From ab03cfb5837d9f5dfe3d2052d03a8b8dea60ab99 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 9 Mar 2020 14:33:50 -0500
Subject: [PATCH 001/152] Updated Travis tests and build dependencies.
---
.travis.yml | 5 +++--
build/lib/build.js | 2 +-
build/package.json | 2 +-
src/index.js | 10 ++--------
4 files changed, 7 insertions(+), 12 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 2c1e145..13e9969 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,5 +7,6 @@ install:
- npm install
script:
- - ls -l
- - cd ./test && ls -l && npm run node
\ No newline at end of file
+ - npm test
+ # - ls -l
+ # - cd ./test && ls -l && npm run node
\ No newline at end of file
diff --git a/build/lib/build.js b/build/lib/build.js
index f238c23..45fc308 100644
--- a/build/lib/build.js
+++ b/build/lib/build.js
@@ -1,7 +1,7 @@
import fs from 'fs'
import path from 'path'
import stripCode from 'rollup-plugin-strip-code'
-import replace from 'rollup-plugin-replace'
+import replace from '@rollup/plugin-replace'
const pkg = JSON.parse(fs.readFileSync('../package.json'))
diff --git a/build/package.json b/build/package.json
index df005fb..cc7da48 100644
--- a/build/package.json
+++ b/build/package.json
@@ -29,10 +29,10 @@
"@babel/plugin-transform-flow-strip-types": "^7.7.4",
"@babel/preset-env": "^7.7.7",
"@rollup/plugin-multi-entry": "^3.0.0",
+ "@rollup/plugin-replace": "^2.3.1",
"browserslist": "^4.8.2",
"rollup": "^1.27.13",
"rollup-plugin-babel": "^4.3.3",
- "rollup-plugin-replace": "^2.2.0",
"rollup-plugin-strip-code": "^0.2.7",
"rollup-plugin-terser": "^5.1.3",
"shortbus": "1.2.8",
diff --git a/src/index.js b/src/index.js
index a08f696..cee3106 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,10 +1,4 @@
import Command from './command.js'
import Shell from './shell.js'
-
-const all = {
- Command,
- Shell
-}
-
-export default Object.assign({}, { Command, Shell })
-export { Command, Shell }
+const all = { Shell, Command }
+export { Command, Shell, all as default }
From a485c76dc378adee87d288185e65354d40bbb430 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 9 Mar 2020 14:55:53 -0500
Subject: [PATCH 002/152] Updated Travis config to support missing tap
dependency.
---
.travis.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.travis.yml b/.travis.yml
index 13e9969..6d90080 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,6 +5,7 @@ node_js:
install:
- npm run setup
- npm install
+ - cd ./test && npm i tap-yaml
script:
- npm test
From a668c5bb89407ded7af768448b58c38b54feae5c Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 9 Mar 2020 14:57:47 -0500
Subject: [PATCH 003/152] Updated Travis config to support missing tap
dependency.
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 6d90080..9d786e9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,7 +5,7 @@ node_js:
install:
- npm run setup
- npm install
- - cd ./test && npm i tap-yaml
+ - cd ./test && npm i yaml
script:
- npm test
From fe5636558638b37146ad7aa0bb177137735f5c15 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 10 Mar 2020 10:04:13 -0500
Subject: [PATCH 004/152] temporary downgrade of yaml lib to prevent tap-yaml
from breaking otherwise successful unit tests.
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 9d786e9..ba798fc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,7 +5,7 @@ node_js:
install:
- npm run setup
- npm install
- - cd ./test && npm i yaml
+ - cd ./test && rm -rf node_modules/yaml && npm i yaml@1.7.2 && cd ../
script:
- npm test
From 9ad66dd4c7d15fc2d5e0b702366475107b4eedbb Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 10 Mar 2020 10:41:22 -0500
Subject: [PATCH 005/152] Removed unnecessary warning for named exports,
attempting to prevent karma from disconnecting to Sauce Labs before tests
run.
---
build/rollup.test.browser.config.js | 4 +++-
build/rollup.test.node.config.js | 1 +
test/unit/karma.conf.cjs | 12 ++++++------
3 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/build/rollup.test.browser.config.js b/build/rollup.test.browser.config.js
index 1e7b7b2..7967033 100644
--- a/build/rollup.test.browser.config.js
+++ b/build/rollup.test.browser.config.js
@@ -51,13 +51,14 @@ build.supportedBrowsers().forEach(edition => {
let terserCfg = config.terser
terserCfg.module = edition === 'current'
terserCfg.compress.module = edition === 'current'
-
+
plugins.push(terser(terserCfg))
configuration.push({
input,
plugins,
output: {
+ exports: 'named',
banner: config.banner,
file: `${outdir}/${build.name}-${build.version}${edition !== 'current' ? '-' + edition : ''}.min.js`,
format: edition === 'current' ? 'esm' : 'iife',
@@ -75,6 +76,7 @@ build.supportedBrowsers().forEach(edition => {
input,
plugins,
output: {
+ exports: 'named',
banner: config.banner,
file: `${outdir}/${build.name}-${build.version}-global.min.js`,
format: 'iife',
diff --git a/build/rollup.test.node.config.js b/build/rollup.test.node.config.js
index b8c85c2..af06869 100644
--- a/build/rollup.test.node.config.js
+++ b/build/rollup.test.node.config.js
@@ -47,6 +47,7 @@ configuration.push({
input,
plugins,
output: {
+ exports: 'named',
banner: config.banner,
file: output,
format: 'esm',
diff --git a/test/unit/karma.conf.cjs b/test/unit/karma.conf.cjs
index dc7c5fa..72992ee 100644
--- a/test/unit/karma.conf.cjs
+++ b/test/unit/karma.conf.cjs
@@ -16,7 +16,7 @@ if (process.env.hasOwnProperty('SAUCE_USERNAME') && process.env.hasOwnProperty('
local = false
}
-let browsers = {}
+const browsers = {}
if (!local) {
const opts = {}
if (process.env.BROWSERSLIST_CONFIG) {
@@ -31,10 +31,10 @@ if (!local) {
.forEach(item => {
if (item.indexOf('-')) {
let browser = item.split('-').shift().split(' ')
- let version = /([0-9]+\.?([0-9]+)?)/.exec(browser[1])
+ const version = /([0-9]+\.?([0-9]+)?)/.exec(browser[1])
if (version && browser[0].trim().toLowerCase() !== 'samsung') {
- let label = `sl_${browser[0]}_${browser[1]}`.toLowerCase()
+ const label = `sl_${browser[0]}_${browser[1]}`.toLowerCase()
browsers[label] = {
base: 'SauceLabs',
browserName: browser[0],
@@ -95,9 +95,9 @@ if (!local) {
module.exports = function (config) {
config.set({
- // browserDisconnectTimeout: 10000,
- // browserDisconnectTolerance: 1,
- // browserNoActivityTimeout: 10000,
+ browserDisconnectTimeout: 30000,
+ browserDisconnectTolerance: 3,
+ browserNoActivityTimeout: 20000,
processKillTimeout: 30000,
// base path that will be used to resolve all patterns (eg. files, exclude)
From 1e4b8a0a6a25629418ff34e38d690ded5ab15d98 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 10 Mar 2020 10:46:46 -0500
Subject: [PATCH 006/152] Increased timeouts in an effort to better support
karma/saucelabs integration.
---
test/unit/karma.conf.cjs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/unit/karma.conf.cjs b/test/unit/karma.conf.cjs
index 72992ee..1e884df 100644
--- a/test/unit/karma.conf.cjs
+++ b/test/unit/karma.conf.cjs
@@ -97,7 +97,7 @@ module.exports = function (config) {
config.set({
browserDisconnectTimeout: 30000,
browserDisconnectTolerance: 3,
- browserNoActivityTimeout: 20000,
+ browserNoActivityTimeout: 60000,
processKillTimeout: 30000,
// base path that will be used to resolve all patterns (eg. files, exclude)
From 2ca59a68f597bb8395fd433e37cd77cc7514eba4 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 31 Mar 2020 22:38:16 -0500
Subject: [PATCH 007/152] Version bump
---
package-lock.json | 2 +-
package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 5c41e35..29d7fe8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.1.7",
+ "version": "1.1.8",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 03ea4d7..8f4a155 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.1.7",
+ "version": "1.1.8",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
From 20583b45c1730394f4bc3445eb358cf4051730b8 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 31 Mar 2020 23:14:40 -0500
Subject: [PATCH 008/152] Updated npm module to support sourcemap files.
---
.github/FUNDING.yml | 12 -----
.github/workflows/release.yml | 99 -----------------------------------
build/lib/browser-package.js | 18 ++++---
package-lock.json | 2 +-
package.json | 2 +-
5 files changed, 12 insertions(+), 121 deletions(-)
delete mode 100644 .github/FUNDING.yml
delete mode 100644 .github/workflows/release.yml
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index eaf9b65..0000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-# These are supported funding model platforms
-
-github: coreybutler
-patreon: # coreybutler
-open_collective: # Replace with a single Open Collective username
-ko_fi: # Replace with a single Ko-fi username
-tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
-community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
-liberapay: # Replace with a single Liberapay username
-issuehunt: # Replace with a single IssueHunt username
-otechie: # Replace with a single Otechie username
-custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
\ No newline at end of file
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
deleted file mode 100644
index 5ac46b5..0000000
--- a/.github/workflows/release.yml
+++ /dev/null
@@ -1,99 +0,0 @@
-name: Tag, Release, & Publish
-
-on:
- push:
- branches:
- - master
-
-jobs:
- build:
- runs-on: ubuntu-latest
- steps:
- # Checkout updated source code
- - uses: actions/checkout@v2
-
- # If the version has changed, create a new git tag for it.
- - name: Tag
- id: autotagger
- uses: butlerlogic/action-autotag@master
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- # The remaining steps all depend on whether or not
- # a new tag was created. There is no need to release/publish
- # updates until the code base is in a releaseable state.
-
- # If the new version/tag is a pre-release (i.e. 1.0.0-beta.1), create
- # an environment variable indicating it is a prerelease.
- - name: Pre-release
- if: steps.autotagger.outputs.tagname != ''
- run: |
- if [[ "${{ steps.autotagger.output.version }}" == *"-"* ]]; then echo "::set-env IS_PRERELEASE=true";else echo "::set-env IS_PRERELEASE=''";fi
-
- # Create a github release
- # This will create a snapshot of the module,
- # available in the "Releases" section on Github.
- - name: Release
- id: create_release
- if: steps.autotagger.outputs.tagname != ''
- uses: actions/create-release@v1.0.0
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- with:
- tag_name: ${{ steps.autotagger.outputs.tagname }}
- release_name: ${{ steps.autotagger.outputs.tagname }}
- body: ${{ steps.autotagger.outputs.tagmessage }}
- draft: false
- prerelease: env.IS_PRERELEASE != ''
-
- - uses: actions/setup-node@v1
- if: steps.create_release.outputs.id != ''
- with:
- node-version: '13'
-
- # Build tarballs of the module code.
- - name: Build Release Artifacts
- id: build_release
- if: steps.create_release.outputs.id != ''
- run: |
- npm install
- cd ./build && npm install && cd ../
- npm run build --if-present
- for d in .dist/*/*/ ; do tar -cvzf ${d%%/}-${{ steps.autotagger.outputs.version }}.tar.gz ${d%%}*; done;
- if [[ ${{ github.ref }} == *"-"* ]]; then echo ::set-output isprerelease=true;else echo ::set-output isprerelease=false;fi
-
- # Upload tarballs to the release.
- - name: Upload Release Artifacts
- uses: AButler/upload-release-assets@v2.0
- if: steps.create_release.outputs.id != ''
- with:
- files: './.dist/**/*.tar.gz'
- repo-token: ${{ secrets.GITHUB_TOKEN }}
- release-tag: ${{ steps.autotagger.outputs.tagname }}
-
- # Build npm packages
- - name: Build Module Artifacts
- id: build_npm
- if: steps.create_release.outputs.id != ''
- run: |
- npm install
- cd ./build && npm install && cd ../
- npm run build --if-present
-
- # Use this action to publish a single module to npm.
- - name: Publish
- id: publish_npm
- if: steps.autotagger.outputs.tagname != ''
- uses: author/action-publish@master
- with:
- scan: .dist
- env:
- REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
-
- - name: Rollback Release
- if: failure() && steps.create_release.outputs.id != ''
- uses: author/action-rollback@stable
- with:
- tag: ${{ steps.autotagger.outputs.tagname }}
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
diff --git a/build/lib/browser-package.js b/build/lib/browser-package.js
index eb27a8a..156cdfc 100644
--- a/build/lib/browser-package.js
+++ b/build/lib/browser-package.js
@@ -16,7 +16,7 @@ build.supportedBrowsers().forEach(edition => {
const prefix = `${config.npmOrganization}${config.npmOrganization.trim().length > 0 ? '/' : ''}`
outdir = `${config.browserOutput}/${edition}`
- const srcfile = `${config.browserOutput}/browser-${build.name}/${build.name}-${build.version}${edition.replace('browser-'+build.name, '')}.min.js`
+ const srcfile = `${config.browserOutput}/browser-${build.name}/${build.name}-${build.version}${edition.replace('browser-' + build.name, '')}.min.js`
console.log(`Creating production npm package for ${edition}`)
const pkg = Object.assign({}, mainpkg)
@@ -24,8 +24,9 @@ build.supportedBrowsers().forEach(edition => {
pkg.description = `${mainpkg.description} (Production code for ${originalEditionName} browsers)`
pkg.devDependencies = {}
pkg.devDependencies[`${prefix}${edition}-debug`] = mainpkg.version
- pkg.module = `./${build.name}-${build.version}${edition.replace('browser-'+build.name, '')}.min.js`
- pkg.main = `./${build.name}-${build.version}${edition.replace('browser-'+build.name, '')}.min.js`
+ pkg.files.indexOf('*.js.map') < 0 && pkg.files.push('*.js.map')
+ pkg.module = `./${build.name}-${build.version}${edition.replace('browser-' + build.name, '')}.min.js`
+ pkg.main = `./${build.name}-${build.version}${edition.replace('browser-' + build.name, '')}.min.js`
if (!fs.existsSync(outdir)) {
fs.mkdirSync(outdir)
@@ -43,10 +44,10 @@ build.supportedBrowsers().forEach(edition => {
.toString()
.replace(/\/+#\s+?sourceMappingURL=/, `//# sourceMappingURL=../${edition}-debug/`)
fs.writeFileSync(globalFile, content)
- fs.renameSync(srcfile.replace('.min.js', '-global.min.js'), `${outdir}/${build.name}-${build.version}${edition.replace('browser-'+build.name, '')}-global.min.js`)
+ fs.renameSync(srcfile.replace('.min.js', '-global.min.js'), `${outdir}/${build.name}-${build.version}${edition.replace('browser-' + build.name, '')}-global.min.js`)
}
- fs.renameSync(srcfile, `${outdir}/${build.name}-${build.version}${edition.replace('browser-'+build.name, '')}.min.js`)
+ fs.renameSync(srcfile, `${outdir}/${build.name}-${build.version}${edition.replace('browser-' + build.name, '')}.min.js`)
fs.writeFileSync(`${outdir}/package.json`, JSON.stringify(pkg, null, 2))
// Add license
@@ -57,7 +58,7 @@ build.supportedBrowsers().forEach(edition => {
console.log(`Creating debug npm package for ${edition}.`)
fs.mkdirSync(`${outdir}-debug`)
- fs.renameSync(srcfile.replace('.min.js', '.min.js.map'), `${outdir}-debug/${build.name}-${build.version}${edition.replace('browser-'+build.name, '')}.min.js.map`)
+ fs.renameSync(srcfile.replace('.min.js', '.min.js.map'), `${outdir}-debug/${build.name}-${build.version}${edition.replace('browser-' + build.name, '')}.min.js.map`)
if (originalEditionName === 'current') {
fs.renameSync(srcfile.replace('.min.js', '-global.min.js.map'), `${outdir}-debug/${build.name}-${build.version}-global.min.js.map`)
}
@@ -66,8 +67,9 @@ build.supportedBrowsers().forEach(edition => {
delete pkg.devDependencies
pkg.name = `${pkg.name}-debug`
pkg.description = `${mainpkg.description} (Sourcemaps for ${originalEditionName} browsers)`
- pkg.module = `./${build.name}-${build.version}${edition.replace('browser-'+build.name, '')}.min.js.map`
- pkg.main = `./${build.name}-${build.version}${edition.replace('browser-'+build.name, '')}.min.js.map`
+ pkg.module = `./${build.name}-${build.version}${edition.replace('browser-' + build.name, '')}.min.js.map`
+ pkg.main = `./${build.name}-${build.version}${edition.replace('browser-' + build.name, '')}.min.js.map`
+ pkg.files.indexOf('*.js.map') < 0 && pkg.files.push('*.js.map')
pkg.dependencies = {}
pkg.dependencies['source-map-support'] = mainpkg['source-map-support']
fs.writeFileSync(`${outdir}-debug/package.json`, JSON.stringify(pkg, null, 2))
diff --git a/package-lock.json b/package-lock.json
index 29d7fe8..a350a99 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.1.8",
+ "version": "1.1.9",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 8f4a155..827ccc5 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.1.8",
+ "version": "1.1.9",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
From 262767ac5305899d843350da05f51600d7cbe3aa Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 31 Mar 2020 23:21:20 -0500
Subject: [PATCH 009/152] Updated README
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 91dfa05..a49b028 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ There are two types of text-based apps:
**tl;dr** Use this library to create multipurpose tools. Use [@author.io/arg](https://github.com/author/arg) to create single purpose tools.
-This framework is designed to support multipurpose CLI tools. At the core, it provides a clean, easily-understood, repeatable pattern for building maintainable multipurpose CLI applications.
+This framework was designed to support multipurpose CLI tools. At the core, it provides a clean, easily-understood, repeatable pattern for building maintainable multipurpose CLI applications.
Multipurpose tools require a layer of organizational overhead to help isolate different commands and features. This overhead is unnecessary in single purpose tools. Single purpose tools just need argument parsing, which the [@author.io/arg](https://github.com/author/arg) does very well.
From 1c9e8fe5e2f226e229300e03f606bcd0b0634f6a Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 31 Mar 2020 23:24:33 -0500
Subject: [PATCH 010/152] Rolled back the release scripts.
---
.github/FUNDING.yml | 12 +++++
.github/workflows/deploy.yml | 97 ++++++++++++++++++++++++++++++++++++
2 files changed, 109 insertions(+)
create mode 100644 .github/FUNDING.yml
create mode 100644 .github/workflows/deploy.yml
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..eaf9b65
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: coreybutler
+patreon: # coreybutler
+open_collective: # Replace with a single Open Collective username
+ko_fi: # Replace with a single Ko-fi username
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
\ No newline at end of file
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
new file mode 100644
index 0000000..d63c6ad
--- /dev/null
+++ b/.github/workflows/deploy.yml
@@ -0,0 +1,97 @@
+name: Tag, Release, & Publish
+
+on:
+ push:
+ branches:
+ - master
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ # Checkout updated source code
+ - uses: actions/checkout@v2
+
+ # If the version has changed, create a new git tag for it.
+ - name: Tag
+ id: autotagger
+ uses: butlerlogic/action-autotag@master
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ # The remaining steps all depend on whether or not
+ # a new tag was created. There is no need to release/publish
+ # updates until the code base is in a releaseable state.
+
+ # If the new version/tag is a pre-release (i.e. 1.0.0-beta.1), create
+ # an environment variable indicating it is a prerelease.
+ - name: Pre-release
+ if: steps.autotagger.outputs.tagname != ''
+ run: |
+ if [[ "${{ steps.autotagger.output.version }}" == *"-"* ]]; then echo "::set-env IS_PRERELEASE=true";else echo "::set-env IS_PRERELEASE=''";fi
+
+ # Create a github release
+ # This will create a snapshot of the module,
+ # available in the "Releases" section on Github.
+ - name: Release
+ id: create_release
+ if: steps.autotagger.outputs.tagname != ''
+ uses: actions/create-release@v1.0.0
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ tag_name: ${{ steps.autotagger.outputs.tagname }}
+ release_name: ${{ steps.autotagger.outputs.tagname }}
+ body: ${{ steps.autotagger.outputs.tagmessage }}
+ draft: false
+ prerelease: env.IS_PRERELEASE != ''
+
+ - uses: actions/setup-node@v1
+ if: steps.create_release.outputs.id != ''
+ with:
+ node-version: '13'
+
+ # Build tarballs of the module code.
+ - name: Build Release Artifacts
+ id: build_release
+ if: steps.create_release.outputs.id != ''
+ run: |
+ npm install
+ cd ./build && npm install && cd ../
+ npm run build --if-present
+ for d in .dist/*/*/ ; do tar -cvzf ${d%%/}-${{ steps.autotagger.outputs.version }}.tar.gz ${d%%}*; done;
+ if [[ ${{ github.ref }} == *"-"* ]]; then echo ::set-output isprerelease=true;else echo ::set-output isprerelease=false;fi
+ # Upload tarballs to the release.
+ - name: Upload Release Artifacts
+ uses: AButler/upload-release-assets@v2.0
+ if: steps.create_release.outputs.id != ''
+ with:
+ files: './.dist/**/*.tar.gz'
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ release-tag: ${{ steps.autotagger.outputs.tagname }}
+
+ # Build npm packages
+ - name: Build Module Artifacts
+ id: build_npm
+ if: steps.create_release.outputs.id != ''
+ run: |
+ npm install
+ cd ./build && npm install && cd ../
+ npm run build --if-present
+ # Use this action to publish a single module to npm.
+ - name: Publish
+ id: publish_npm
+ if: steps.autotagger.outputs.tagname != ''
+ uses: author/action-publish@master
+ with:
+ scan: .dist
+ env:
+ REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
+
+ - name: Rollback Release
+ if: failure() && steps.create_release.outputs.id != ''
+ uses: author/action-rollback@stable
+ with:
+ tag: ${{ steps.autotagger.outputs.tagname }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
From c5e09fc45106a4b27b8f4598fb79811b589a4684 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 1 Apr 2020 11:37:17 -0500
Subject: [PATCH 011/152] Update README.md
---
README.md | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/README.md b/README.md
index a49b028..4273aac 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,15 @@
This is a super-lightweight framework for building text-based programs, like [CLI](https://en.wikipedia.org/wiki/Command-line_interface) applications.
+**Sponsors (as of 2020)**
+
+
+
+
+
+
+
+
## Uses
There are two types of text-based apps:
From b690be366a5636d51b1245a1b39c86102ddb8a81 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sat, 4 Apr 2020 00:57:37 -0500
Subject: [PATCH 012/152] Added metadoc capability to introspect the
shell/commands. (data attribute on each class)
---
examples/cli/index.js | 18 +++++++++++++++++-
package.json | 2 +-
src/command.js | 25 +++++++++++++++++++++++++
src/middleware.js | 8 ++++++--
src/shell.js | 25 +++++++++++++++++++++++++
test/unit/01-sanity/01-sanity.js | 13 +++++--------
6 files changed, 79 insertions(+), 12 deletions(-)
diff --git a/examples/cli/index.js b/examples/cli/index.js
index 1eaa185..861e557 100755
--- a/examples/cli/index.js
+++ b/examples/cli/index.js
@@ -3,8 +3,10 @@
import fs from 'fs'
import path from 'path'
import { Command, Shell } from '../../src/index.js'
+import { fileURLToPath } from 'url'
+const __dirname = path.dirname(fileURLToPath(import.meta.url))
-const pkg = JSON.parse(fs.readFileSync('./package.json'))
+const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, './package.json')))
const shell = new Shell({
name: Object.keys(pkg.bin)[0],
@@ -109,6 +111,20 @@ shell.add(new Command({
}
}))
+
+shell.add(new Command({
+ name: 'doc',
+ description: 'Output the metadoc of this shell.',
+ handler () {
+ console.log(shell.data)
+ }
+}))
+
+shell.use((data, next) => {
+ console.log('This middleware runs on very command.')
+ next()
+})
+
const cmd = process.argv.slice(2).join(' ').trim()
// console.log(cmd)
shell.exec(cmd).catch(e => console.log(e.message || e))
diff --git a/package.json b/package.json
index 827ccc5..c612d22 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.1.9",
+ "version": "1.2.0",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/command.js b/src/command.js
index 98d2f8b..9bdea0b 100644
--- a/src/command.js
+++ b/src/command.js
@@ -107,6 +107,31 @@ export default class Command {
}
}
+ get data () {
+ const commands = {}
+
+ Array.from(this.#processors.values()).forEach(cmd => {
+ let data = cmd.data
+ const name = data.name
+ delete data.name
+ commands[name] = data
+ })
+
+ const data = {
+ name: this.#name,
+ description: this.description,
+ help: this.help,
+ usage: this.usage,
+ aliases: this.#aliases || [],
+ flags: this.#flagConfig || {},
+ handler: (this.#fn || this.#defaultHandler).toString(),
+ commands,
+ middleware: this.#middleware.data
+ }
+
+ return data
+ }
+
set tableWidth(value) {
this.#tableWidth = value
this.#processors.forEach(cmd => cmd.tableWidth = value)
diff --git a/src/middleware.js b/src/middleware.js
index 3604e68..62f8657 100644
--- a/src/middleware.js
+++ b/src/middleware.js
@@ -2,10 +2,14 @@ const last = a => a[a.length - 1]
const reduce = a => a.slice(0, -1)
export default class Middleware {
- constructor () { this.size = 0 }
+ constructor () { Object.defineProperty(this, '_data', { enumerable: false, value: [] }) }
+
+ get size () { return this._data.length }
+
+ get data () { return this._data }
use (method) {
- this.size++
+ this._data.push(method.toString())
this.run = ((stack) => (...args) => stack(...reduce(args), () => {
const next = last(args)
method.apply(this, [...reduce(args), next.bind.apply(next, [null, ...reduce(args)])])
diff --git a/src/shell.js b/src/shell.js
index 0bddb08..635712a 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -59,6 +59,31 @@ export default class Shell {
}
}
+ get data () {
+ const commands = {}
+
+ Array.from(this.#processors.values()).forEach(cmd => {
+ let data = cmd.data
+ const name = data.name
+ delete data.name
+ commands[name] = data
+ })
+
+ return {
+ name: this.name,
+ description: this.description,
+ version: this.version,
+ commands,
+ middleware: this.#middleware.data,
+ help: this.help,
+ usage: this.usage,
+ defaultHandler: this.#defaultHandler.toString(),
+ authohelp: this.#autohelp,
+ runtime: this.#runtime,
+ maxHistoryItems: this.#maxHistoryItems
+ }
+ }
+
get version () {
return this.#version || 'Unknown'
}
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index 418f2ee..6e5ac0f 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -23,7 +23,7 @@ test('Sanity Check - Command', t => {
cb && cb()
}
})
-
+ console.log('>>', mirror.xdata)
t.ok(mirror instanceof Command, 'Command initialized successfully.')
const CLI = new Shell({
@@ -40,11 +40,8 @@ test('Sanity Check - Command', t => {
t.ok(CLI instanceof Shell, 'Shell initialized with commands successfully.')
- let defaultHandlerFires = false
-
- CLI.exec('test', data => defaultHandlerFires = true)
-
- t.ok(defaultHandlerFires, 'Default handler fires.')
-
- t.end()
+ CLI.exec('test').then(data => {
+ t.pass('Default handler fires.')
+ t.end()
+ }).catch(e => t.fail(e.message))
})
From be790546b3fd36ce882ad02d6ed79013085f836c Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sat, 4 Apr 2020 01:00:04 -0500
Subject: [PATCH 013/152] Updated link to use latest stable version.
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 4273aac..0adad73 100644
--- a/README.md
+++ b/README.md
@@ -57,7 +57,7 @@ If you need to use the older CommonJS format (i.e. `require`), run `npm install
**CDN**
```javascript
-import { Shell, Command } from 'https://cdn.pika.dev/@author.io/browser-shell/v1'
+import { Shell, Command } from 'https://cdn.pika.dev/@author.io/browser-shell'
```
Also available from [jsdelivr](https://www.jsdelivr.com/?query=%40author.io%2Fshell) and [unpkg](https://unpkg.com/@author.io/browser-shell).
From dc1bfa714be0fdb1e8037017a53afa40aeb09080 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sat, 4 Apr 2020 23:12:57 -0500
Subject: [PATCH 014/152] Added default strings to prevent undefined
customUsage and customHelp from causing errors in data serialization.
---
examples/cli/index.js | 2 +-
package.json | 2 +-
src/command.js | 6 +++---
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/examples/cli/index.js b/examples/cli/index.js
index 861e557..15bff29 100755
--- a/examples/cli/index.js
+++ b/examples/cli/index.js
@@ -121,7 +121,7 @@ shell.add(new Command({
}))
shell.use((data, next) => {
- console.log('This middleware runs on very command.')
+ console.log('This middleware runs on every command.')
next()
})
diff --git a/package.json b/package.json
index c612d22..03a01af 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.2.0",
+ "version": "1.2.1",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/command.js b/src/command.js
index 9bdea0b..9464604 100644
--- a/src/command.js
+++ b/src/command.js
@@ -200,7 +200,7 @@ export default class Command {
}
get description () {
- return this.#description || this.usage
+ return this.#description || this.usage || ''
}
get commandroot () {
@@ -223,8 +223,8 @@ export default class Command {
const a = Array.from(this.#aliases)
const msg = [`${this.commandroot}${a.length > 0 ? ' <' + a.join(', ') + '> ' : ''} [OPTIONS]`.trim()]
- if (this.#description.trim().length > 0) {
- msg.push('\n ' + this.#description.trim())
+ if ((this.#description || '').trim().length > 0) {
+ msg.push('\n ' + (this.#description || '').trim())
}
return msg.join('\n').trim()
}
From 41263cf3690c7a82cced1b72bf333105c58ab9ca Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sat, 11 Apr 2020 13:14:14 -0500
Subject: [PATCH 015/152] Update README.md
Use proper grammar.
---
README.md | 36 ++++++++++++++++++++++++++++--------
1 file changed, 28 insertions(+), 8 deletions(-)
diff --git a/README.md b/README.md
index 0adad73..017502f 100644
--- a/README.md
+++ b/README.md
@@ -34,21 +34,21 @@ This framework was designed to support multipurpose CLI tools. At the core, it p
Multipurpose tools require a layer of organizational overhead to help isolate different commands and features. This overhead is unnecessary in single purpose tools. Single purpose tools just need argument parsing, which the [@author.io/arg](https://github.com/author/arg) does very well.
-`@author.io/arg` is embedded in this framework, making `@author.io/shell` _capable_ of creating single purpose tools, but it's a bit redundant.
+`@author.io/arg` is embedded in this framework, making `@author.io/shell` _capable_ of creating single purpose tools, but it's merely unnecessary overhead for single purpose commands.
**Think about how your tooling evolves...**
-Sometimes single purpose tools grow into multipurpose tools over time. Tools which start out using the `@author.io/arg` library be transitioned into multipurpose tools using `@author.io/shell`, with reasonable ease. After all, they use the same code, just nicely separated by purpose.
+Sometimes single purpose tools grow into multipurpose tools over time. Tools which start out using the `@author.io/arg` library can be transitioned into multipurpose tools using `@author.io/shell` (with reasonable ease). After all, they use the same code, just nicely separated by purpose.
## Installation & Usage
-### For Node (ES Modules)
+### For Modern Node (ES Modules)
`npm install @author.io/node-shell`
-Please note, you'll need a verison of Node that support ESM Modules. In Node 12, this feature is behind the `--experimental-modules` flag. It is available in Node 13+ without a flag, but your `package.json` file must have the `"type": "module"` attribute.
+Please note, you'll need a verison of Node that supports ES Modules. In Node 12, this feature is behind the `--experimental-modules` flag. It is available in Node 13+ without a flag, but your `package.json` file must have the `"type": "module"` attribute. This feature will be generally available in Node 14.0.0 (release date April 21, 2020).
-### For Node (CommonJS/require)
+### For Legacy Node (CommonJS/require)
If you need to use the older CommonJS format (i.e. `require`), run `npm install @author.io/node-shell-legacy` instead.
@@ -245,7 +245,7 @@ const cmd = new Command({
})
```
-While the differences aren't extreme, it abstracts the need to know whether a flag is recognized or not (or even exists).
+While the differences aren't extreme, it abstracts the need to know whether a flag is recognized or not (or even exists). If a `flag()` is executed for a non-existant flag, it will return `null`.
## Middleware
@@ -283,7 +283,7 @@ shell.useWith('demo', function (metadata, next) {
})
```
-The code above would only run when the user inputs the `demo` command (or and `demo` subcommand).
+The code above would only run when the user inputs the `demo` command (or any `demo` subcommand).
It is possible to assign middleware to more than one command at a time, and it is possible to target subcommands. For example:
@@ -299,8 +299,28 @@ shell.useWith(['demo', 'command subcommand'], function (metadata, next) {
Notice the array as the first argument of the `useWith` method. This middleware would be assigned to `demo` command, all `demo` subcommands, the `subcommand` of `command`, and all subcommands of `subcommand`. If this sounds confusing, just know that middleware is applied to commands, including nested commands.
+Assigned middleware can also be applied directly to a `Command` class. For example,
+
+```javascript
+const cmd = new Command({
+ name: 'demo',
+ flags: {
+ a: { type: String },
+ b: { type: String }
+ },
+ handler: metadata => {
+ console.log(metadata)
+ }
+})
+
+cmd.use(function (metadata, next) {
+ console.log(`this middleware is specific to the "${cmd.name}" command`)
+ next()
+})
+```
+
### Other Middleware
-One development goal of this framework is to remain as lightweight and unopinionated as possible. Another is to be as simple to use as possible. These two goals often conflict with each other (the more features you add, the heavier it becomes). In an attempt to find a comfortable balance, some additional middleware libraries are available fo those who want a little extra functionality.
+One development goal of this framework is to remain as lightweight and unopinionated as possible. Another is to be as simple to use as possible. These two goals often conflict with each other (the more features you add, the heavier it becomes). In an attempt to find a comfortable balance, some additional middleware libraries are available for those who want a little extra functionality.
1. [@author.io/shell-middleware](https://github.com/author/shell-middleware)
From 603c331542e65b03a7c2923172dbf94f20c86f3f Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Fri, 17 Apr 2020 18:54:56 -0500
Subject: [PATCH 016/152] Initial beta including introspective JSON data.
---
build/rollup.node.config.js | 7 +-
examples/cli/index.js | 18 ++-
examples/json/README.md | 196 ++++++++++++++++++++++++++++++++
examples/json/dir.json | 112 ++++++++++++++++++
examples/json/index.js | 11 ++
examples/json/package-lock.json | 5 +
examples/json/package.json | 20 ++++
package.json | 2 +-
src/command.js | 72 ++++++++++--
src/middleware.js | 6 +-
src/shell.js | 22 +++-
11 files changed, 448 insertions(+), 23 deletions(-)
create mode 100644 examples/json/README.md
create mode 100644 examples/json/dir.json
create mode 100755 examples/json/index.js
create mode 100644 examples/json/package-lock.json
create mode 100644 examples/json/package.json
diff --git a/build/rollup.node.config.js b/build/rollup.node.config.js
index 04990c3..673088c 100644
--- a/build/rollup.node.config.js
+++ b/build/rollup.node.config.js
@@ -26,7 +26,7 @@ fs.rmdirSync(rootdir, { recursive: true })
let terserCfg = config.terser
terserCfg.module = true
// terserCfg.mangle = { properties: true }
-
+console.log(terserCfg)
// Identify plugins
const plugins = [
build.only('node'),
@@ -35,9 +35,8 @@ const plugins = [
presets: [['@babel/preset-env', { targets: { node: true } }]],
plugins: [
['@babel/plugin-proposal-class-properties', { loose: false }],
- // ['@babel/plugin-proposal-private-methods', { loose: false }]
- ],
- externalHelpersWhitelist: ['classPrivateFieldSet', 'classPrivateFieldGet', 'classPrivateMethods']
+ ['@babel/plugin-proposal-private-methods', { loose: false }]
+ ]
}),
terser(terserCfg)
]
diff --git a/examples/cli/index.js b/examples/cli/index.js
index 15bff29..2079fb8 100755
--- a/examples/cli/index.js
+++ b/examples/cli/index.js
@@ -115,8 +115,20 @@ shell.add(new Command({
shell.add(new Command({
name: 'doc',
description: 'Output the metadoc of this shell.',
- handler () {
- console.log(shell.data)
+ flags: {
+ file: {
+ alias: 'f',
+ type: String
+ }
+ },
+ handler (meta) {
+ let data = this.shell.data
+
+ if (meta.flag('file') !== null) {
+ fs.writeFileSync(path.resolve(meta.flag('file')), JSON.stringify(data, null, 2))
+ } else {
+ console.log(data)
+ }
}
}))
@@ -127,4 +139,4 @@ shell.use((data, next) => {
const cmd = process.argv.slice(2).join(' ').trim()
// console.log(cmd)
-shell.exec(cmd).catch(e => console.log(e.message || e))
+shell.exec(cmd).catch(e => console.log(e.message || e))
\ No newline at end of file
diff --git a/examples/json/README.md b/examples/json/README.md
new file mode 100644
index 0000000..54b2ad5
--- /dev/null
+++ b/examples/json/README.md
@@ -0,0 +1,196 @@
+# CLI example
+
+To try this out:
+
+1. Clone the repo
+1. Navigate to the `examples/cli` directory in your terminal/console.
+1. Run `npm link`. This will make the command available globally.
+
+> Notice that there are no dependencies in the package.json file for this example app. That's because this example is part of the module. In all other apps, you would need to run `npm install @author.io/shell -S` to make it work.
+
+Next, start using it.
+
+> The name of the shell is defined in the package.json file (`bin` attribute).
+
+```sh
+examples/cli> dir
+```
+
+You should see the following output:
+
+```sh
+dir 1.0.0
+A simple file system utility.
+
+ - list [ls] : List files of a directory. Optionally specify a
+ long format.
+ - export : Export a file representation of a directory.
+ Has an additional subcommand.
+ - mkdir [md, m] : Make a new directory.
+```
+
+### Try the list Command
+
+```sh
+examples/cli> dir list
+```
+_Output:_
+```sh
+README.md, index.js, package-lock.json, package.json
+```
+
+#### Same command, as an alias & a flag:
+
+```sh
+examples/cli> dir ls -l
+```
+_`-l` is the "long format" flag defined in the list command (see index.js)._
+
+_Output:_
+```sh
+- README.md
+- index.js
+- package-lock.json
+- package.json
+```
+
+### Explore Another Command
+
+```sh
+dir md -R /path/to/dir
+```
+
+```sh
+...make a directory...
+{
+ command: 'mkdir',
+ input: '-R /path/to/dir',
+ flags: {
+ recognized: { p: true },
+ unrecognized: [ '/path/to/dir' ]
+ },
+ valid: true,
+ violations: [],
+ help: { requested: false }
+}
+```
+
+**Notice the help attribute**. A help flag is automatically created for every command (can be overridden), which can be detected in the help attribute. In the example above, no help was requested.
+
+Run the same command again with the help flag:
+```sh
+dir md -R /path/to/dir --help
+```
+
+_Output:_
+
+```sh
+dir mkdir [OPTIONS]
+
+ Make a new directory.
+
+Options:
+
+ -p [-R] : Recursively create the directory if it does not
+ already exist.
+```
+
+By default, a help message like the one above will be logged out to the console. However; this can be disabled by setting `autohelp: false` in the shell configuration. When automatic help is turned off, the help objects are still passed to handler functions, giving developers full control.
+
+_With `autohelp: false`_
+
+```sh
+{
+ command: 'mkdir',
+ input: '-R /path/to/dir -h',
+ flags: { recognized: { p: true }, unrecognized: [ '/path/to/dir' ] },
+ valid: true,
+ violations: [],
+ help: {
+ requested: true,
+ message: 'dir mkdir [OPTIONS]\n' +
+ '\n' +
+ ' Make a new directory.\n' +
+ '\n' +
+ 'Options:\n' +
+ '\n' +
+ ' -p [-R] : Recursively create the directory if it does not\n' +
+ ' already exist.\n'
+ }
+}
+```
+
+> **TRY IT YOURSELF:** Change the source code of the `mkdir` command to do something meaningful. For example, use Node's recursive directory creation option (see [the docs](https://nodejs.org/dist/latest-v13.x/docs/api/fs.html#fs_fs_mkdir_path_options_callback)) to make new directories.
+
+### Subcommands
+
+There is an example subcommand called `json`, which is part of the `export` family of commands.
+
+In this app, running the main command, `export`, isn't supposed to do anything. It shows the help message:
+
+```sh
+dir export
+```
+
+_Output:_
+```sh
+dir export [OPTIONS]
+
+ Export a file representation of a directory.
+
+Options:
+
+ json: Generate a JSON representation of the directory.
+```
+
+The `json` **subcommand** is a little more interesting. It is supposed to display the file system as a JSON object.
+
+```sh
+dir export json
+```
+
+_Outputs:_
+
+```sh
+{
+ "/.../@author.io/shell/examples/cli": [
+ "README.md",
+ "index.js",
+ "package-lock.json",
+ "package.json"
+ ]
+}
+```
+
+You can see all of the subcommand features by applying the `--help` flag to the command:
+
+```sh
+dir export json -help
+```
+
+_Outputs:_
+
+```sh
+dir export json [OPTIONS]
+
+ Generate a JSON representation of the directory.
+
+Options:
+
+ -array [-a] : Generate an array. This is a pretty long message
+ for such a short explanation. Kinda Rube
+ Goldbergish.
+```
+
+Notice there is an `array` flag for the `json` subcommand.
+
+```sh
+dir export json -a
+```
+
+_Outputs:_
+
+```sh
+[ 'README.md', 'index.js', 'package-lock.json', 'package.json' ]
+```
+
diff --git a/examples/json/dir.json b/examples/json/dir.json
new file mode 100644
index 0000000..98f3460
--- /dev/null
+++ b/examples/json/dir.json
@@ -0,0 +1,112 @@
+{
+ "name": "dir",
+ "description": "A simple file system utility.",
+ "version": "1.0.0",
+ "commands": {
+ "list": {
+ "description": "List files of a directory. Optionally specify a long format.",
+ "help": "dir list [OPTIONS]\n\n List files of a directory. Optionally specify a long format.\n\nOptions:\n\n -l : Long format.\n",
+ "usage": "dir list [OPTIONS]\n\n List files of a directory. Optionally specify a long format.",
+ "aliases": [
+ "ls"
+ ],
+ "flags": {
+ "l": {
+ "description": "Long format.",
+ "default": false,
+ "aliases": []
+ }
+ },
+ "handler": "(data) => {\n let dir = process.cwd()\n\n if (data.flags.unrecognized.length > 0) {\n dir = path.resolve(data.flags.unrecognized[0])\n }\n\n const out = fs.readdirSync(dir)\n .map(item => {\n if (data.flags.recognized.l) {\n return ((fs.statSync(path.join(dir, item)).isDirectory() ? '>' : '-') + ' ' + item).trim()\n }\n\n return item\n })\n .join(data.flags.recognized.l ? '\\n' : ', ')\n\n console.log(out)\n }",
+ "commands": {},
+ "middleware": []
+ },
+ "export": {
+ "description": "Export a file representation of a directory.",
+ "help": "dir export [OPTIONS]\n\n Export a file representation of a directory.\n\nOptions:\n\n json: Generate a JSON representation of the directory. \n",
+ "usage": "dir export [OPTIONS]\n\n Export a file representation of a directory.",
+ "aliases": [],
+ "flags": {},
+ "handler": "(data, cb) => {\n if (data.help && data.help.requested) {\n console.log(data.help.message)\n }\n\n cb && cb(data)\n }",
+ "commands": {
+ "json": {
+ "description": "Generate a JSON representation of the directory.",
+ "help": "dir export json [OPTIONS]\n\n Generate a JSON representation of the directory.\n\nOptions:\n\n -array [-a] : Generate an array. This is a pretty long message\n for such a short explanation. Kinda Rube\n Goldbergish.\n",
+ "usage": "dir export json [OPTIONS]\n\n Generate a JSON representation of the directory.",
+ "aliases": [],
+ "flags": {
+ "array": {
+ "type": "boolean",
+ "default": false,
+ "description": "Generate an array. This is a pretty long message for such a short explanation. Kinda Rube Goldbergish.",
+ "aliases": [
+ "a"
+ ]
+ }
+ },
+ "handler": "function (data) {\n if (data.help.requested) {\n return console.log(this.help)\n }\n\n let dir = process.cwd()\n\n if (data.flags.unrecognized.length > 0) {\n dir = path.resolve(data.flags.unrecognized[0])\n }\n\n const contents = fs.readdirSync(dir)\n\n if (data.flags.recognized.array) {\n return console.log(contents)\n }\n\n const result = Object.defineProperty({}, dir, {\n enumerable: true,\n value: contents\n })\n\n console.log(JSON.stringify(result, null, 2))\n }",
+ "commands": {},
+ "middleware": []
+ }
+ },
+ "middleware": []
+ },
+ "mkdir": {
+ "description": "Make a new directory.",
+ "help": "dir mkdir [OPTIONS]\n\n Make a new directory.\n\nOptions:\n\n -p [-R] : Recursively create the directory if it does not\n already exist.\n",
+ "usage": "dir mkdir [OPTIONS]\n\n Make a new directory.",
+ "aliases": [
+ "md",
+ "m"
+ ],
+ "flags": {
+ "p": {
+ "type": "boolean",
+ "default": false,
+ "description": "Recursively create the directory if it does not already exist.",
+ "aliases": [
+ "R"
+ ]
+ }
+ },
+ "handler": "function (data) {\n console.log('...make a directory...')\n console.log(data)\n }",
+ "commands": {},
+ "middleware": []
+ },
+ "doc": {
+ "description": "Output the metadoc of this shell.",
+ "help": "dir doc [OPTIONS]\n\n Output the metadoc of this shell.\n\nOptions:\n\n -file [-f] \n",
+ "usage": "dir doc [OPTIONS]\n\n Output the metadoc of this shell.",
+ "aliases": [],
+ "flags": {
+ "file": {
+ "name": "file",
+ "aliases": [
+ "f"
+ ]
+ },
+ "help": {
+ "description": "Display doc help.",
+ "aliases": [
+ "h"
+ ],
+ "default": false,
+ "type": "boolean",
+ "name": "help"
+ }
+ },
+ "handler": "function (meta) {\n let data = this.shell.data\n\n if (meta.flag('file') !== null) {\n fs.writeFileSync(path.resolve(meta.flag('file')), JSON.stringify(data, null, 2))\n } else {\n console.log(data)\n }\n }",
+ "commands": {},
+ "middleware": []
+ }
+ },
+ "middleware": [
+ "(data, next) => {\n console.log('This middleware runs on every command.')\n next()\n}"
+ ],
+ "help": "dir 1.0.0\n\n A simple file system utility.\n\n - list [ls] \t : List files of a directory. Optionally specify a\n long format.\n - export \t : Export a file representation of a directory.\n Has an additional subcommand.\n - mkdir [md, m] \t : Make a new directory.\n - doc \t : Output the metadoc of this shell.\n",
+ "usage": "dir 1.0.0\n\n A simple file system utility.",
+ "defaultHandler": "(data, cb) => {\n if (data.help && data.help.requested) {\n console.log(data.help.message)\n }\n\n cb && cb(data)\n }",
+ "authohelp": true,
+ "runtime": "node",
+ "maxHistoryItems": 100
+}
\ No newline at end of file
diff --git a/examples/json/index.js b/examples/json/index.js
new file mode 100755
index 0000000..f4a074d
--- /dev/null
+++ b/examples/json/index.js
@@ -0,0 +1,11 @@
+#!/usr/bin/env node --experimental-modules
+import fs from 'fs'
+import path from 'path'
+import { Command, Shell } from '../../src/index.js'
+import { fileURLToPath } from 'url'
+const __dirname = path.dirname(fileURLToPath(import.meta.url))
+
+const config = JSON.parse(fs.readFileSync(path.join(__dirname, 'dir.json')))
+const shell = new Shell(config)
+const cmd = process.argv.slice(2).join(' ').trim()
+shell.exec(cmd).catch(e => console.log(e.message || e))
diff --git a/examples/json/package-lock.json b/examples/json/package-lock.json
new file mode 100644
index 0000000..a46eb29
--- /dev/null
+++ b/examples/json/package-lock.json
@@ -0,0 +1,5 @@
+{
+ "name": "jdir",
+ "version": "1.0.0",
+ "lockfileVersion": 1
+}
diff --git a/examples/json/package.json b/examples/json/package.json
new file mode 100644
index 0000000..f7005d4
--- /dev/null
+++ b/examples/json/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "jdir",
+ "version": "1.0.0",
+ "description": "A simple file system utility.",
+ "main": "index.js",
+ "bin": {
+ "jdir": "index.js"
+ },
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "type": "module",
+ "private": true,
+ "author": "Corey Butler",
+ "license": "MIT",
+ "engines": {
+ "node": "^12.0.0"
+ },
+ "dependencies": {}
+}
diff --git a/package.json b/package.json
index 03a01af..d0aed8c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.2.1",
+ "version": "1.3.0-beta.1",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/command.js b/src/command.js
index 9464604..a929a7f 100644
--- a/src/command.js
+++ b/src/command.js
@@ -1,16 +1,18 @@
import { Parser } from '../node_modules/@author.io/arg/index.js'
import Middleware from './middleware.js'
+import Shell from './shell.js'
const STRIP_EQUAL_SIGNS = /(\=+)(?=([^'"\\]*(\\.|['"]([^'"\\]*\\.)*[^'"\\]*['"]))*[^'"]*$)/g
const SUBCOMMAND_PATTERN = /^([^"'][\S\b]+)[\s+]?([^-].*)$/i
const FLAG_PATTERN = /((?:"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|\/[^\/\\]*(?:\\[\S\s][^\/\\]*)*\/[gimy]*(?=\s|$)|(?:\\\s|\S))+)(?=\s|$)/g
+const METHOD_PATTERN = /^([\w]+\s?)\(.*\)\s?{/i
export default class Command {
#pattern
#oid
#name
#description
- #aliases
+ #aliases = new Set()
#customUsage
#customHelp
#fn
@@ -35,8 +37,26 @@ export default class Command {
throw new Error('Invalid command configuration. A "name" attribute is required.')
}
- if (cfg.handler && typeof cfg.handler !== 'function') {
- throw new Error('Invalid command configuration. A "handler" function is required.')
+ if (cfg.hasOwnProperty('handler')) {
+ if (typeof cfg.handler === 'string') {
+ cfg.handler = Function('return (' + cfg.handler.replace('function anonymous', 'function') + ').call(this)').call(globalThis)
+ }
+
+ if (typeof cfg.handler !== 'function') {
+ throw new Error('Invalid command configuration. A "handler" function is required.')
+ }
+
+ if (cfg.hasOwnProperty('help') && cfg.help === this.help) {
+ delete cfg.help
+ }
+
+ if (cfg.hasOwnProperty('usage') && cfg.usage === this.usage) {
+ delete cfg.usage
+ }
+ }
+
+ if (cfg.hasOwnProperty('middleware') && Array.isArray(cfg.middleware)) {
+ cfg.middleware.forEach(code => this.use(Function(code)))
}
this.#name = cfg.name.trim().split(/\s+/)[0]
@@ -97,7 +117,8 @@ export default class Command {
'usage',
'pattern',
'name',
- 'handler'
+ 'handler',
+ 'middleware'
])
const unrecognized = Object.keys(cfg).filter(attribute => !attributes.has(attribute))
@@ -117,18 +138,40 @@ export default class Command {
commands[name] = data
})
+ let handler = (this.#fn || this.#defaultHandler).toString()
+ if (METHOD_PATTERN.test(handler)) {
+ handler = handler.replace(METHOD_PATTERN.exec(handler)[1], 'function ')
+ }
+
+ let flags = this.#flagConfig || {}
+ for (let [key, value] of Object.entries(flags)) {
+ value.aliases = value.aliases || []
+
+ if (value.hasOwnProperty('alias')) {
+ if (value.aliases.indexOf(value.alias) < 0) {
+ value.aliases.push(value.alias)
+ }
+ }
+
+ delete value.alias
+ }
+
const data = {
name: this.#name,
description: this.description,
help: this.help,
usage: this.usage,
- aliases: this.#aliases || [],
- flags: this.#flagConfig || {},
- handler: (this.#fn || this.#defaultHandler).toString(),
+ aliases: Array.from(this.#aliases),
+ flags,
+ handler,
commands,
middleware: this.#middleware.data
}
+ for (let [key, value] of Object.entries(data.flags)) {
+ delete value.alias
+ }
+
return data
}
@@ -165,7 +208,11 @@ export default class Command {
}
set shell (shell) {
- this.#shell = shell
+ if (shell instanceof Shell) {
+ this.#shell = shell
+ } else {
+ throw new Error(`Expected a Shell object, received a "${typeof shell}" object.`)
+ }
}
get shell () {
@@ -173,10 +220,11 @@ export default class Command {
if (this.#parent) {
return this.#parent.shell
}
- return ''
+
+ return null
}
- return this.#shell.name
+ return this.#shell
}
get autohelp() {
@@ -523,7 +571,7 @@ export default class Command {
}
async run (input, callback) {
- let fn = this.#fn || this.#defaultHandler
+ let fn = (this.#fn || this.#defaultHandler).bind(this)
let data = typeof input === 'string' ? this.parse(input) : input
const parsed = SUBCOMMAND_PATTERN.exec(input)
@@ -589,7 +637,7 @@ export default class Command {
return this.#middleware.run(...arguments, () => {})
}
- return Command.reply(await processor.run(args, callback))
+ return Command.reply(await processor.run(args, callback()))
}
// No subcommand was recognized
diff --git a/src/middleware.js b/src/middleware.js
index 62f8657..80f4280 100644
--- a/src/middleware.js
+++ b/src/middleware.js
@@ -9,7 +9,11 @@ export default class Middleware {
get data () { return this._data }
use (method) {
- this._data.push(method.toString())
+ const methodBody = method.toString()
+ if (methodBody.indexOf('[native code]') < 0) {
+ this._data.push(methodBody)
+ }
+
this.run = ((stack) => (...args) => stack(...reduce(args), () => {
const next = last(args)
method.apply(this, [...reduce(args), next.bind.apply(next, [null, ...reduce(args)])])
diff --git a/src/shell.js b/src/shell.js
index 635712a..9a75af3 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -41,7 +41,7 @@ export default class Shell {
this.#name = cfg.name || 'unknown'
this.#description = cfg.description || null
this.#version = cfg.version || '1.0.0'
- this.#maxHistoryItems = cfg.maxhistory || 100
+ this.#maxHistoryItems = cfg.maxhistory || cfg.maxHistoryItems || 100
this.#tabWidth = cfg.hasOwnProperty('tabWidth') ? cfg.tabWidth : 4
this.#tableWidth = cfg.hasOwnProperty('tableWidth') ? cfg.tableWidth : 70
@@ -50,12 +50,30 @@ export default class Shell {
this.#autohelp = cfg.autohelp
}
- if (cfg.hasOwnProperty('defaultHandler')) {
+ if (cfg.hasOwnProperty('defaultHandler') && cfg.defaultHandler.toString() !== this.#defaultHandler.toString()) {
this.defaultHandler = cfg.defaultHandler
}
if (Array.isArray(cfg.commands)) {
cfg.commands.forEach(cmd => this.add(cmd))
+ } else if (typeof cfg.commands === 'object') {
+ for (const key in cfg.commands) {
+ let data = cfg.commands[key]
+ data.name = key
+ this.add(data)
+ }
+ }
+
+ if (cfg.hasOwnProperty('middleware') && Array.isArray(cfg.middleware)) {
+ cfg.middleware.forEach(code => this.use(Function('return ' + code)()))
+ }
+
+ if (cfg.hasOwnProperty('help') && cfg.help !== this.help) {
+ this.#customHelp = cfg.help
+ }
+
+ if (cfg.hasOwnProperty('usage') && cfg.usage !== this.usage) {
+ this.#customUsage = cfg.usage
}
}
From c88b3b38d77cbec70664a6e84bdc2caed74d2e0e Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 21 Apr 2020 00:43:27 -0500
Subject: [PATCH 017/152] Update README.md
Fixed npm install path.
---
README.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 017502f..346833b 100644
--- a/README.md
+++ b/README.md
@@ -66,9 +66,9 @@ Also available from [jsdelivr](https://www.jsdelivr.com/?query=%40author.io%2Fsh
If you wish to bundle this library in your build process, use the version most appropriate for your target runtimes:
-- `npm install @author/shell` (source)
-- `npm install @author/browser-shell` (Minified ES Module)
-- `npm install @author/browser-shell-es6` (IIFE Minified Module - globally accessible)
+- `npm install @author.io/shell` (source)
+- `npm install @author.io/browser-shell` (Minified ES Module)
+- `npm install @author.io/browser-shell-es6` (IIFE Minified Module - globally accessible)
### Debugging
From 97277950c201e04d29f4adeadc684a40ce2a392c Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 21 Apr 2020 17:11:12 -0500
Subject: [PATCH 018/152] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 346833b..907aec9 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# @author.io/shell 
- using the [cross-runtime template](https://github.com/author/template-cross-runtime).
+ using the [cross-runtime template](https://github.com/author/template-cross-runtime).
This is a super-lightweight framework for building text-based programs, like [CLI](https://en.wikipedia.org/wiki/Command-line_interface) applications.
From 089fd7b42c33c4c1f315c18c5e782e82c8e26aba Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 21 Apr 2020 23:55:27 -0500
Subject: [PATCH 019/152] Added introspection and config loading. Abstracted
usage/help content generation into new author/table module. The rest were bug
fixes and tweaks.
---
.github/workflows/deploy.yml | 2 +-
README.md | 14 +++
examples/cli/index.js | 2 +-
package-lock.json | 7 +-
package.json | 3 +-
src/command.js | 176 ++++++++++++-------------------
src/format.js | 82 ++++++++++++++
src/index.js | 5 +-
src/shell.js | 159 +++++++++++++++-------------
test/unit/01-sanity/01-sanity.js | 35 +++++-
10 files changed, 298 insertions(+), 187 deletions(-)
create mode 100644 src/format.js
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index d63c6ad..0630e7b 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -84,7 +84,7 @@ jobs:
if: steps.autotagger.outputs.tagname != ''
uses: author/action-publish@master
with:
- scan: .dist
+ scan: .dist, ./
env:
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
diff --git a/README.md b/README.md
index 017502f..7a11b31 100644
--- a/README.md
+++ b/README.md
@@ -324,3 +324,17 @@ cmd.use(function (metadata, next) {
One development goal of this framework is to remain as lightweight and unopinionated as possible. Another is to be as simple to use as possible. These two goals often conflict with each other (the more features you add, the heavier it becomes). In an attempt to find a comfortable balance, some additional middleware libraries are available for those who want a little extra functionality.
1. [@author.io/shell-middleware](https://github.com/author/shell-middleware)
+
+### Introspection/Metadata Generation
+
+A JSON metadoc can be produced from the shell:
+
+```javascript
+console.log(shell.data)
+```
+
+Simple CLI utilities can also be loaded entirely from a JSON file by passing the object into the shell constructor as the only argument. The limitation is no imports or hoisted variables/methods will be recognized in a shell which is loaded this way.
+
+### Related Modules
+
+1. [@author.io/table](https://github.com/author/table) - Used to generate the default usage/help messages for the shell and subcommands.
\ No newline at end of file
diff --git a/examples/cli/index.js b/examples/cli/index.js
index 2079fb8..468f695 100755
--- a/examples/cli/index.js
+++ b/examples/cli/index.js
@@ -2,7 +2,7 @@
import fs from 'fs'
import path from 'path'
-import { Command, Shell } from '../../src/index.js'
+import { Command, Shell, Formatter } from '../../src/index.js'
import { fileURLToPath } from 'url'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
diff --git a/package-lock.json b/package-lock.json
index a350a99..eb1f27a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.1.9",
+ "version": "1.3.0-beta.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -8,6 +8,11 @@
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.2.5.tgz",
"integrity": "sha512-i+6F2ViIojVDqs+GS6Att/79SPDvdTijYzNg0VmNXF/03MIPWKnVwyRLOCpTx0pRjZNa3WQJwGZ3vqGN36lG1w=="
+ },
+ "@author.io/table": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.0.0-beta.2.tgz",
+ "integrity": "sha512-TMylr6d9K/XYVBoNNLJnHwhMPS3P3fwzf6aQMj5r8KbhHtsjCha0wflBfNOmZgB/003a09Hv+cyNsZU+aaHeQQ=="
}
}
}
diff --git a/package.json b/package.json
index d0aed8c..161d89a 100644
--- a/package.json
+++ b/package.json
@@ -50,6 +50,7 @@
]
},
"dependencies": {
- "@author.io/arg": "^1.2.5"
+ "@author.io/arg": "^1.2.5",
+ "@author.io/table": "^1.0.0-beta.2"
}
}
diff --git a/src/command.js b/src/command.js
index a929a7f..0baebdf 100644
--- a/src/command.js
+++ b/src/command.js
@@ -1,6 +1,7 @@
import { Parser } from '../node_modules/@author.io/arg/index.js'
import Middleware from './middleware.js'
import Shell from './shell.js'
+import Formatter from './format.js'
const STRIP_EQUAL_SIGNS = /(\=+)(?=([^'"\\]*(\\.|['"]([^'"\\]*\\.)*[^'"\\]*['"]))*[^'"]*$)/g
const SUBCOMMAND_PATTERN = /^([^"'][\S\b]+)[\s+]?([^-].*)$/i
@@ -8,6 +9,7 @@ const FLAG_PATTERN = /((?:"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\
const METHOD_PATTERN = /^([\w]+\s?)\(.*\)\s?{/i
export default class Command {
+ #formattedDefaultHelp
#pattern
#oid
#name
@@ -23,10 +25,12 @@ export default class Command {
#parent = null
#shell = null
#middleware = new Middleware()
- #tabWidth
- #tableWidth
#hasCustomDefaultHandler = false
#defaultHandler = data => console.log(this.help)
+ #updateHelp = () => {
+ this.#formattedDefaultHelp = new Formatter(this)
+ this.#formattedDefaultHelp.width = this.shell === null ? 80 : this.shell.tableWidth
+ }
constructor (cfg = {}) {
if (typeof cfg !== 'object') {
@@ -46,12 +50,12 @@ export default class Command {
throw new Error('Invalid command configuration. A "handler" function is required.')
}
- if (cfg.hasOwnProperty('help') && cfg.help === this.help) {
- delete cfg.help
+ if (cfg.hasOwnProperty('help')) {
+ this.help = cfg.help
}
- if (cfg.hasOwnProperty('usage') && cfg.usage === this.usage) {
- delete cfg.usage
+ if (cfg.hasOwnProperty('usage')) {
+ this.usage = cfg.usage
}
}
@@ -65,17 +69,20 @@ export default class Command {
this.#pattern = cfg.pattern || /[\s\S]+/i
this.#customUsage = cfg.usage || null
this.#customHelp = cfg.help || null
- this.aliases = cfg.aliases
+ // this.aliases = cfg.aliases
this.#description = cfg.description || null
- this.#tabWidth = cfg.hasOwnProperty('tabWidth') ? cfg.tabWidth : 4
- this.#tableWidth = cfg.hasOwnProperty('tableWidth') ? cfg.tableWidth : 70
- if (cfg.alias) {
- if (Array.isArray(cfg.alias)) {
- this.aliases = cfg.alias
- } else {
- this.aliases.push(cfg.alias)
+ if (cfg.alias && !cfg.aliases) {
+ cfg.aliases = Array.isArray(cfg.alias) ? cfg.alias : [cfg.alias]
+ delete cfg.alias
+ }
+
+ if (cfg.aliases) {
+ if (!Array.isArray(cfg.aliases)) {
+ throw new Error('The alias property only accepts an array.')
}
+
+ this.#aliases = new Set(cfg.aliases)
}
if (cfg.flags) {
@@ -83,6 +90,25 @@ export default class Command {
throw new Error(`Invalid flag configuration (expected and object, received ${typeof cfg.flags}).`)
}
+ for (const [key, value] of Object.entries(cfg.flags)) {
+ if (value.hasOwnProperty('alias')) {
+ value.aliases = value.aliases || []
+
+ if (Array.isArray(value.alias)) {
+ value.aliases = Array.from(new Set(...value.aliases, ... value.alias))
+ if (value.aliases.filter(a => typeof a !== 'string') > 0) {
+ throw new Error(`${key} flag aliases must be strings. Type failure on: ${value.aliases.filter(a => typeof a !== 'string').join(', ')}.`)
+ }
+ } else if (typeof value.alias === 'string') {
+ value.aliases.push(value.alias)
+ } else {
+ throw new Error(`Aliases must be strings, not ${typeof value.alias} (${key} flag).`)
+ }
+
+ delete value.alias
+ }
+ }
+
this.#flagConfig = cfg.flags
}
@@ -110,8 +136,6 @@ export default class Command {
'flags',
'alias',
'aliases',
- 'tabWidth',
- 'tableWidth',
'description',
'help',
'usage',
@@ -126,6 +150,20 @@ export default class Command {
if (unrecognized.length > 0) {
throw new Error(`Unrecognized shell configuration attribute(s): ${unrecognized.join(', ')}`)
}
+
+ Object.defineProperties(this, {
+ __flagConfig: {
+ enumerable: false,
+ get () {
+ const flags = new Map()
+ Object.keys(this.#flagConfig).forEach(key => flags.set(key, this.#flagConfig[key]))
+ flags.delete('help')
+ return flags
+ }
+ }
+ })
+
+ this.#updateHelp()
}
get data () {
@@ -144,6 +182,7 @@ export default class Command {
}
let flags = this.#flagConfig || {}
+
for (let [key, value] of Object.entries(flags)) {
value.aliases = value.aliases || []
@@ -175,16 +214,6 @@ export default class Command {
return data
}
- set tableWidth(value) {
- this.#tableWidth = value
- this.#processors.forEach(cmd => cmd.tableWidth = value)
- }
-
- set tabWidth(value) {
- this.#tabWidth = value
- this.#processors.forEach(cmd => cmd.tabWidth = value)
- }
-
// @private
set defaultHandler (value) {
if (typeof value === 'function') {
@@ -204,10 +233,15 @@ export default class Command {
set parent (cmd) {
if (cmd instanceof Command) {
this.#parent = cmd
+ } else {
+ throw new Error(`Cannot set parent of "${this.name}" command to anything other than another command. To make this command a direct descendent of the main shell, use the shell attribute instead.`)
}
}
set shell (shell) {
+ if (!shell) {
+ throw new Error(`Cannot set shell of ${this.name} command to a non-Shell object.`)
+ }
if (shell instanceof Shell) {
this.#shell = shell
} else {
@@ -248,7 +282,7 @@ export default class Command {
}
get description () {
- return this.#description || this.usage || ''
+ return this.#description || ''
}
get commandroot () {
@@ -264,17 +298,13 @@ export default class Command {
}
get usage () {
- if (this.#customUsage) {
+ if (this.#customUsage !== null) {
return typeof this.#customUsage === 'function' ? this.#customUsage() : this.#customUsage
}
- const a = Array.from(this.#aliases)
- const msg = [`${this.commandroot}${a.length > 0 ? ' <' + a.join(', ') + '> ' : ''} [OPTIONS]`.trim()]
+ this.#updateHelp()
- if ((this.#description || '').trim().length > 0) {
- msg.push('\n ' + (this.#description || '').trim())
- }
- return msg.join('\n').trim()
+ return this.#formattedDefaultHelp.usage
}
set usage (value) {
@@ -286,79 +316,9 @@ export default class Command {
return typeof this.#customHelp === 'function' ? this.#customHelp() : this.#customHelp
}
- let maxWidth = this.#tableWidth
- let tabWidth = this.#tabWidth
-
- let msg = [this.usage + '\n']
- let flags = Object.keys(this.#flagConfig || {}).filter(f => f !== 'help')
- if (flags.length > 0) {
- msg.push('Options:\n')
-
- flags.forEach(flag => {
- let message = ` -${flag}`
- flag = this.#flagConfig[flag]
- flag.alias = Array.isArray(flag.alias) ? flag.alias : [flag.alias]
- if (flag.aliases) {
- flag.alias = flag.alias.concat(flag.aliases)
- }
- flag.alias = new Set(flag.alias.filter(a => typeof a === 'string'))
-
- if (flag.alias.size > 0) {
- message += ` [${Array.from(flag.alias).map(a => '-'+a).join(', ')}]`
- }
- message += '\t'
-
- let desc = []
- let tabs = message.match(/\t/gi).length
- let prefixLength = message.length + 2 + (this.#tabWidth*tabs)
- let dsc = new String(flag.description)
- const match = new RegExp(`(.{0,${this.#tableWidth-prefixLength}}[\\s\n])`, 'g')
-
- if (flag.description) {
- desc = flag.description.match(match)
- desc.push(dsc.replace(desc.join(''), ''))
- }
-
- while (desc.length > 1 && desc[desc.length - 1].length + desc[desc.length - 2].length < (this.#tableWidth-prefixLength)) {
- desc[desc.length - 2] += desc.pop()
- }
-
- desc = desc.reverse().map(item => item.trim())
-
- if (desc.length > 0) {
- let prefix = ''
- for (let i = 0; i < prefixLength; i++) {
- prefix += ' '
- }
-
- message += ' : ' + desc.pop()
- while (desc.length > 0) {
- message += `\n${prefix}${desc.pop()}`
- }
- }
-
- msg.push(message)
- })
- } else if (this.#processors.size > 0) {
- msg.push('Options:\n')
- }
-
- this.#processors.forEach(proc => {
- let message = ` ${ proc.name }: \t ${ proc.description } `
-
- if (proc.aliases.length > 0) {
- message = `${ message } Aliases: ${ proc.aliases.join(', ') }.`
- }
- msg.push(message)
- })
-
- let tab = ''
- for (let i = 0; i < tabWidth; i++) {
- tab += ' '
- }
+ this.#updateHelp()
- return (msg.join('\n') + '\n').replace(/\n{2,}$/, '\n').replace(/\t/gi, tab)
- // return `${this.#name} help goes here`
+ return this.#formattedDefaultHelp.help
}
set help (value) {
@@ -396,7 +356,7 @@ export default class Command {
}
get aliases () {
- return this.#aliases
+ return Array.from(this.#aliases) || []
}
get OID () {
@@ -439,8 +399,6 @@ export default class Command {
command.parent = this
command.autohelp = this.#autohelp
- command.tabWidth = this.#tabWidth
- command.tableWidth = this.#tableWidth
this.#processors.set(command.OID, command)
this.#subcommands.set(command.name, command.OID)
diff --git a/src/format.js b/src/format.js
new file mode 100644
index 0000000..30b50b7
--- /dev/null
+++ b/src/format.js
@@ -0,0 +1,82 @@
+import Table from '../node_modules/@author.io/table/src/index.js'
+import Command from './command.js'
+import Shell from './shell.js'
+
+class Formatter {
+ #data = null
+ #tableWidth = 80
+ #colAlign = [] // Defaults to ['l', 'l', 'l']
+ #colWidth = ['15%', '20%', '65%']
+
+ constructor (data) {
+ this.#data = data
+ }
+
+ set width (value) {
+ this.#tableWidth = value < 20 ? 20 : value
+ }
+
+ set columnWidths (value) {
+ this.#colWidth = value
+ }
+
+ set columnAlignment (value) {
+ this.#colAlign = value
+ }
+
+ get usage () {
+ if (this.#data instanceof Command) {
+ const aliases = this.#data.aliases
+ const out = [`${this.#data.commandroot}${aliases.length > 0 ? ' <' + aliases.join(', ') + '>' : ''}${this.#data.__flagConfig.size > 0 ? ' [OPTIONS]' : ''}`]
+ const desc = this.#data.description.trim()
+
+ if (desc.trim().length > 0 && out !== desc) {
+ out.push(`\n ${desc.trim()}` + '\n')
+ }
+
+ return out.join('\n')
+ } else if (this.#data instanceof Shell) {
+ return `${this.#data.name}${this.#data.__commandMap.size > 0 ? ' [COMMAND]' : ''}\n\n ${this.#data.description || ''} Version ${this.#data.version}.\n`.trim()
+ }
+
+ return ''
+ }
+
+ get help () {
+ const usage = this.usage.trim()
+
+ if (this.#data instanceof Command) {
+ const flags = this.#data.__flagConfig
+ const rows = []
+ if (flags.size > 0) {
+ flags.forEach((cfg, flag) => {
+ let aliases = Array.from(cfg.aliases||[])
+ aliases = aliases.length === 0 ? '' : '[' + aliases.map(a => `-${a}`).join(', ') + ']'
+ rows.push(['-' + flag, aliases, cfg.description])
+ })
+ }
+
+ const table = new Table(rows, this.#colAlign, this.#colWidth, this.#tableWidth, [2, 0, usage.length > 0 ? 1 : 0, 0])
+
+ return usage + '\n\nOptions:' + table.output
+ } else if (this.#data instanceof Shell) {
+ const rows = Array.from(this.#data.__commandMap.values()).map(cmd => {
+ return [cmd.name, (cmd.aliases||[]).length > 0 ? `[${cmd.aliases.join(', ').trim()}]` : '', cmd.description]
+ })
+
+ let result = [usage]
+
+ if (rows.length > 0) {
+ const table = new Table(rows, this.#colAlign, this.#colWidth, this.#tableWidth, [2])
+ result.push(`\nCommands:\n`)
+ result.push(table.output)
+ }
+
+ return result.join('\n')
+ }
+
+ return ''
+ }
+}
+
+export { Formatter as default, Table }
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index cee3106..fac9f1c 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,4 +1,5 @@
import Command from './command.js'
import Shell from './shell.js'
-const all = { Shell, Command }
-export { Command, Shell, all as default }
+import Formatter from './format.js'
+const all = { Shell, Command, Formatter }
+export { Command, Shell, Formatter, all as default }
diff --git a/src/shell.js b/src/shell.js
index 9a75af3..66598ed 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -1,9 +1,11 @@
import Command from './command.js'
import Middleware from './middleware.js'
+import Formatter from './format.js'
const COMMAND_PATTERN = /^(\w+)\s+([\s\S]+)?/i
export default class Shell {
+ #formattedDefaultHelp
#processors = new Map()
#commands = new Map()
#middleware = new Middleware()
@@ -36,6 +38,10 @@ export default class Shell {
cb && cb(data)
}
+ #updateHelp = () => {
+ this.#formattedDefaultHelp = new Formatter(this)
+ this.#formattedDefaultHelp.width = this.#tableWidth
+ }
constructor (cfg = { maxhistory: 100 }) {
this.#name = cfg.name || 'unknown'
@@ -75,6 +81,13 @@ export default class Shell {
if (cfg.hasOwnProperty('usage') && cfg.usage !== this.usage) {
this.#customUsage = cfg.usage
}
+
+ Object.defineProperty(this, '__commandMap', {
+ enumerable: false,
+ get () {
+ return this.#processors
+ }
+ })
}
get data () {
@@ -116,12 +129,10 @@ export default class Shell {
set tableWidth(value) {
this.#tableWidth = value
- this.#processors.forEach(cmd => cmd.tableWidth = value)
}
- set tabWidth(value) {
- this.#tabWidth = value
- this.#processors.forEach(cmd => cmd.tabWidth = value)
+ get tableWidth () {
+ return this.#tableWidth || 80
}
get autohelp () {
@@ -161,11 +172,13 @@ export default class Shell {
}
get usage () {
- if (this.#customUsage) {
- return typeof this.#customUsage === 'function' ? this.#customUsage(this) : this.#customUsage
+ if (this.#customUsage !== null) {
+ return typeof this.#customUsage === 'function' ? this.#customUsage() : this.#customUsage
}
- return `${this.#name} ${this.#version}\n\n ${this.#description || ''}\n`.trim()
+ this.#updateHelp()
+
+ return this.#formattedDefaultHelp.usage
}
set usage (value) {
@@ -177,90 +190,94 @@ export default class Shell {
return typeof this.#customHelp === 'function' ? this.#customHelp(this) : this.#customHelp
}
- let mainmsg = [this.usage + '\n']
+ this.#updateHelp()
- const help = new Map()
+ return this.#formattedDefaultHelp.help
- let nameWidth = 0
- let aliasWidth = 0
- let tabWidth = this.#tabWidth
- let maxWidth = this.#tableWidth
+ // let mainmsg = [this.usage + '\n']
- this.#processors.forEach(proc => {
- nameWidth = proc.name.length > nameWidth ? proc.name.length : nameWidth
- aliasWidth = proc.aliases.join(', ').trim().length + proc.aliases.length > aliasWidth ? proc.aliases.join(', ').trim().length + proc.aliases.length : aliasWidth
+ // const help = new Map()
- let summary = proc.description
+ // let nameWidth = 0
+ // let aliasWidth = 0
+ // let tabWidth = this.#tabWidth
+ // let maxWidth = this.#tableWidth
- let size = proc.subcommands.size
- if (size > 0) {
- summary += ` Has ${ size === 1 ? 'an' : size } additional subcommand${ size !== 1 ? 's' : '' }.`
- }
+ // this.#processors.forEach(proc => {
+ // nameWidth = proc.name.length > nameWidth ? proc.name.length : nameWidth
+ // aliasWidth = proc.aliases.join(', ').trim().length + proc.aliases.length > aliasWidth ? proc.aliases.join(', ').trim().length + proc.aliases.length : aliasWidth
- help.set(proc.name, {
- description: summary,
- aliases: proc.aliases
- })
- })
+ // let summary = proc.description
- help.forEach((data, name) => {
- let msg = name
+ // let size = proc.subcommands.size
+ // if (size > 0) {
+ // summary += ` Has ${ size === 1 ? 'an' : size } additional subcommand${ size !== 1 ? 's' : '' }.`
+ // }
- // Command name
- while (msg.length < nameWidth) {
- msg += ' '
- }
+ // help.set(proc.name, {
+ // description: summary,
+ // aliases: proc.aliases
+ // })
+ // })
- // Aliases
- let aliases = data.aliases.map(item => `${item}`).join(', ')
- while (aliases.length < aliasWidth) {
- aliases += ' '
- }
+ // help.forEach((data, name) => {
+ // let msg = name
- msg += (aliases.trim().length > 0 ? ' [' + aliases.replace(/^(.*[^\s])/i, '$1]$`') : aliases) + '\t'
+ // // Command name
+ // while (msg.length < nameWidth) {
+ // msg += ' '
+ // }
- // Desc
- let desc = []
- let tabs = msg.match(/\t/gi).length
- let descWidth = maxWidth - (nameWidth + aliasWidth + 10)
+ // // Aliases
+ // let aliases = data.aliases.map(item => `${item}`).join(', ')
+ // while (aliases.length < aliasWidth) {
+ // aliases += ' '
+ // }
- if (data.description && data.description.length > descWidth) {
- let dsc = new String(data.description)
- let match = new RegExp(`(.{0,${descWidth}}[\\s\n])`, 'g')
+ // msg += (aliases.trim().length > 0 ? ' [' + aliases.replace(/^(.*[^\s])/i, '$1]$`') : aliases) + '\t'
- desc = data.description.match(match)
- desc.push(dsc.replace(desc.join(''), ''))
+ // // Desc
+ // let desc = []
+ // let tabs = msg.match(/\t/gi).length
+ // let descWidth = maxWidth - (nameWidth + aliasWidth + 10)
- while (desc.length > 1 && desc[desc.length - 1].length + desc[desc.length - 2].length < descWidth) {
- desc[desc.length - 2] += desc.pop()
- }
+ // if (data.description && data.description.length > descWidth) {
+ // let dsc = new String(data.description)
+ // let match = new RegExp(`(.{0,${descWidth}}[\\s\n])`, 'g')
- desc = desc.reverse().map(item => item.trim())
- } else {
- desc.push(data.description)
- }
+ // desc = data.description.match(match)
+ // desc.push(dsc.replace(desc.join(''), ''))
- if (desc.length > 0) {
- let prefix = ''
- for (let i = 0; i < (nameWidth + aliasWidth + 10 + (tabs * tabWidth)); i++) {
- prefix += ' '
- }
+ // while (desc.length > 1 && desc[desc.length - 1].length + desc[desc.length - 2].length < descWidth) {
+ // desc[desc.length - 2] += desc.pop()
+ // }
- msg += ' : ' + desc.pop()
- while (desc.length > 0) {
- msg += `\n${prefix}${desc.pop()}`
- }
- }
+ // desc = desc.reverse().map(item => item.trim())
+ // } else {
+ // desc.push(data.description)
+ // }
- mainmsg.push(' - ' + msg)
- })
+ // if (desc.length > 0) {
+ // let prefix = ''
+ // for (let i = 0; i < (nameWidth + aliasWidth + 10 + (tabs * tabWidth)); i++) {
+ // prefix += ' '
+ // }
- let tab = ''
- for (let i = 0; i < tabWidth; i++) {
- tab += ' '
- }
+ // msg += ' : ' + desc.pop()
+ // while (desc.length > 0) {
+ // msg += `\n${prefix}${desc.pop()}`
+ // }
+ // }
+
+ // mainmsg.push(' - ' + msg)
+ // })
+
+ // let tab = ''
+ // for (let i = 0; i < tabWidth; i++) {
+ // tab += ' '
+ // }
- return mainmsg.join('\n') + '\n'.replace(/\n{2,}$/, '\n').replace(/\t/g, tab)
+ // return mainmsg.join('\n') + '\n'.replace(/\n{2,}$/, '\n').replace(/\t/g, tab)
}
set help (value) {
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index 6e5ac0f..a8c1683 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -1,6 +1,6 @@
import 'source-map-support/register.js'
import test from 'tape'
-import { Command, Shell } from '../../.node/index.js'
+import { Command, Shell, Formatter } from '../../.node/index.js'
test('Sanity Check - Shell', t => {
const shell = new Shell({
@@ -45,3 +45,36 @@ test('Sanity Check - Command', t => {
t.end()
}).catch(e => t.fail(e.message))
})
+
+test('Output Formatting', t => {
+ const shell = new Shell({
+ name: 'test'
+ })
+
+ const cmd = new Command({
+ name: 'cmd',
+ alias: 'c',
+ flags: {
+ test: {
+ alias: 't',
+ description: 'test description'
+ },
+ more: {
+ aliases: ['m', 'mr'],
+ description: 'This is a longer description that should break onto more than one line, or perhaps even more than one extra line with especially poor grammar and spellling.'
+ },
+ none: {
+ description: 'Ignore me. I do not exist.'
+ }
+ }
+ })
+
+ shell.add(cmd)
+
+ const formatter = new Formatter(cmd)
+ formatter.width = 80
+
+ t.ok(formatter instanceof Formatter, 'Basic formatter instantiates correctly.')
+ console.log(formatter.help)
+ t.end()
+})
From 71f3361665a93e56c446a67f9d155e180106a5cc Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 21 Apr 2020 23:57:45 -0500
Subject: [PATCH 020/152] Version bump
---
package-lock.json | 2 +-
package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index eb1f27a..aff4ac6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.0-beta.1",
+ "version": "1.3.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 161d89a..6baf0a7 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.0-beta.1",
+ "version": "1.3.0",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
From 1e21efab2a2e06b784c0a9b2def4b8316cac4e19 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 21 Apr 2020 23:58:38 -0500
Subject: [PATCH 021/152] Updated dependencies.
---
package-lock.json | 8 ++++----
package.json | 4 ++--
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index aff4ac6..2c9d924 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.0",
+ "version": "1.3.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -10,9 +10,9 @@
"integrity": "sha512-i+6F2ViIojVDqs+GS6Att/79SPDvdTijYzNg0VmNXF/03MIPWKnVwyRLOCpTx0pRjZNa3WQJwGZ3vqGN36lG1w=="
},
"@author.io/table": {
- "version": "1.0.0-beta.2",
- "resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.0.0-beta.2.tgz",
- "integrity": "sha512-TMylr6d9K/XYVBoNNLJnHwhMPS3P3fwzf6aQMj5r8KbhHtsjCha0wflBfNOmZgB/003a09Hv+cyNsZU+aaHeQQ=="
+ "version": "1.0.0-beta.4",
+ "resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.0.0-beta.4.tgz",
+ "integrity": "sha512-EHKSpNDsejV4U5284UxoJtJW41aTHQJKyPUUzyl0x+AAq6F5wzmrXHun/MmfsxF+I/pZyXaUscPhMpanJVThcg=="
}
}
}
diff --git a/package.json b/package.json
index 6baf0a7..864c48d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.0",
+ "version": "1.3.1",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
@@ -51,6 +51,6 @@
},
"dependencies": {
"@author.io/arg": "^1.2.5",
- "@author.io/table": "^1.0.0-beta.2"
+ "@author.io/table": "^1.0.0-beta.4"
}
}
From c529f3b63cd0f03baf6d355a676b5a328657789a Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 22 Apr 2020 15:47:43 -0500
Subject: [PATCH 022/152] Updated build process. Fixed formatting (row
adjustments on line wrap). Version bump.
---
README.md | 44 +++++++++++++++
build/lib/build.js | 22 ++++++++
build/rollup.browser.config.js | 3 +
build/rollup.node.config.js | 8 ++-
build/rollup.test.browser.config.js | 3 +
build/rollup.test.node.config.js | 2 +
package.json | 4 +-
src/format.js | 7 ++-
src/index.js | 6 +-
src/shell.js | 85 -----------------------------
10 files changed, 89 insertions(+), 95 deletions(-)
diff --git a/README.md b/README.md
index ee65fb1..1fe498e 100644
--- a/README.md
+++ b/README.md
@@ -325,6 +325,50 @@ One development goal of this framework is to remain as lightweight and unopinion
1. [@author.io/shell-middleware](https://github.com/author/shell-middleware)
+### Customized Help/Usage Messages
+
+This library has only one dependency, [@author.io/table](https://github.com/author/table). It is used to format the usage and help messages within a shell app. The `Table` library can be used to create your own custom screens, though most users will likely want to stick with the defaults.
+
+_Example:_
+
+```javascript
+import { Shell, Command, Table } from '@author.io/node-shell'
+
+const shell = new Shell(...)
+shell.usage = '...'
+shell.help = () => {
+ const rows = [
+ ['Command', 'Alias Names'],
+ ['...', '...']
+ ]
+
+ const table = new Table(rows)
+
+ console.log(shell.usage + '\n' + table.output)
+}
+```
+
+**The `usage` and/or `help` attributes of an individual `Command` can also be set:**
+
+```javascript
+import { Shell, Command, Table } from '@author.io/node-shell'
+
+const cmd = new Command(...)
+cmd.usage = '...'
+cmd.help = () => {
+ const rows = [
+ ['Flags', 'Alias Names'],
+ ['...', '...']
+ ]
+
+ const table = new Table(rows)
+
+ console.log(cmd.usage + '\n' + table.output)
+}
+```
+
+There is also a `Formatter` class that helps combine usage/help messages internally. This class is exposed for those who want to dig into the inner workings, but it should be considered as more of an example than a supported feature. Since it is an internal class, it may change without warning (though we'll try to keep the methods consistent across releases).
+
### Introspection/Metadata Generation
A JSON metadoc can be produced from the shell:
diff --git a/build/lib/build.js b/build/lib/build.js
index 45fc308..9e9d0f8 100644
--- a/build/lib/build.js
+++ b/build/lib/build.js
@@ -1,5 +1,6 @@
import fs from 'fs'
import path from 'path'
+import chalk from 'chalk' // Included in Rollup
import stripCode from 'rollup-plugin-strip-code'
import replace from '@rollup/plugin-replace'
@@ -154,4 +155,25 @@ export default class build {
return false
}
+
+ ignoreCircularDependency () {
+ const refs = new Set([...arguments])
+
+ return warning => {
+ if (
+ warning.code === 'CIRCULAR_DEPENDENCY' &&
+ refs.size > 0 &&
+ Array.from(refs).filter(p => {
+ try {
+ return !warning.importer.indexOf(path.normalize(p))
+ } catch (e) { return false }
+ }).length > 0
+ ) {
+ return
+ }
+
+ console.log(chalk.yellow.bold(`(!) ${warning.code}`))
+ console.log(chalk.grey(warning.message))
+ }
+ }
}
diff --git a/build/rollup.browser.config.js b/build/rollup.browser.config.js
index 24881b4..a2f1142 100644
--- a/build/rollup.browser.config.js
+++ b/build/rollup.browser.config.js
@@ -33,6 +33,7 @@ const globalplugins = [
]
// 2. Build Browser Production Package: Standard (Minified/Munged)
+const onwarn = build.ignoreCircularDependency('../src/command.js', '../src/shell.js', '../src/format.js')
outdir += `/browser-${build.name}`
build.supportedBrowsers().forEach(edition => {
console.log(`Generating ${edition} browser code.`)
@@ -56,6 +57,7 @@ build.supportedBrowsers().forEach(edition => {
configuration.push({
input,
plugins,
+ onwarn,
output: {
banner: config.banner,
file: `${outdir}/${build.name}-${build.version}${edition !== 'current' ? '-' + edition : ''}.min.js`,
@@ -73,6 +75,7 @@ build.supportedBrowsers().forEach(edition => {
configuration.push({
input,
plugins,
+ onwarn,
output: {
banner: config.banner,
file: `${outdir}/${build.name}-${build.version}-global.min.js`,
diff --git a/build/rollup.node.config.js b/build/rollup.node.config.js
index 673088c..533fa81 100644
--- a/build/rollup.node.config.js
+++ b/build/rollup.node.config.js
@@ -13,7 +13,7 @@ install()
const build = new Build()
// Identify source file
-const input = path.resolve(`../${build.pkg.main||'../src/index.js'}`)
+const input = path.resolve(`../${build.pkg.main || '../src/index.js'}`)
// Configure metadata for the build process.
const rootdir = config.nodeOutput // Main output directory
@@ -26,7 +26,8 @@ fs.rmdirSync(rootdir, { recursive: true })
let terserCfg = config.terser
terserCfg.module = true
// terserCfg.mangle = { properties: true }
-console.log(terserCfg)
+// console.log(terserCfg)
+
// Identify plugins
const plugins = [
build.only('node'),
@@ -42,10 +43,12 @@ const plugins = [
]
// 2. Build Node Production Package: Standard (Minified/Munged)
+const onwarn = build.ignoreCircularDependency('../src/command.js', '../src/shell.js', '../src/format.js')
outdir += `/node-${build.name}`
configuration.push({
input,
plugins,
+ onwarn,
output: {
banner: config.banner,
file: `${outdir}/${build.name}-${build.version}.min.js`,
@@ -59,6 +62,7 @@ configuration.push({
configuration.push({
input,
plugins,
+ onwarn,
output: {
banner: config.banner,
file: `${outdir}-legacy/${build.name}-${build.version}.min.js`,
diff --git a/build/rollup.test.browser.config.js b/build/rollup.test.browser.config.js
index 7967033..d42218c 100644
--- a/build/rollup.test.browser.config.js
+++ b/build/rollup.test.browser.config.js
@@ -34,6 +34,7 @@ const globalplugins = [
]
// 2. Build Browser Production Package: Standard (Minified/Munged)
+const onwarn = build.ignoreCircularDependency('../src/command.js', '../src/shell.js', '../src/format.js')
build.supportedBrowsers().forEach(edition => {
console.log(`Generating ${edition} browser code.`)
const plugins = globalplugins.slice()
@@ -57,6 +58,7 @@ build.supportedBrowsers().forEach(edition => {
configuration.push({
input,
plugins,
+ onwarn,
output: {
exports: 'named',
banner: config.banner,
@@ -75,6 +77,7 @@ build.supportedBrowsers().forEach(edition => {
configuration.push({
input,
plugins,
+ onwarn,
output: {
exports: 'named',
banner: config.banner,
diff --git a/build/rollup.test.node.config.js b/build/rollup.test.node.config.js
index af06869..3fafdf7 100644
--- a/build/rollup.test.node.config.js
+++ b/build/rollup.test.node.config.js
@@ -43,9 +43,11 @@ const plugins = [
]
// 2. Build Node Production Package: Standard (Minified/Munged)
+const onwarn = build.ignoreCircularDependency('../src/command.js', '../src/shell.js', '../src/format.js')
configuration.push({
input,
plugins,
+ onwarn,
output: {
exports: 'named',
banner: config.banner,
diff --git a/package.json b/package.json
index 864c48d..88581c8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.1",
+ "version": "1.3.2",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
@@ -51,6 +51,6 @@
},
"dependencies": {
"@author.io/arg": "^1.2.5",
- "@author.io/table": "^1.0.0-beta.4"
+ "@author.io/table": "^1.0.0"
}
}
diff --git a/src/format.js b/src/format.js
index 30b50b7..a84881d 100644
--- a/src/format.js
+++ b/src/format.js
@@ -31,12 +31,12 @@ class Formatter {
const desc = this.#data.description.trim()
if (desc.trim().length > 0 && out !== desc) {
- out.push(`\n ${desc.trim()}` + '\n')
+ out.push(new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output)
}
return out.join('\n')
} else if (this.#data instanceof Shell) {
- return `${this.#data.name}${this.#data.__commandMap.size > 0 ? ' [COMMAND]' : ''}\n\n ${this.#data.description || ''} Version ${this.#data.version}.\n`.trim()
+ return `${this.#data.name}${this.#data.description.trim().length > 0 ? new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output : ''}${this.#data.__commandMap.size > 0 ? ' [COMMAND]' : ''}\n\n ${this.#data.description || ''} Version ${this.#data.version}.\n`.trim()
}
return ''
@@ -48,6 +48,7 @@ class Formatter {
if (this.#data instanceof Command) {
const flags = this.#data.__flagConfig
const rows = []
+
if (flags.size > 0) {
flags.forEach((cfg, flag) => {
let aliases = Array.from(cfg.aliases||[])
@@ -79,4 +80,4 @@ class Formatter {
}
}
-export { Formatter as default, Table }
\ No newline at end of file
+export { Formatter as default, Formatter, Table }
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index fac9f1c..cbdc682 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,5 +1,5 @@
import Command from './command.js'
import Shell from './shell.js'
-import Formatter from './format.js'
-const all = { Shell, Command, Formatter }
-export { Command, Shell, Formatter, all as default }
+import { Formatter, Table } from './format.js'
+const all = { Shell, Command, Formatter, Table }
+export { Command, Shell, Formatter, Table, all as default }
diff --git a/src/shell.js b/src/shell.js
index 66598ed..5186a15 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -193,91 +193,6 @@ export default class Shell {
this.#updateHelp()
return this.#formattedDefaultHelp.help
-
- // let mainmsg = [this.usage + '\n']
-
- // const help = new Map()
-
- // let nameWidth = 0
- // let aliasWidth = 0
- // let tabWidth = this.#tabWidth
- // let maxWidth = this.#tableWidth
-
- // this.#processors.forEach(proc => {
- // nameWidth = proc.name.length > nameWidth ? proc.name.length : nameWidth
- // aliasWidth = proc.aliases.join(', ').trim().length + proc.aliases.length > aliasWidth ? proc.aliases.join(', ').trim().length + proc.aliases.length : aliasWidth
-
- // let summary = proc.description
-
- // let size = proc.subcommands.size
- // if (size > 0) {
- // summary += ` Has ${ size === 1 ? 'an' : size } additional subcommand${ size !== 1 ? 's' : '' }.`
- // }
-
- // help.set(proc.name, {
- // description: summary,
- // aliases: proc.aliases
- // })
- // })
-
- // help.forEach((data, name) => {
- // let msg = name
-
- // // Command name
- // while (msg.length < nameWidth) {
- // msg += ' '
- // }
-
- // // Aliases
- // let aliases = data.aliases.map(item => `${item}`).join(', ')
- // while (aliases.length < aliasWidth) {
- // aliases += ' '
- // }
-
- // msg += (aliases.trim().length > 0 ? ' [' + aliases.replace(/^(.*[^\s])/i, '$1]$`') : aliases) + '\t'
-
- // // Desc
- // let desc = []
- // let tabs = msg.match(/\t/gi).length
- // let descWidth = maxWidth - (nameWidth + aliasWidth + 10)
-
- // if (data.description && data.description.length > descWidth) {
- // let dsc = new String(data.description)
- // let match = new RegExp(`(.{0,${descWidth}}[\\s\n])`, 'g')
-
- // desc = data.description.match(match)
- // desc.push(dsc.replace(desc.join(''), ''))
-
- // while (desc.length > 1 && desc[desc.length - 1].length + desc[desc.length - 2].length < descWidth) {
- // desc[desc.length - 2] += desc.pop()
- // }
-
- // desc = desc.reverse().map(item => item.trim())
- // } else {
- // desc.push(data.description)
- // }
-
- // if (desc.length > 0) {
- // let prefix = ''
- // for (let i = 0; i < (nameWidth + aliasWidth + 10 + (tabs * tabWidth)); i++) {
- // prefix += ' '
- // }
-
- // msg += ' : ' + desc.pop()
- // while (desc.length > 0) {
- // msg += `\n${prefix}${desc.pop()}`
- // }
- // }
-
- // mainmsg.push(' - ' + msg)
- // })
-
- // let tab = ''
- // for (let i = 0; i < tabWidth; i++) {
- // tab += ' '
- // }
-
- // return mainmsg.join('\n') + '\n'.replace(/\n{2,}$/, '\n').replace(/\t/g, tab)
}
set help (value) {
From 38806cfcafe5477f6254f6968efd1870ba5a1f95 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 22 Apr 2020 15:56:11 -0500
Subject: [PATCH 023/152] Updated README with new information.
---
README.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 1fe498e..d560104 100644
--- a/README.md
+++ b/README.md
@@ -327,7 +327,7 @@ One development goal of this framework is to remain as lightweight and unopinion
### Customized Help/Usage Messages
-This library has only one dependency, [@author.io/table](https://github.com/author/table). It is used to format the usage and help messages within a shell app. The `Table` library can be used to create your own custom screens, though most users will likely want to stick with the defaults.
+This library uses a vanilla dependency (i.e. no-subdependencies) called [@author.io/table](https://github.com/author/table) to format the usage and help messages of the shell. The `Table` library can be used to create your own custom screens, though most users will likely want to stick with the defaults. If you want to customize messages, the following example can be used as a starting point. The configuration options for the table can be found in the README of its repository.
_Example:_
@@ -344,7 +344,7 @@ shell.help = () => {
const table = new Table(rows)
- console.log(shell.usage + '\n' + table.output)
+ return shell.usage + '\n' + table.output
}
```
@@ -363,7 +363,7 @@ cmd.help = () => {
const table = new Table(rows)
- console.log(cmd.usage + '\n' + table.output)
+ return cmd.usage + '\n' + table.output
}
```
From 0a9168285d20266c26e57f21407cac46b9e56cad Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Thu, 23 Apr 2020 16:51:39 -0500
Subject: [PATCH 024/152] Abstracted base class functionality (reduced lib
size).
---
build/rollup.browser.config.js | 2 +-
build/rollup.node.config.js | 2 +-
build/rollup.test.browser.config.js | 2 +-
build/rollup.test.node.config.js | 2 +-
package-lock.json | 2 +-
package.json | 2 +-
src/base.js | 282 ++++++++++++++++++++++++++++
src/command.js | 275 ++++++---------------------
src/format.js | 13 +-
src/shell.js | 240 ++---------------------
test/unit/01-sanity/01-sanity.js | 8 +-
11 files changed, 378 insertions(+), 452 deletions(-)
create mode 100644 src/base.js
diff --git a/build/rollup.browser.config.js b/build/rollup.browser.config.js
index a2f1142..e89c50a 100644
--- a/build/rollup.browser.config.js
+++ b/build/rollup.browser.config.js
@@ -33,7 +33,7 @@ const globalplugins = [
]
// 2. Build Browser Production Package: Standard (Minified/Munged)
-const onwarn = build.ignoreCircularDependency('../src/command.js', '../src/shell.js', '../src/format.js')
+const onwarn = build.ignoreCircularDependency('../src/command.js', '../src/shell.js', '../src/format.js', '../src/base.js')
outdir += `/browser-${build.name}`
build.supportedBrowsers().forEach(edition => {
console.log(`Generating ${edition} browser code.`)
diff --git a/build/rollup.node.config.js b/build/rollup.node.config.js
index 533fa81..c1460cd 100644
--- a/build/rollup.node.config.js
+++ b/build/rollup.node.config.js
@@ -43,7 +43,7 @@ const plugins = [
]
// 2. Build Node Production Package: Standard (Minified/Munged)
-const onwarn = build.ignoreCircularDependency('../src/command.js', '../src/shell.js', '../src/format.js')
+const onwarn = build.ignoreCircularDependency('../src/command.js', '../src/shell.js', '../src/format.js', '../src/base.js')
outdir += `/node-${build.name}`
configuration.push({
input,
diff --git a/build/rollup.test.browser.config.js b/build/rollup.test.browser.config.js
index d42218c..5d0e73f 100644
--- a/build/rollup.test.browser.config.js
+++ b/build/rollup.test.browser.config.js
@@ -34,7 +34,7 @@ const globalplugins = [
]
// 2. Build Browser Production Package: Standard (Minified/Munged)
-const onwarn = build.ignoreCircularDependency('../src/command.js', '../src/shell.js', '../src/format.js')
+const onwarn = build.ignoreCircularDependency('../src/command.js', '../src/shell.js', '../src/format.js', '../src/base.js')
build.supportedBrowsers().forEach(edition => {
console.log(`Generating ${edition} browser code.`)
const plugins = globalplugins.slice()
diff --git a/build/rollup.test.node.config.js b/build/rollup.test.node.config.js
index 3fafdf7..2136e3f 100644
--- a/build/rollup.test.node.config.js
+++ b/build/rollup.test.node.config.js
@@ -43,7 +43,7 @@ const plugins = [
]
// 2. Build Node Production Package: Standard (Minified/Munged)
-const onwarn = build.ignoreCircularDependency('../src/command.js', '../src/shell.js', '../src/format.js')
+const onwarn = build.ignoreCircularDependency('../src/command.js', '../src/shell.js', '../src/format.js', '../src/base.js')
configuration.push({
input,
plugins,
diff --git a/package-lock.json b/package-lock.json
index 2c9d924..cc126f7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.1",
+ "version": "1.3.3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 88581c8..7d1c685 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.2",
+ "version": "1.3.3",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/base.js b/src/base.js
new file mode 100644
index 0000000..9eed44a
--- /dev/null
+++ b/src/base.js
@@ -0,0 +1,282 @@
+import Middleware from './middleware.js'
+import Formatter from './format.js'
+import Shell from './shell.js'
+import Command from './command.js'
+
+export default class Base {
+ #formattedDefaultHelp
+ #description
+ #customUsage
+ #customHelp
+ #extraOptions = new Set()
+ #autohelp = true
+ #processors = new Map()
+ #commands = new Map()
+ #width = 80
+ #name = 'Unknown'
+ #middleware = new Middleware()
+ #hasCustomDefaultHandler = false
+ #defaultHandler = data => console.log(this.help)
+
+ constructor(cfg = {}) {
+ if (typeof cfg !== 'object') {
+ throw new Error('Invalid command configuration. Expected an object.')
+ }
+
+ if (!cfg.hasOwnProperty('name')) {
+ throw new Error('Invalid command configuration. A "name" attribute is required.')
+ }
+
+ if (cfg.hasOwnProperty('help') && cfg.help !== this.help) {
+ this.#customHelp = cfg.help
+ }
+
+ if (cfg.hasOwnProperty('usage') && cfg.usage !== this.usage) {
+ this.#customUsage = cfg.usage
+ }
+
+ if (cfg.hasOwnProperty('autohelp')) {
+ this.#autohelp = cfg.autohelp
+ }
+
+ if (typeof cfg.help === 'function' || typeof cfg.help === 'string') {
+ this.help = cfg.help
+ }
+
+ if (typeof cfg.usage === 'function' || typeof cfg.usage === 'string') {
+ this.usage = cfg.usage
+ }
+
+ if (cfg.hasOwnProperty('defaultHandler') && cfg.defaultHandler.toString() !== this.#defaultHandler.toString()) {
+ this.defaultHandler = cfg.defaultHandler
+ }
+
+ if (typeof cfg.extraOptions === 'string') {
+ cfg.extraOptions = cfg.extraOptions.split(/\s+\,/)
+ }
+
+ if (Array.isArray(cfg.extraOptions)) {
+ this.#extraOptions = new Set([...cfg.extraOptions])
+ }
+
+ this.#defaultHandler = cfg.defaultHandler || this.#defaultHandler
+ this.#name = (cfg.name || 'unknown').trim().split(/\s+/)[0]
+ this.#description = cfg.description || null
+
+ if (Array.isArray(cfg.commands)) {
+ cfg.commands.forEach(cmd => this.add(cmd))
+ } else if (typeof cfg.commands === 'object') {
+ for (const key in cfg.commands) {
+ let data = cfg.commands[key]
+ data.name = key
+ this.add(data)
+ }
+ }
+
+ Object.defineProperties(this, {
+ __extraOptions: {
+ enumerable: true,
+ get() {
+ return this.#extraOptions
+ }
+ },
+ __processors: {
+ enumerable: true,
+ get() {
+ return this.#processors
+ }
+ },
+ __commands: {
+ enumerable: true,
+ get() {
+ return this.#commands
+ }
+ },
+ __width: {
+ enumerable: true,
+ get() {
+ return this.#width
+ },
+ set (v) {
+ this.#width = v || 80
+ }
+ }
+ })
+ }
+
+ get name () {
+ return this.#name || 'Unknown'
+ }
+
+ get description () {
+ return this.#description || this.usage || ''
+ }
+
+ get autohelp() {
+ return this.#autohelp
+ }
+
+ set autohelp (value) {
+ if (typeof value !== 'boolean') {
+ return
+ }
+ this.#autohelp = value
+ this.#processors.forEach(cmd => cmd.autohelp = value)
+ }
+
+ updateHelp () {
+ this.#formattedDefaultHelp = new Formatter(this)
+ this.#formattedDefaultHelp.width = this.#width
+ }
+
+ get usage() {
+ if (this.#customUsage !== null) {
+ return typeof this.#customUsage === 'function' ? this.#customUsage() : this.#customUsage
+ }
+
+ this.updateHelp()
+
+ return this.#formattedDefaultHelp.usage
+ }
+
+ set usage (value) {
+ if (typeof value === 'string' && value.trim().length === 0) {
+ this.#customUsage = null
+ }
+
+ this.#customUsage = value
+ }
+
+ get help () {
+ if (this.#customHelp) {
+ return typeof this.#customHelp === 'function' ? this.#customHelp(this) : this.#customHelp
+ }
+
+ this.updateHelp()
+
+ return this.#formattedDefaultHelp.help
+ }
+
+ set help (value) {
+ if (typeof value === 'string' && value.trim().length === 0) {
+ this.#customHelp = null
+ }
+
+ this.#customHelp = value
+ }
+
+ // @private
+ set defaultHandler (value) {
+ if (typeof value === 'function') {
+ this.#defaultHandler = value
+ this.#hasCustomDefaultHandler = true
+ this.#processors.forEach(cmd => cmd.defaultProcessor = value)
+ } else {
+ throw new Error(`Invalid default method (must be a function, not "${typeof value}").`)
+ }
+ }
+
+ get defaultHandler () {
+ return this.#defaultHandler
+ }
+
+ // @private
+ get hasCustomDefaultHandler () {
+ return this.#hasCustomDefaultHandler
+ }
+
+ get data () {
+ const commands = {}
+
+ Array.from(this.#processors.values()).forEach(cmd => {
+ let data = cmd.data
+ const name = data.name
+ delete data.name
+ commands[name] = data
+ })
+
+ return commands
+ }
+
+ getCommand(name = null) {
+ if (!name) {
+ return null
+ }
+
+ let names = name.split(/\s+/i)
+ let cmd = this.#commands.get(names.shift())
+ if (cmd) {
+ cmd = this.#processors.get(cmd)
+ for (const nm of names) {
+ cmd = cmd.getCommand(nm)
+ }
+ }
+
+ return cmd instanceof Command ? cmd : null
+ }
+
+ remove() {
+ for (const cmd of arguments) {
+ if (typeof cmd === 'symbol') {
+ this.#processors.delete(cmd)
+ this.#commands.forEach(oid => oid === cmd && this.#commands.delete(oid))
+ }
+
+ if (typeof cmd === 'string') {
+ const OID = this.#commands.get(cmd)
+ if (OID) {
+ this.remove(OID)
+ }
+ }
+ }
+ }
+
+ use() {
+ for (const arg of arguments) {
+ if (typeof arg !== 'function') {
+ throw new Error(`All "use()" arguments must be valid functions.\n${arg.toString().substring(0, 50)} ${arg.toString().length > 50 ? '...' : ''}`)
+ }
+
+ this.#middleware.use(arg)
+ }
+
+ this.__processors.forEach(subCmd => subCmd.use(...arguments))
+ }
+
+ get middleware () {
+ return this.#middleware
+ }
+
+ get commands() {
+ return this.__processors
+ }
+
+ add () {
+ for (let command of arguments) {
+ if (!(command instanceof Command)) {
+ if (typeof command === 'object') {
+ command = new Command(command)
+ } else {
+ throw new Error('Invalid argument. Only "Command" instances may be added to the processor.')
+ }
+ }
+
+ if (!command.hasCustomDefaultHandler) {
+ command.defaultHandler = this.defaultHandler
+ }
+
+ command.autohelp = this.autohelp
+
+ if (this instanceof Shell) {
+ command.shell = this
+ } else if (this instanceof Command) {
+ command.parent = this
+ }
+
+ this.#processors.set(command.OID, command)
+ this.#commands.set(command.name, command.OID)
+
+ command.aliases.forEach(alias => this.#commands.set(alias, command.OID))
+ }
+ }
+}
diff --git a/src/command.js b/src/command.js
index 0baebdf..a07a2d6 100644
--- a/src/command.js
+++ b/src/command.js
@@ -1,46 +1,22 @@
import { Parser } from '../node_modules/@author.io/arg/index.js'
-import Middleware from './middleware.js'
import Shell from './shell.js'
-import Formatter from './format.js'
+import Base from './base.js'
const STRIP_EQUAL_SIGNS = /(\=+)(?=([^'"\\]*(\\.|['"]([^'"\\]*\\.)*[^'"\\]*['"]))*[^'"]*$)/g
const SUBCOMMAND_PATTERN = /^([^"'][\S\b]+)[\s+]?([^-].*)$/i
const FLAG_PATTERN = /((?:"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|\/[^\/\\]*(?:\\[\S\s][^\/\\]*)*\/[gimy]*(?=\s|$)|(?:\\\s|\S))+)(?=\s|$)/g
const METHOD_PATTERN = /^([\w]+\s?)\(.*\)\s?{/i
-export default class Command {
- #formattedDefaultHelp
+export default class Command extends Base {
#pattern
#oid
- #name
- #description
#aliases = new Set()
- #customUsage
- #customHelp
#fn
#flagConfig = null
- #subcommands = new Map()
- #processors = new Map()
- #autohelp = true
#parent = null
#shell = null
- #middleware = new Middleware()
- #hasCustomDefaultHandler = false
- #defaultHandler = data => console.log(this.help)
- #updateHelp = () => {
- this.#formattedDefaultHelp = new Formatter(this)
- this.#formattedDefaultHelp.width = this.shell === null ? 80 : this.shell.tableWidth
- }
-
+
constructor (cfg = {}) {
- if (typeof cfg !== 'object') {
- throw new Error('Invalid command configuration. Expected an object.')
- }
-
- if (!cfg.hasOwnProperty('name')) {
- throw new Error('Invalid command configuration. A "name" attribute is required.')
- }
-
if (cfg.hasOwnProperty('handler')) {
if (typeof cfg.handler === 'string') {
cfg.handler = Function('return (' + cfg.handler.replace('function anonymous', 'function') + ').call(this)').call(globalThis)
@@ -49,29 +25,26 @@ export default class Command {
if (typeof cfg.handler !== 'function') {
throw new Error('Invalid command configuration. A "handler" function is required.')
}
-
- if (cfg.hasOwnProperty('help')) {
- this.help = cfg.help
- }
-
- if (cfg.hasOwnProperty('usage')) {
- this.usage = cfg.usage
- }
}
+ super(cfg)
+
if (cfg.hasOwnProperty('middleware') && Array.isArray(cfg.middleware)) {
cfg.middleware.forEach(code => this.use(Function(code)))
}
- this.#name = cfg.name.trim().split(/\s+/)[0]
+ // this.defaultHandler = (data, cb) => {
+ // if (data.help && data.help.requested) {
+ // console.log(data.help.message)
+ // }
+
+ // cb && cb(data)
+ // }
+
this.#fn = cfg.handler
this.#oid = Symbol(((cfg.name || cfg.usage) || cfg.pattern) || 'command')
this.#pattern = cfg.pattern || /[\s\S]+/i
- this.#customUsage = cfg.usage || null
- this.#customHelp = cfg.help || null
- // this.aliases = cfg.aliases
- this.#description = cfg.description || null
-
+
if (cfg.alias && !cfg.aliases) {
cfg.aliases = Array.isArray(cfg.alias) ? cfg.alias : [cfg.alias]
delete cfg.alias
@@ -112,20 +85,8 @@ export default class Command {
this.#flagConfig = cfg.flags
}
- if (typeof cfg.autohelp === 'boolean') {
- this.#autohelp = cfg.autohelp
- }
-
- if (typeof cfg.defaultHandler === 'function') {
- this.defaultHandler = cfg.defaultHandler
- }
-
- if (Array.isArray(cfg.commands)) {
- cfg.commands.forEach(cmd => this.add(cmd))
- }
-
if (Array.isArray(cfg.subcommands)) {
- cfg.subcommands.forEach(cmd => this.add(cmd))
+ this.add(...cfg.subcommands)
}
const attributes = new Set([
@@ -142,7 +103,8 @@ export default class Command {
'pattern',
'name',
'handler',
- 'middleware'
+ 'middleware',
+ 'extraOptions'
])
const unrecognized = Object.keys(cfg).filter(attribute => !attributes.has(attribute))
@@ -156,27 +118,25 @@ export default class Command {
enumerable: false,
get () {
const flags = new Map()
- Object.keys(this.#flagConfig).forEach(key => flags.set(key, this.#flagConfig[key]))
- flags.delete('help')
+ if (this.#flagConfig !== null) {
+ Object.keys(this.#flagConfig).forEach(key => flags.set(key, this.#flagConfig[key]))
+ flags.delete('help')
+ }
+
return flags
}
}
})
- this.#updateHelp()
+ this.__width = this.shell === null ? 80 : this.shell.tableWidth || 80
+
+ this.updateHelp()
}
get data () {
- const commands = {}
-
- Array.from(this.#processors.values()).forEach(cmd => {
- let data = cmd.data
- const name = data.name
- delete data.name
- commands[name] = data
- })
+ const commands = super.data
- let handler = (this.#fn || this.#defaultHandler).toString()
+ let handler = (this.#fn || this.defaultHandler).toString()
if (METHOD_PATTERN.test(handler)) {
handler = handler.replace(METHOD_PATTERN.exec(handler)[1], 'function ')
}
@@ -196,7 +156,7 @@ export default class Command {
}
const data = {
- name: this.#name,
+ name: this.name,
description: this.description,
help: this.help,
usage: this.usage,
@@ -204,7 +164,7 @@ export default class Command {
flags,
handler,
commands,
- middleware: this.#middleware.data
+ middleware: this.middleware.data
}
for (let [key, value] of Object.entries(data.flags)) {
@@ -214,22 +174,6 @@ export default class Command {
return data
}
- // @private
- set defaultHandler (value) {
- if (typeof value === 'function') {
- this.#defaultHandler = value
- this.#hasCustomDefaultHandler = true
- this.#processors.forEach(cmd => cmd.defaultProcessor = value)
- } else {
- throw new Error(`Invalid default method (must be a function, not ${typeof cfg.defaultHandler}).`)
- }
- }
-
- // @private
- get hasCustomDefaultHandler () {
- return this.#hasCustomDefaultHandler
- }
-
set parent (cmd) {
if (cmd instanceof Command) {
this.#parent = cmd
@@ -244,6 +188,7 @@ export default class Command {
}
if (shell instanceof Shell) {
this.#shell = shell
+ this.__width = this.shell === null ? 80 : shell.tableWidth
} else {
throw new Error(`Expected a Shell object, received a "${typeof shell}" object.`)
}
@@ -261,68 +206,16 @@ export default class Command {
return this.#shell
}
- get autohelp() {
- return this.#autohelp
- }
-
- set autohelp(value) {
- if (typeof value !== 'boolean') {
- return
- }
- this.#autohelp = value
- this.#processors.forEach(cmd => cmd.autohelp = value)
- }
-
- get subcommands () {
- return this.#processors
- }
-
- get name () {
- return this.#name
- }
-
- get description () {
- return this.#description || ''
- }
-
get commandroot () {
if (this.#parent) {
- return `${this.#parent.commandroot} ${this.#name}`.trim()
+ return `${this.#parent.commandroot} ${this.name}`.trim()
}
if (this.#shell) {
- return `${this.#shell.name} ${this.#name}`.trim()
+ return `${this.#shell.name} ${this.name}`.trim()
}
- return this.#name
- }
-
- get usage () {
- if (this.#customUsage !== null) {
- return typeof this.#customUsage === 'function' ? this.#customUsage() : this.#customUsage
- }
-
- this.#updateHelp()
-
- return this.#formattedDefaultHelp.usage
- }
-
- set usage (value) {
- this.#customUsage = value
- }
-
- get help () {
- if (this.#customHelp) {
- return typeof this.#customHelp === 'function' ? this.#customHelp() : this.#customHelp
- }
-
- this.#updateHelp()
-
- return this.#formattedDefaultHelp.help
- }
-
- set help (value) {
- this.#customHelp = value
+ return this.name
}
set aliases (value) {
@@ -363,10 +256,6 @@ export default class Command {
return this.#oid
}
- getCommand (name) {
- return this.#subcommands.get(name)
- }
-
addFlag (name, cfg) {
if (typeof name !== 'string') {
if (!cfg.hasOwnProperty('name')) {
@@ -388,56 +277,10 @@ export default class Command {
return this.#flagConfig.hasOwnProperty(name)
}
- add (command) {
- if (!(command instanceof Command)) {
- if (typeof command === 'object') {
- command = new Command(command)
- } else {
- throw new Error('Invalid argument. Only "Command" instances may be added to the processor.')
- }
- }
-
- command.parent = this
- command.autohelp = this.#autohelp
-
- this.#processors.set(command.OID, command)
- this.#subcommands.set(command.name, command.OID)
-
- command.aliases.forEach(alias => this.#subcommands.set(alias, command.OID))
- }
-
- remove () {
- for (const cmd of arguments) {
- if (typeof cmd === 'symbol') {
- this.#processors.delete(cmd)
- this.#subcommands.forEach(oid => oid === cmd && this.#subcommands.delete(oid))
- }
-
- if (typeof cmd === 'string') {
- const OID = this.#subcommands.get(cmd)
- if (OID) {
- this.remove(OID)
- }
- }
- }
- }
-
- use () {
- for (const arg of arguments) {
- if (typeof arg !== 'function') {
- throw new Error(`All "use()" arguments must be valid functions.\n${ arg.toString().substring(0, 50) } ${ arg.toString().length > 50 ? '...' : '' }`)
- }
-
- this.#middleware.use(arg)
- }
-
- this.#processors.forEach(subCmd => subCmd.use(...arguments))
- }
-
deepParse (input) {
let meta = this.parse(input)
- if (this.#subcommands.size === 0) {
+ if (this.__commands.size === 0) {
return meta
}
@@ -446,24 +289,24 @@ export default class Command {
}
let args = meta.input.split(/\s+/)
- let subcmd = this.#subcommands.get(args.shift())
+ let subcmd = this.__commands.get(args.shift())
if (!subcmd) {
return meta
}
- return this.#processors.get(subcmd).deepParse(args.join(' '))
+ return this.__processors.get(subcmd).deepParse(args.join(' '))
}
parse (input) {
// Parse the command input for flags
- const data = { command: this.#name, input: input.trim() }
+ const data = { command: this.name, input: input.trim() }
let flagConfig = this.#flagConfig || {}
if (!flagConfig.hasOwnProperty('help')) {
flagConfig.help = {
- description: `Display ${ this.#name } help.`,
+ description: `Display ${ this.name } help.`,
aliases: ['h'],
default: false,
type: 'boolean'
@@ -481,7 +324,7 @@ export default class Command {
data.flags = { recognized, unrecognized: parser.unrecognizedFlags }
data.valid = parser.valid
data.violations = parser.violations
-
+
data.parsed = {}
if (Object.keys(parser.data.flagSource).length > 0) {
for (const [key, src] of Object.entries(parser.data.flagSource)) {
@@ -529,22 +372,22 @@ export default class Command {
}
async run (input, callback) {
- let fn = (this.#fn || this.#defaultHandler).bind(this)
+ let fn = (this.#fn || this.defaultHandler).bind(this)
let data = typeof input === 'string' ? this.parse(input) : input
const parsed = SUBCOMMAND_PATTERN.exec(input)
arguments[0] = this.deepParse(input)
-
+
// A possible subcommand was input
if (parsed) {
let cmd = parsed[1]
let args = parsed.length > 2 ? parsed[2] : ''
let command = null
- let subcommand = this.#subcommands.get(cmd)
+ let subcommand = this.__commands.get(cmd)
if (!subcommand) {
- for (const [name, id] of this.#subcommands) {
- const subcmd = this.#processors.get(id)
+ for (const [name, id] of this.__commands) {
+ const subcmd = this.__processors.get(id)
if (subcmd.aliases.indexOf(cmd)) {
subcommand = subcmd
@@ -557,13 +400,13 @@ export default class Command {
if (!subcommand) {
return await (new Promise((resolve, reject) => {
try {
- if (this.#autohelp && data.help.requested) {
- console.log(this.help)
+ if (this.autohelp && data.help.requested) {
+ console.log(this.help)
resolve()
} else {
try {
- this.#middleware.use(fn)
- resolve(() => this.#middleware.run(data, () => callback && callback()))
+ this.middleware.use(fn)
+ resolve(() => this.middleware.run(data, () => callback && callback()))
} catch (ee) {
reject(ee)
}
@@ -573,10 +416,10 @@ export default class Command {
}
}))
}
-
- const processor = this.#processors.get(subcommand)
-
- if (this.#autohelp) {
+ console.log(4)
+ const processor = this.__processors.get(subcommand)
+ console.log(5)
+ if (this.autohelp) {
if (data.help.requested) {
if (processor) {
return console.log(processor.help)
@@ -587,21 +430,21 @@ export default class Command {
}
if (!processor) {
- return new Promise((resolve, reject) => reject(new Error(`${ this.#name } "${cmd}" command not found.`)))
+ return new Promise((resolve, reject) => reject(new Error(`${ this.name } "${cmd}" command not found.`)))
}
- if (this.#middleware.size > 0) {
- this.#middleware.use(async meta => await Command.reply(fn(meta, callback)))
- return this.#middleware.run(...arguments, () => {})
+ if (this.middleware.size > 0) {
+ this.middleware.use(async meta => await Command.reply(fn(meta, callback)))
+ return this.middleware.run(...arguments, () => {})
}
return Command.reply(await processor.run(args, callback()))
}
// No subcommand was recognized
- if (this.#middleware.size > 0) {
- this.#middleware.use(async meta => await Command.reply(fn(meta, callback)))
- return this.#middleware.run(...arguments, () => {})
+ if (this.middleware.size > 0) {
+ this.middleware.use(async meta => await Command.reply(fn(meta, callback)))
+ return this.middleware.run(...arguments, () => {})
}
return Command.reply(fn(data, callback))
diff --git a/src/format.js b/src/format.js
index a84881d..b75bb9b 100644
--- a/src/format.js
+++ b/src/format.js
@@ -25,10 +25,11 @@ class Formatter {
}
get usage () {
+ const desc = this.#data.description.trim()
+
if (this.#data instanceof Command) {
const aliases = this.#data.aliases
- const out = [`${this.#data.commandroot}${aliases.length > 0 ? ' <' + aliases.join(', ') + '>' : ''}${this.#data.__flagConfig.size > 0 ? ' [OPTIONS]' : ''}`]
- const desc = this.#data.description.trim()
+ const out = [`${this.#data.commandroot}${aliases.length > 0 ? ' <' + aliases.join(', ') + '>' : ''}${this.#data.__flagConfig.size > 0 ? ' [OPTIONS]' : ''}${this.#data.__extraOptions.size > 0 ? ' ' + Array.from(this.#data.__extraOptions).join(', ') : ''}`]
if (desc.trim().length > 0 && out !== desc) {
out.push(new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output)
@@ -36,7 +37,7 @@ class Formatter {
return out.join('\n')
} else if (this.#data instanceof Shell) {
- return `${this.#data.name}${this.#data.description.trim().length > 0 ? new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output : ''}${this.#data.__commandMap.size > 0 ? ' [COMMAND]' : ''}\n\n ${this.#data.description || ''} Version ${this.#data.version}.\n`.trim()
+ return `${this.#data.name}${desc.trim().length > 0 ? new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output : ''}${this.#data.__processors.size > 0 ? ' [COMMAND]' : ''}${this.#data.__extraOptions.size > 0 ? ' ' + Array.from(this.#data.__extraOptions).join(', ') : ''}\n\n ${this.#data.description || ''} Version ${this.#data.version}.\n`.trim()
}
return ''
@@ -56,12 +57,12 @@ class Formatter {
rows.push(['-' + flag, aliases, cfg.description])
})
}
-
+
const table = new Table(rows, this.#colAlign, this.#colWidth, this.#tableWidth, [2, 0, usage.length > 0 ? 1 : 0, 0])
-
+
return usage + '\n\nOptions:' + table.output
} else if (this.#data instanceof Shell) {
- const rows = Array.from(this.#data.__commandMap.values()).map(cmd => {
+ const rows = Array.from(this.#data.__processors.values()).map(cmd => {
return [cmd.name, (cmd.aliases||[]).length > 0 ? `[${cmd.aliases.join(', ').trim()}]` : '', cmd.description]
})
diff --git a/src/shell.js b/src/shell.js
index 5186a15..5f8c695 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -1,27 +1,15 @@
import Command from './command.js'
-import Middleware from './middleware.js'
-import Formatter from './format.js'
+import Base from './base.js'
const COMMAND_PATTERN = /^(\w+)\s+([\s\S]+)?/i
-export default class Shell {
- #formattedDefaultHelp
- #processors = new Map()
- #commands = new Map()
- #middleware = new Middleware()
+export default class Shell extends Base {
#middlewareGroups = new Map()
#history = []
#maxHistoryItems
- #name
- #description
#version
- #customHelp = null
- #customUsage = null
#cursor = 0
- #autohelp = true
#tabWidth
- #tableWidth
- #hasCustomDefaultHandler = false
#runtime = globalThis.hasOwnProperty('window')
? 'browser'
: (
@@ -31,85 +19,32 @@ export default class Shell {
? globalThis.process.release.name
: 'unknown'
)
- #defaultHandler = (data, cb) => {
- if (data.help && data.help.requested) {
- console.log(data.help.message)
- }
-
- cb && cb(data)
- }
- #updateHelp = () => {
- this.#formattedDefaultHelp = new Formatter(this)
- this.#formattedDefaultHelp.width = this.#tableWidth
- }
-
+
constructor (cfg = { maxhistory: 100 }) {
- this.#name = cfg.name || 'unknown'
- this.#description = cfg.description || null
- this.#version = cfg.version || '1.0.0'
- this.#maxHistoryItems = cfg.maxhistory || cfg.maxHistoryItems || 100
-
- this.#tabWidth = cfg.hasOwnProperty('tabWidth') ? cfg.tabWidth : 4
- this.#tableWidth = cfg.hasOwnProperty('tableWidth') ? cfg.tableWidth : 70
-
- if (cfg.hasOwnProperty('autohelp')) {
- this.#autohelp = cfg.autohelp
- }
-
- if (cfg.hasOwnProperty('defaultHandler') && cfg.defaultHandler.toString() !== this.#defaultHandler.toString()) {
- this.defaultHandler = cfg.defaultHandler
- }
-
- if (Array.isArray(cfg.commands)) {
- cfg.commands.forEach(cmd => this.add(cmd))
- } else if (typeof cfg.commands === 'object') {
- for (const key in cfg.commands) {
- let data = cfg.commands[key]
- data.name = key
- this.add(data)
- }
- }
+ super(cfg)
if (cfg.hasOwnProperty('middleware') && Array.isArray(cfg.middleware)) {
cfg.middleware.forEach(code => this.use(Function('return ' + code)()))
}
- if (cfg.hasOwnProperty('help') && cfg.help !== this.help) {
- this.#customHelp = cfg.help
- }
-
- if (cfg.hasOwnProperty('usage') && cfg.usage !== this.usage) {
- this.#customUsage = cfg.usage
- }
-
- Object.defineProperty(this, '__commandMap', {
- enumerable: false,
- get () {
- return this.#processors
- }
- })
+ this.#version = cfg.version || '1.0.0'
+ this.#maxHistoryItems = cfg.maxhistory || cfg.maxHistoryItems || 100
+ this.#tabWidth = cfg.hasOwnProperty('tabWidth') ? cfg.tabWidth : 4
}
get data () {
- const commands = {}
-
- Array.from(this.#processors.values()).forEach(cmd => {
- let data = cmd.data
- const name = data.name
- delete data.name
- commands[name] = data
- })
+ const commands = super.data
return {
name: this.name,
description: this.description,
version: this.version,
commands,
- middleware: this.#middleware.data,
+ middleware: this.middleware.data,
help: this.help,
usage: this.usage,
- defaultHandler: this.#defaultHandler.toString(),
- authohelp: this.#autohelp,
+ defaultHandler: this.defaultHandler.toString(),
+ authohelp: this.autohelp,
runtime: this.#runtime,
maxHistoryItems: this.#maxHistoryItems
}
@@ -119,84 +54,12 @@ export default class Shell {
return this.#version || 'Unknown'
}
- get name () {
- return this.#name || 'Unknown'
- }
-
- get description () {
- return this.#description || ''
- }
-
set tableWidth(value) {
- this.#tableWidth = value
+ this.__width = value
}
get tableWidth () {
- return this.#tableWidth || 80
- }
-
- get autohelp () {
- return this.#autohelp
- }
-
- // @private
- set defaultHandler(value) {
- if (typeof value === 'function') {
- this.#defaultHandler = value
- this.#hasCustomDefaultHandler = true
- this.#processors.forEach(cmd => cmd.defaultProcessor = value)
- } else {
- throw new Error(`Invalid default method (must be a function, not ${typeof cfg.defaultHandler}).`)
- }
- }
-
- // @private
- get hasCustomDefaultHandler() {
- return this.#hasCustomDefaultHandler
- }
-
- set autohelp (value) {
- if (typeof value !== 'boolean') {
- return
- }
- this.#autohelp = value
- this.#commands.forEach(cmd => cmd.autohelp = value)
- }
-
- get name () {
- return this.#name
- }
-
- get description () {
- return this.#description || this.usage
- }
-
- get usage () {
- if (this.#customUsage !== null) {
- return typeof this.#customUsage === 'function' ? this.#customUsage() : this.#customUsage
- }
-
- this.#updateHelp()
-
- return this.#formattedDefaultHelp.usage
- }
-
- set usage (value) {
- this.#customUsage = value
- }
-
- get help () {
- if (this.#customHelp) {
- return typeof this.#customHelp === 'function' ? this.#customHelp(this) : this.#customHelp
- }
-
- this.#updateHelp()
-
- return this.#formattedDefaultHelp.help
- }
-
- set help (value) {
- this.#customHelp = value
+ return this.__width
}
history (count = null) {
@@ -234,57 +97,6 @@ export default class Shell {
return this.#history[this.#cursor]
}
- add () {
- for (let command of arguments) {
- if (typeof command === 'object' && !(command instanceof Command)) {
- command = new Command(command)
- }
-
- if (!(command instanceof Command)) {
- throw new Error('Invalid argument. Only "Command" instances may be added to the processor.')
- }
-
- if (!command.hasCustomDefaultHandler) {
- command.defaultHandler = this.#defaultHandler
- }
-
- command.autohelp = this.#autohelp
- command.shell = this
-
- this.#processors.set(command.OID, command)
- this.#commands.set(command.name, command.OID)
-
- command.aliases.forEach(alias => this.#commands.set(alias, command.OID))
- }
- }
-
- getCommand (name=null) {
- if (!name) {
- return null
- }
-
- let names = name.split(/\s+/i)
- let cmd = this.#commands.get(names.shift())
- if (cmd) {
- cmd = this.#processors.get(cmd)
- for (const nm of names) {
- cmd = cmd.getCommand(nm)
- }
- }
-
- return cmd instanceof Command ? cmd : null
- }
-
- use () {
- for (const arg of arguments) {
- if (typeof arg !== 'function') {
- throw new Error(`All "use()" arguments must be valid functions.\n${arg.toString().substring(0,50)}${arg.toString().length > 50 ? '...' : ''}`)
- }
-
- this.#middleware.use(arg)
- }
- }
-
useWith (commands) {
if (arguments.length < 2) {
throw new Error('useWith([\'command\', \'command\'], fn) requires two or more arguments.')
@@ -301,22 +113,6 @@ export default class Shell {
commands.forEach(cmd => this.#middlewareGroups.set(cmd, (this.#middlewareGroups.get(cmd) || []).concat(fns)))
}
- remove () {
- for (const cmd of arguments) {
- if (typeof cmd === 'symbol') {
- this.#processors.delete(cmd)
- this.#commands.forEach(oid => oid === cmd && this.#commands.delete(oid))
- }
-
- if (typeof cmd === 'string') {
- const OID = this.#commands.get(cmd)
- if (OID) {
- this.remove(OID)
- }
- }
- }
- }
-
async exec (input, callback) {
this.#history.shift({ input, time: new Date().toLocaleString()})
@@ -336,20 +132,20 @@ export default class Shell {
let args = parsed.length > 2 ? parsed[2] : ''
let command = null
- const action = this.#commands.get(cmd)
+ const action = this.__commands.get(cmd)
if (!action) {
return Command.stderr(this.help)
}
- const processor = this.#processors.get(action)
+ const processor = this.__processors.get(action)
if (!processor) {
return Command.stderr('Command not found.')
}
// Apply command-specific middleware (configured via useWith)
- processor.commandroot.replace(new RegExp('^' + this.#name, 'i'), '')
+ processor.commandroot.replace(new RegExp('^' + this.name, 'i'), '')
.trim()
.split(/\s+/)
.reduce((cmdpath, name) => {
@@ -360,13 +156,13 @@ export default class Shell {
}
}, [])
- if (this.#middleware.size === 0) {
+ if (this.middleware.size === 0) {
return await Command.reply(await processor.run(args, callback))
}
arguments[0] = processor.deepParse(args)
- return this.#middleware.run(
+ return this.middleware.run(
...arguments,
async () => await Command.reply(await processor.run(args)))
}
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index a8c1683..b2e1912 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -23,7 +23,7 @@ test('Sanity Check - Command', t => {
cb && cb()
}
})
- console.log('>>', mirror.xdata)
+
t.ok(mirror instanceof Command, 'Command initialized successfully.')
const CLI = new Shell({
@@ -43,7 +43,11 @@ test('Sanity Check - Command', t => {
CLI.exec('test').then(data => {
t.pass('Default handler fires.')
t.end()
- }).catch(e => t.fail(e.message))
+ }).catch(e => {
+ console.log(e)
+ t.fail(e.message)
+ t.end()
+ })
})
test('Output Formatting', t => {
From bfdad357d8b47fa867d0acb630aa072db7316faa Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Thu, 23 Apr 2020 21:36:44 -0500
Subject: [PATCH 025/152] Fixed command usage content for help messages. Added
a default 'version' command. Updated README to reflect these changes.
---
README.md | 42 ++++++++++++++++++++++++++++++++++++++++++
package-lock.json | 2 +-
package.json | 2 +-
src/format.js | 2 +-
src/shell.js | 8 ++++++++
5 files changed, 53 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index d560104..5048c2d 100644
--- a/README.md
+++ b/README.md
@@ -87,6 +87,8 @@ import { Shell, Command } from '@author.io/node-shell'
const ListCommand = new Command({
name: 'list',
description: 'List the contents of the directory.',
+ // extraOptions are listed after the command in the default help screen. Ex: "dir list "
+ extraOptions: '',
alias: 'ls',
// Any flag parsing options from the @author.io/arg library can be configured here.
// See https://github.com/author/arg#configuration-methods for a list.
@@ -319,6 +321,46 @@ cmd.use(function (metadata, next) {
})
```
+### Built-in "Middleware"
+
+Displaying help and version information is built-in (overridable).
+
+**Help**
+
+Appending `--help` to anything will display the help content for the shell/command/subcommand. This will respect any custom usage/help configurations that may be defined.
+
+**Shell Version**
+
+A `version` command is available on the shell. For example:
+
+```sh
+$ cmd version
+1.0.0
+```
+
+The following common flag variations map to the version command, producing the same output:
+
+```sh
+$ cmd --version
+1.0.0
+
+$ cmd -v
+1.0.0
+```
+
+This can be overridden by creating a command called `version`, the same way any other command is created.
+
+```javascript
+const v = new Command({
+ name: 'version',
+ handler (meta) {
+ console.log(this.shell.version)
+ }
+})
+
+shell.add(v)
+```
+
### Other Middleware
One development goal of this framework is to remain as lightweight and unopinionated as possible. Another is to be as simple to use as possible. These two goals often conflict with each other (the more features you add, the heavier it becomes). In an attempt to find a comfortable balance, some additional middleware libraries are available for those who want a little extra functionality.
diff --git a/package-lock.json b/package-lock.json
index cc126f7..32e852b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.3",
+ "version": "1.3.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 7d1c685..e5e63d7 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.3",
+ "version": "1.3.4",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/format.js b/src/format.js
index b75bb9b..67f3cc3 100644
--- a/src/format.js
+++ b/src/format.js
@@ -37,7 +37,7 @@ class Formatter {
return out.join('\n')
} else if (this.#data instanceof Shell) {
- return `${this.#data.name}${desc.trim().length > 0 ? new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output : ''}${this.#data.__processors.size > 0 ? ' [COMMAND]' : ''}${this.#data.__extraOptions.size > 0 ? ' ' + Array.from(this.#data.__extraOptions).join(', ') : ''}\n\n ${this.#data.description || ''} Version ${this.#data.version}.\n`.trim()
+ return `${this.#data.name}${this.#data.__processors.size > 0 ? ' [COMMAND]' : ''}\n${desc.trim().length > 0 ? new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output : ''}${this.#data.__extraOptions.size > 0 ? ' ' + Array.from(this.#data.__extraOptions).join(', ') : ''}\n`.trim()
}
return ''
diff --git a/src/shell.js b/src/shell.js
index 5f8c695..3a0669b 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -123,6 +123,10 @@ export default class Shell extends Base {
let parsed = COMMAND_PATTERN.exec(input + ' ')
if (parsed === null) {
+ if (input.indexOf('version') !== -1 || input.indexOf('-v') !== -1) {
+ return console.log(this.version)
+ }
+
return Command.stderr(this.help)
}
@@ -135,6 +139,10 @@ export default class Shell extends Base {
const action = this.__commands.get(cmd)
if (!action) {
+ if (cmd.toLowerCase() === 'version') {
+ return console.log(this.version)
+ }
+
return Command.stderr(this.help)
}
From ea9d615e531f4d3c4ea8e8a45ecda9663423a043 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Thu, 23 Apr 2020 22:58:08 -0500
Subject: [PATCH 026/152] Updated dependencies, version bump.
---
package-lock.json | 2 +-
package.json | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 32e852b..752e675 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.4",
+ "version": "1.3.5",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index e5e63d7..fef1cc1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.4",
+ "version": "1.3.5",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
@@ -51,6 +51,6 @@
},
"dependencies": {
"@author.io/arg": "^1.2.5",
- "@author.io/table": "^1.0.0"
+ "@author.io/table": "^1.0.1"
}
}
From 1333c7be92f822ebddf1f842b5e3d4014a5dcb9a Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sun, 26 Apr 2020 16:35:52 -0500
Subject: [PATCH 027/152] Updated arg dependency. Now supports quoted flag
values.
---
package-lock.json | 2 +-
package.json | 7 ++++---
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 752e675..e7d6060 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.5",
+ "version": "1.3.6",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index fef1cc1..c4a5f07 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.5",
+ "version": "1.3.6",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
@@ -46,11 +46,12 @@
],
"globals": [
"window",
- "global"
+ "global",
+ "globalThis"
]
},
"dependencies": {
- "@author.io/arg": "^1.2.5",
+ "@author.io/arg": "^1.2.6",
"@author.io/table": "^1.0.1"
}
}
From d3e3075e7dcafe593e069051647a4d6e6b8bce04 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sun, 26 Apr 2020 17:37:07 -0500
Subject: [PATCH 028/152] Added support for flag method to return an
unrecognized flag value by its index number.
---
package-lock.json | 2 +-
package.json | 2 +-
src/command.js | 15 ++++++++++-----
3 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index e7d6060..8ae3ae1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.6",
+ "version": "1.3.7",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index c4a5f07..41c894e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.6",
+ "version": "1.3.7",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/command.js b/src/command.js
index a07a2d6..95a4c36 100644
--- a/src/command.js
+++ b/src/command.js
@@ -2,7 +2,7 @@ import { Parser } from '../node_modules/@author.io/arg/index.js'
import Shell from './shell.js'
import Base from './base.js'
-const STRIP_EQUAL_SIGNS = /(\=+)(?=([^'"\\]*(\\.|['"]([^'"\\]*\\.)*[^'"\\]*['"]))*[^'"]*$)/g
+// const STRIP_EQUAL_SIGNS = /(\=+)(?=([^'"\\]*(\\.|['"]([^'"\\]*\\.)*[^'"\\]*['"]))*[^'"]*$)/g
const SUBCOMMAND_PATTERN = /^([^"'][\S\b]+)[\s+]?([^-].*)$/i
const FLAG_PATTERN = /((?:"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|\/[^\/\\]*(?:\\[\S\s][^\/\\]*)*\/[gimy]*(?=\s|$)|(?:\\\s|\S))+)(?=\s|$)/g
const METHOD_PATTERN = /^([\w]+\s?)\(.*\)\s?{/i
@@ -307,14 +307,15 @@ export default class Command extends Base {
if (!flagConfig.hasOwnProperty('help')) {
flagConfig.help = {
description: `Display ${ this.name } help.`,
- aliases: ['h'],
+ // aliases: ['h'],
default: false,
type: 'boolean'
}
}
- let source = input.replace(STRIP_EQUAL_SIGNS, '').trim() + ' '
- const flags = Array.from(FLAG_PATTERN[Symbol.matchAll](source), x => x[0])
+ // let source = input.replace(STRIP_EQUAL_SIGNS, '').trim() + ' '
+
+ const flags = Array.from(FLAG_PATTERN[Symbol.matchAll](input), x => x[0])
const parser = new Parser(flags, flagConfig)
let recognized = parser.data
@@ -347,7 +348,11 @@ export default class Command extends Base {
writable: false,
value: name => {
try {
- return parser.data.flagSource[name].value
+ if (typeof name === 'number') {
+ return Array.from(parser.unrecognizedFlags)[name]
+ } else {
+ return parser.data.flagSource[name].value
+ }
} catch (e) {
return undefined
}
From f9393311ab6496af07a4a2bb9f08d01fa7642b90 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 29 Apr 2020 17:15:19 -0500
Subject: [PATCH 029/152] Updated syntax of output to be consistent with
brackets. Renamed extraOptions parameter to arguments to be more consistent
with what it actually represents. Version bump.
---
README.md | 4 ++--
package-lock.json | 2 +-
package.json | 2 +-
src/base.js | 14 +++++++-------
src/command.js | 8 ++++----
src/format.js | 12 +++++++-----
6 files changed, 22 insertions(+), 20 deletions(-)
diff --git a/README.md b/README.md
index 5048c2d..44211a8 100644
--- a/README.md
+++ b/README.md
@@ -87,8 +87,8 @@ import { Shell, Command } from '@author.io/node-shell'
const ListCommand = new Command({
name: 'list',
description: 'List the contents of the directory.',
- // extraOptions are listed after the command in the default help screen. Ex: "dir list "
- extraOptions: '',
+ // arguments are listed after the command in the default help screen. Ex: "dir list "
+ arguments: '',
alias: 'ls',
// Any flag parsing options from the @author.io/arg library can be configured here.
// See https://github.com/author/arg#configuration-methods for a list.
diff --git a/package-lock.json b/package-lock.json
index 8ae3ae1..1197591 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.7",
+ "version": "1.3.8",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 41c894e..4fe244c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.7",
+ "version": "1.3.8",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/base.js b/src/base.js
index 9eed44a..4aa6d4d 100644
--- a/src/base.js
+++ b/src/base.js
@@ -8,7 +8,7 @@ export default class Base {
#description
#customUsage
#customHelp
- #extraOptions = new Set()
+ #arguments = new Set()
#autohelp = true
#processors = new Map()
#commands = new Map()
@@ -51,12 +51,12 @@ export default class Base {
this.defaultHandler = cfg.defaultHandler
}
- if (typeof cfg.extraOptions === 'string') {
- cfg.extraOptions = cfg.extraOptions.split(/\s+\,/)
+ if (typeof cfg.arguments === 'string') {
+ cfg.arguments = cfg.arguments.split(/\s+\,/)
}
- if (Array.isArray(cfg.extraOptions)) {
- this.#extraOptions = new Set([...cfg.extraOptions])
+ if (Array.isArray(cfg.arguments)) {
+ this.#arguments = new Set([...cfg.arguments])
}
this.#defaultHandler = cfg.defaultHandler || this.#defaultHandler
@@ -74,10 +74,10 @@ export default class Base {
}
Object.defineProperties(this, {
- __extraOptions: {
+ __arguments: {
enumerable: true,
get() {
- return this.#extraOptions
+ return this.#arguments
}
},
__processors: {
diff --git a/src/command.js b/src/command.js
index 95a4c36..e56da3d 100644
--- a/src/command.js
+++ b/src/command.js
@@ -104,7 +104,7 @@ export default class Command extends Base {
'name',
'handler',
'middleware',
- 'extraOptions'
+ 'arguments'
])
const unrecognized = Object.keys(cfg).filter(attribute => !attributes.has(attribute))
@@ -421,9 +421,9 @@ export default class Command extends Base {
}
}))
}
- console.log(4)
+
const processor = this.__processors.get(subcommand)
- console.log(5)
+
if (this.autohelp) {
if (data.help.requested) {
if (processor) {
@@ -443,7 +443,7 @@ export default class Command extends Base {
return this.middleware.run(...arguments, () => {})
}
- return Command.reply(await processor.run(args, callback()))
+ return Command.reply(await processor.run(args, callback))
}
// No subcommand was recognized
diff --git a/src/format.js b/src/format.js
index 67f3cc3..4d0332c 100644
--- a/src/format.js
+++ b/src/format.js
@@ -29,7 +29,7 @@ class Formatter {
if (this.#data instanceof Command) {
const aliases = this.#data.aliases
- const out = [`${this.#data.commandroot}${aliases.length > 0 ? ' <' + aliases.join(', ') + '>' : ''}${this.#data.__flagConfig.size > 0 ? ' [OPTIONS]' : ''}${this.#data.__extraOptions.size > 0 ? ' ' + Array.from(this.#data.__extraOptions).join(', ') : ''}`]
+ const out = [`${this.#data.commandroot}${aliases.length > 0 ? '|' + aliases.join('|') : ''}${this.#data.__flagConfig.size > 0 ? ' [FLAGS]' : ''}${this.#data.__arguments.size > 0 ? ' ' + Array.from(this.#data.__arguments).join(', ') : ''}`]
if (desc.trim().length > 0 && out !== desc) {
out.push(new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output)
@@ -37,7 +37,7 @@ class Formatter {
return out.join('\n')
} else if (this.#data instanceof Shell) {
- return `${this.#data.name}${this.#data.__processors.size > 0 ? ' [COMMAND]' : ''}\n${desc.trim().length > 0 ? new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output : ''}${this.#data.__extraOptions.size > 0 ? ' ' + Array.from(this.#data.__extraOptions).join(', ') : ''}\n`.trim()
+ return `${this.#data.name}${this.#data.__processors.size > 0 ? ' [COMMAND]' : ''}\n${desc.trim().length > 0 ? new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output : ''}${this.#data.__arguments.size > 0 ? ' ' + Array.from(this.#data.__arguments).join(', ') : ''}\n`.trim()
}
return ''
@@ -60,16 +60,18 @@ class Formatter {
const table = new Table(rows, this.#colAlign, this.#colWidth, this.#tableWidth, [2, 0, usage.length > 0 ? 1 : 0, 0])
- return usage + '\n\nOptions:' + table.output
+ return usage + '\n\nFlags:' + table.output
} else if (this.#data instanceof Shell) {
const rows = Array.from(this.#data.__processors.values()).map(cmd => {
- return [cmd.name, (cmd.aliases||[]).length > 0 ? `[${cmd.aliases.join(', ').trim()}]` : '', cmd.description]
+ console.log('>>>', cmd.name, cmd.aliases)
+ let nm = [cmd.name].concat(cmd.aliases)
+ return [nm.join('|'), cmd.description]
})
let result = [usage]
if (rows.length > 0) {
- const table = new Table(rows, this.#colAlign, this.#colWidth, this.#tableWidth, [2])
+ const table = new Table(rows, this.#colAlign, ['25%', '75%'], this.#tableWidth, [2])
result.push(`\nCommands:\n`)
result.push(table.output)
}
From b4ad2c41a5b72b4500baf91397dd1b87b028c146 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 29 Apr 2020 17:20:49 -0500
Subject: [PATCH 030/152] Updated deploy process to eliminate root level
scanning.
---
.github/workflows/deploy.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 0630e7b..d63c6ad 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -84,7 +84,7 @@ jobs:
if: steps.autotagger.outputs.tagname != ''
uses: author/action-publish@master
with:
- scan: .dist, ./
+ scan: .dist
env:
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
From b16b8e9343d655463f8964da7c904e3759b64997 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 29 Apr 2020 17:24:27 -0500
Subject: [PATCH 031/152] Removed erroneous debugging output. No longer
displays flag headers if there are no flags (in the default help).
---
package-lock.json | 2 +-
package.json | 2 +-
src/format.js | 3 +--
3 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 1197591..ca1332e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.8",
+ "version": "1.3.9",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 4fe244c..7b6aea9 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.8",
+ "version": "1.3.9",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/format.js b/src/format.js
index 4d0332c..ab50901 100644
--- a/src/format.js
+++ b/src/format.js
@@ -60,10 +60,9 @@ class Formatter {
const table = new Table(rows, this.#colAlign, this.#colWidth, this.#tableWidth, [2, 0, usage.length > 0 ? 1 : 0, 0])
- return usage + '\n\nFlags:' + table.output
+ return usage + (flags.size > 0 ? '\n\nFlags:' + table.output : '')
} else if (this.#data instanceof Shell) {
const rows = Array.from(this.#data.__processors.values()).map(cmd => {
- console.log('>>>', cmd.name, cmd.aliases)
let nm = [cmd.name].concat(cmd.aliases)
return [nm.join('|'), cmd.description]
})
From d4c8998faf5f8474aa26915dfab495d459f72065 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 29 Apr 2020 18:36:20 -0500
Subject: [PATCH 032/152] Attempting to add help override capability.
---
.github/workflows/deploy.yml | 35 ++++++++++++++++++++++++-
package.json | 2 +-
src/base.js | 4 +--
test/unit/01-sanity/01-sanity.js | 44 ++++++++++++++++++++++++++++++++
4 files changed, 81 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index d63c6ad..1081488 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -94,4 +94,37 @@ jobs:
with:
tag: ${{ steps.autotagger.outputs.tagname }}
env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Failure Notification
+ if: failure() && steps.create_release.outputs.id != ''
+ env:
+ SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
+ SLACK_USERNAME: Github # Optional. (defaults to webhook app)
+ SLACK_CHANNEL: author # Optional. (defaults to webhook)
+ SLACK_AVATAR: https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/320px-Npm-logo.svg.png
+ uses: Ilshidur/action-slack@master
+ with:
+ args: '@author.io/shell ${{ steps.autotagger.outputs.tagname }} failed to publish and was rolled back.' # Optional
+
+ - name: Success Notification
+ if: success() && steps.autotagger.outputs.tagname != ''
+ env:
+ SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
+ SLACK_USERNAME: Github # Optional. (defaults to webhook app)
+ SLACK_CHANNEL: author # Optional. (defaults to webhook)
+ SLACK_AVATAR: https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/320px-Npm-logo.svg.png
+ uses: Ilshidur/action-slack@master
+ with:
+ args: '@author.io/shell ${{ steps.autotagger.outputs.tagname }} published to npm.' # Optional
+
+ - name: Inaction Notification
+ if: steps.autotagger.outputs.tagname == ''
+ env:
+ SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
+ SLACK_USERNAME: Github # Optional. (defaults to webhook app)
+ SLACK_CHANNEL: author # Optional. (defaults to webhook)
+ SLACK_AVATAR: "https://cdn.freebiesupply.com/logos/large/2x/nodejs-icon-logo-png-transparent.png" # Optional. can be (repository, sender, an URL) (defaults to webhook app avatar)
+ uses: Ilshidur/action-slack@master
+ with:
+ args: "New code was added to author/shell master branch." # Optional
\ No newline at end of file
diff --git a/package.json b/package.json
index 7b6aea9..749ab69 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.9",
+ "version": "1.3.10-beta.1",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/base.js b/src/base.js
index 4aa6d4d..2289b19 100644
--- a/src/base.js
+++ b/src/base.js
@@ -27,11 +27,11 @@ export default class Base {
throw new Error('Invalid command configuration. A "name" attribute is required.')
}
- if (cfg.hasOwnProperty('help') && cfg.help !== this.help) {
+ if (cfg.hasOwnProperty('help')) {
this.#customHelp = cfg.help
}
- if (cfg.hasOwnProperty('usage') && cfg.usage !== this.usage) {
+ if (cfg.hasOwnProperty('usage')) {
this.#customUsage = cfg.usage
}
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index b2e1912..8428d06 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -82,3 +82,47 @@ test('Output Formatting', t => {
console.log(formatter.help)
t.end()
})
+
+test('Subcommand Config', t => {
+ const cfg = {
+ name: 'account',
+ description: 'Perform operations on a user account.',
+ handler (meta, cb) {
+ console.log('TODO: Output account details')
+ },
+ commands: [
+ {
+ name: 'create',
+ description: 'Create a user account.',
+ arguments: '',
+ flags: {
+ name: {
+ alias: 'n',
+ description: 'Account display name'
+ },
+ phone: {
+ alias: 'p',
+ description: 'Account phone number'
+ },
+ avatar: {
+ alias: 'a',
+ description: 'Account avatar image URL'
+ }
+ },
+
+ handler (meta, cb) {
+ console.log(meta)
+ }
+ }
+ ]
+ }
+
+ const shell = new Shell({
+ name: 'test',
+ commands: [cfg]
+ })
+
+ shell.exec('account create')
+ t.pass('test')
+ t.end()
+})
From 546e4c6b3c634c9311d1a27bc1f82d7f4479a6e6 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 29 Apr 2020 19:06:14 -0500
Subject: [PATCH 033/152] Renamed autohelp to disableHelp (flipped the
boolean). Based on user feedback, this config option is more meaningful and
easier to understand.
---
README.md | 1 +
package.json | 2 +-
src/base.js | 8 ++++++--
test/unit/01-sanity/01-sanity.js | 2 +-
4 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 44211a8..33b7a50 100644
--- a/README.md
+++ b/README.md
@@ -87,6 +87,7 @@ import { Shell, Command } from '@author.io/node-shell'
const ListCommand = new Command({
name: 'list',
description: 'List the contents of the directory.',
+ disableHelp: false, // Set to true to turn off default help messages for the entire shell (you can still provide your own). Defaults to false.
// arguments are listed after the command in the default help screen. Ex: "dir list "
arguments: '',
alias: 'ls',
diff --git a/package.json b/package.json
index 749ab69..06c4caf 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.10-beta.1",
+ "version": "1.3.10",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/base.js b/src/base.js
index 2289b19..60b3376 100644
--- a/src/base.js
+++ b/src/base.js
@@ -35,8 +35,12 @@ export default class Base {
this.#customUsage = cfg.usage
}
- if (cfg.hasOwnProperty('autohelp')) {
- this.#autohelp = cfg.autohelp
+ if (cfg.hasOwnProperty('disablehelp') && !cfg.hasOwnProperty('disableHelp')) {
+ cfg.disableHelp = cfg.disablehelp
+ }
+
+ if (cfg.hasOwnProperty('disableHelp')) {
+ this.#autohelp = !cfg.disableHelp
}
if (typeof cfg.help === 'function' || typeof cfg.help === 'string') {
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index 8428d06..31441a2 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -123,6 +123,6 @@ test('Subcommand Config', t => {
})
shell.exec('account create')
- t.pass('test')
+ t.pass('Configuring subcommands does not throw an error')
t.end()
})
From f42b94e9d5eadd2c139d7595715f4de303b75a4e Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 29 Apr 2020 19:19:05 -0500
Subject: [PATCH 034/152] Re-added default help on commands.
---
package.json | 2 +-
src/command.js | 12 ++++++------
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/package.json b/package.json
index 06c4caf..2d1beb4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.10",
+ "version": "1.3.11-beta.1",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/command.js b/src/command.js
index e56da3d..df0763f 100644
--- a/src/command.js
+++ b/src/command.js
@@ -33,13 +33,13 @@ export default class Command extends Base {
cfg.middleware.forEach(code => this.use(Function(code)))
}
- // this.defaultHandler = (data, cb) => {
- // if (data.help && data.help.requested) {
- // console.log(data.help.message)
- // }
+ this.defaultHandler = (data, cb) => {
+ if (data.help && data.help.requested) {
+ console.log(data.help.message)
+ }
- // cb && cb(data)
- // }
+ cb && cb(data)
+ }
this.#fn = cfg.handler
this.#oid = Symbol(((cfg.name || cfg.usage) || cfg.pattern) || 'command')
From db84abdebd9c9c120b630df734b8ccb00e46c166 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 29 Apr 2020 21:43:58 -0500
Subject: [PATCH 035/152] Updated default handlers and added recursive lookups
for default handlers.
---
package.json | 2 +-
src/base.js | 17 +++++---
src/command.js | 12 ++----
test/unit/01-sanity/01-sanity.js | 74 ++++++++++++++++++++++++++++++++
4 files changed, 91 insertions(+), 14 deletions(-)
diff --git a/package.json b/package.json
index 2d1beb4..b18f57d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.11-beta.1",
+ "version": "1.3.11",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/base.js b/src/base.js
index 60b3376..0e3bbf3 100644
--- a/src/base.js
+++ b/src/base.js
@@ -16,7 +16,15 @@ export default class Base {
#name = 'Unknown'
#middleware = new Middleware()
#hasCustomDefaultHandler = false
- #defaultHandler = data => console.log(this.help)
+ #defaultHandler = function () {
+ if (this.parent !== null && this.parent.hasCustomDefaultHandler) {
+ return this.parent.defaultHandler(...arguments)
+ } else if (this.shell.hasCustomDefaultHandler) {
+ return this.shell.defaultHandler(...arguments)
+ }
+
+ console.log(this.help)
+ }
constructor(cfg = {}) {
if (typeof cfg !== 'object') {
@@ -63,7 +71,6 @@ export default class Base {
this.#arguments = new Set([...cfg.arguments])
}
- this.#defaultHandler = cfg.defaultHandler || this.#defaultHandler
this.#name = (cfg.name || 'unknown').trim().split(/\s+/)[0]
this.#description = cfg.description || null
@@ -265,9 +272,9 @@ export default class Base {
}
}
- if (!command.hasCustomDefaultHandler) {
- command.defaultHandler = this.defaultHandler
- }
+ // if (!command.hasCustomDefaultHandler) {
+ // command.defaultHandler = this.defaultHandler
+ // }
command.autohelp = this.autohelp
diff --git a/src/command.js b/src/command.js
index df0763f..5cbabf9 100644
--- a/src/command.js
+++ b/src/command.js
@@ -33,14 +33,6 @@ export default class Command extends Base {
cfg.middleware.forEach(code => this.use(Function(code)))
}
- this.defaultHandler = (data, cb) => {
- if (data.help && data.help.requested) {
- console.log(data.help.message)
- }
-
- cb && cb(data)
- }
-
this.#fn = cfg.handler
this.#oid = Symbol(((cfg.name || cfg.usage) || cfg.pattern) || 'command')
this.#pattern = cfg.pattern || /[\s\S]+/i
@@ -182,6 +174,10 @@ export default class Command extends Base {
}
}
+ get parent () {
+ return this.#parent
+ }
+
set shell (shell) {
if (!shell) {
throw new Error(`Cannot set shell of ${this.name} command to a non-Shell object.`)
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index 31441a2..af2e0ba 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -126,3 +126,77 @@ test('Subcommand Config', t => {
t.pass('Configuring subcommands does not throw an error')
t.end()
})
+
+// test('Default command help (regression test)', t => {
+// const shell = new Shell({
+// name: 'test',
+// version: '1.0.0',
+// defaultHandler: () => console.log('yo'),
+// commands: [
+// {
+// name: 'account',
+// description: 'Perform operations on a user account.',
+// handler: (meta, cb) => {
+// console.log('TODO: Output account details')
+// },
+// commands: [
+// {
+// name: 'create',
+// description: 'Create a user account.',
+// arguments: '',
+// flags: {
+// name: {
+// alias: 'n',
+// description: 'Account display name'
+// },
+// phone: {
+// alias: 'p',
+// description: 'Account phone number'
+// },
+// avatar: {
+// alias: 'a',
+// description: 'Account avatar image URL'
+// }
+// }
+// // handler: (meta, cb) => {
+// // // console.log(meta);
+// // }
+// }
+// ]
+// },
+// {
+// name: 'find',
+// description: 'Search Metadoc for all the things.',
+// alias: 'search',
+// handler: (meta, cb) => {
+// },
+// flags: {
+// maxresults: {
+// type: 'string',
+// single: true
+// }
+// }
+// },
+// {
+// name: 'load',
+// description: 'Load a metadoc.',
+// handler: (meta, cb) => {
+// }
+// },
+// {
+// name: 'logout',
+// alias: 'signout',
+// handler: (meta, cb) => {
+// console.log(meta)
+// cb && cb()
+// }
+// }
+// ]
+// })
+
+// shell.exec('account create')
+// // console.log('---------')
+// // shell.exec('blah')
+// t.pass('ok')
+// t.end()
+// })
From 8bfa21c884695a91822250f766d2c79428191300 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 29 Apr 2020 21:47:05 -0500
Subject: [PATCH 036/152] Updated build process
---
.github/workflows/deploy.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 1081488..b8464dc 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -102,7 +102,7 @@ jobs:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_USERNAME: Github # Optional. (defaults to webhook app)
SLACK_CHANNEL: author # Optional. (defaults to webhook)
- SLACK_AVATAR: https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/320px-Npm-logo.svg.png
+ SLACK_AVATAR: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/320px-Npm-logo.svg.png"
uses: Ilshidur/action-slack@master
with:
args: '@author.io/shell ${{ steps.autotagger.outputs.tagname }} failed to publish and was rolled back.' # Optional
@@ -113,7 +113,7 @@ jobs:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_USERNAME: Github # Optional. (defaults to webhook app)
SLACK_CHANNEL: author # Optional. (defaults to webhook)
- SLACK_AVATAR: https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/320px-Npm-logo.svg.png
+ SLACK_AVATAR: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/320px-Npm-logo.svg.png"
uses: Ilshidur/action-slack@master
with:
args: '@author.io/shell ${{ steps.autotagger.outputs.tagname }} published to npm.' # Optional
From 130de1b4e6316d763cc457a07caeab98dd9ff846 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 29 Apr 2020 22:01:59 -0500
Subject: [PATCH 037/152] Added missing logic to disable help.
---
package-lock.json | 2 +-
package.json | 2 +-
src/base.js | 6 ++++--
test/unit/01-sanity/01-sanity.js | 6 +++++-
4 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index ca1332e..7fa5182 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.9",
+ "version": "1.3.12",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index b18f57d..98b0495 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.11",
+ "version": "1.3.12",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/base.js b/src/base.js
index 0e3bbf3..359573e 100644
--- a/src/base.js
+++ b/src/base.js
@@ -16,14 +16,16 @@ export default class Base {
#name = 'Unknown'
#middleware = new Middleware()
#hasCustomDefaultHandler = false
- #defaultHandler = function () {
+ #defaultHandler = function (meta) {
if (this.parent !== null && this.parent.hasCustomDefaultHandler) {
return this.parent.defaultHandler(...arguments)
} else if (this.shell.hasCustomDefaultHandler) {
return this.shell.defaultHandler(...arguments)
}
- console.log(this.help)
+ if (this.#autohelp) {
+ console.log(this.help)
+ }
}
constructor(cfg = {}) {
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index af2e0ba..f0d602b 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -131,7 +131,8 @@ test('Subcommand Config', t => {
// const shell = new Shell({
// name: 'test',
// version: '1.0.0',
-// defaultHandler: () => console.log('yo'),
+// disableHelp: true,
+// // defaultHandler: () => console.log('yo'),
// commands: [
// {
// name: 'account',
@@ -144,6 +145,9 @@ test('Subcommand Config', t => {
// name: 'create',
// description: 'Create a user account.',
// arguments: '',
+// help () {
+// return 'overridden help'
+// },
// flags: {
// name: {
// alias: 'n',
From 51fb2ce19d036b2a599b3e9efbbe9cf763056f13 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 29 Apr 2020 22:08:38 -0500
Subject: [PATCH 038/152] Added missing logic to disable help.
---
src/command.js | 2 +-
test/unit/01-sanity/01-sanity.js | 347 +++++++++++++++----------------
2 files changed, 173 insertions(+), 176 deletions(-)
diff --git a/src/command.js b/src/command.js
index 5cbabf9..5064eb3 100644
--- a/src/command.js
+++ b/src/command.js
@@ -85,7 +85,7 @@ export default class Command extends Base {
'commands',
'subcommands',
'defaultHandler',
- 'autohelp',
+ 'disableHelp',
'flags',
'alias',
'aliases',
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index f0d602b..ba5356e 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -2,205 +2,202 @@ import 'source-map-support/register.js'
import test from 'tape'
import { Command, Shell, Formatter } from '../../.node/index.js'
-test('Sanity Check - Shell', t => {
- const shell = new Shell({
- name: 'test'
- })
-
- t.ok(shell instanceof Shell, 'Basic shell instantiates correctly.')
-
- t.end()
-})
-
-test('Sanity Check - Command', t => {
- const mirror = new Command({
- name: 'mirror',
- description: 'Search metadoc for all the things.',
- alias: 'search',
- handler: (input, cb) => {
- console.log(`Mirroring input: ${input}`)
-
- cb && cb()
- }
- })
+// test('Sanity Check - Shell', t => {
+// const shell = new Shell({
+// name: 'test'
+// })
- t.ok(mirror instanceof Command, 'Command initialized successfully.')
+// t.ok(shell instanceof Shell, 'Basic shell instantiates correctly.')
- const CLI = new Shell({
- name: 'test',
- description: 'test',
- commands: [
- mirror,
- {
- name: 'test',
- description: 'Test command which has no custom handler.'
- }
- ]
- })
+// t.end()
+// })
- t.ok(CLI instanceof Shell, 'Shell initialized with commands successfully.')
+// test('Sanity Check - Command', t => {
+// const mirror = new Command({
+// name: 'mirror',
+// description: 'Search metadoc for all the things.',
+// alias: 'search',
+// handler: (input, cb) => {
+// console.log(`Mirroring input: ${input}`)
- CLI.exec('test').then(data => {
- t.pass('Default handler fires.')
- t.end()
- }).catch(e => {
- console.log(e)
- t.fail(e.message)
- t.end()
- })
-})
+// cb && cb()
+// }
+// })
-test('Output Formatting', t => {
- const shell = new Shell({
- name: 'test'
- })
+// t.ok(mirror instanceof Command, 'Command initialized successfully.')
- const cmd = new Command({
- name: 'cmd',
- alias: 'c',
- flags: {
- test: {
- alias: 't',
- description: 'test description'
- },
- more: {
- aliases: ['m', 'mr'],
- description: 'This is a longer description that should break onto more than one line, or perhaps even more than one extra line with especially poor grammar and spellling.'
- },
- none: {
- description: 'Ignore me. I do not exist.'
- }
- }
- })
+// const CLI = new Shell({
+// name: 'test',
+// description: 'test',
+// commands: [
+// mirror,
+// {
+// name: 'test',
+// description: 'Test command which has no custom handler.'
+// }
+// ]
+// })
- shell.add(cmd)
+// t.ok(CLI instanceof Shell, 'Shell initialized with commands successfully.')
- const formatter = new Formatter(cmd)
- formatter.width = 80
+// CLI.exec('test').then(data => {
+// t.pass('Default handler fires.')
+// t.end()
+// }).catch(e => {
+// console.log(e)
+// t.fail(e.message)
+// t.end()
+// })
+// })
- t.ok(formatter instanceof Formatter, 'Basic formatter instantiates correctly.')
- console.log(formatter.help)
- t.end()
-})
+// test('Output Formatting', t => {
+// const shell = new Shell({
+// name: 'test'
+// })
-test('Subcommand Config', t => {
- const cfg = {
- name: 'account',
- description: 'Perform operations on a user account.',
- handler (meta, cb) {
- console.log('TODO: Output account details')
- },
- commands: [
- {
- name: 'create',
- description: 'Create a user account.',
- arguments: '',
- flags: {
- name: {
- alias: 'n',
- description: 'Account display name'
- },
- phone: {
- alias: 'p',
- description: 'Account phone number'
- },
- avatar: {
- alias: 'a',
- description: 'Account avatar image URL'
- }
- },
+// const cmd = new Command({
+// name: 'cmd',
+// alias: 'c',
+// flags: {
+// test: {
+// alias: 't',
+// description: 'test description'
+// },
+// more: {
+// aliases: ['m', 'mr'],
+// description: 'This is a longer description that should break onto more than one line, or perhaps even more than one extra line with especially poor grammar and spellling.'
+// },
+// none: {
+// description: 'Ignore me. I do not exist.'
+// }
+// }
+// })
- handler (meta, cb) {
- console.log(meta)
- }
- }
- ]
- }
+// shell.add(cmd)
- const shell = new Shell({
- name: 'test',
- commands: [cfg]
- })
+// const formatter = new Formatter(cmd)
+// formatter.width = 80
- shell.exec('account create')
- t.pass('Configuring subcommands does not throw an error')
- t.end()
-})
+// t.ok(formatter instanceof Formatter, 'Basic formatter instantiates correctly.')
+// console.log(formatter.help)
+// t.end()
+// })
-// test('Default command help (regression test)', t => {
-// const shell = new Shell({
-// name: 'test',
-// version: '1.0.0',
-// disableHelp: true,
-// // defaultHandler: () => console.log('yo'),
+// test('Subcommand Config', t => {
+// const cfg = {
+// name: 'account',
+// description: 'Perform operations on a user account.',
+// handler (meta, cb) {
+// console.log('TODO: Output account details')
+// },
// commands: [
// {
-// name: 'account',
-// description: 'Perform operations on a user account.',
-// handler: (meta, cb) => {
-// console.log('TODO: Output account details')
-// },
-// commands: [
-// {
-// name: 'create',
-// description: 'Create a user account.',
-// arguments: '',
-// help () {
-// return 'overridden help'
-// },
-// flags: {
-// name: {
-// alias: 'n',
-// description: 'Account display name'
-// },
-// phone: {
-// alias: 'p',
-// description: 'Account phone number'
-// },
-// avatar: {
-// alias: 'a',
-// description: 'Account avatar image URL'
-// }
-// }
-// // handler: (meta, cb) => {
-// // // console.log(meta);
-// // }
-// }
-// ]
-// },
-// {
-// name: 'find',
-// description: 'Search Metadoc for all the things.',
-// alias: 'search',
-// handler: (meta, cb) => {
-// },
+// name: 'create',
+// description: 'Create a user account.',
+// arguments: '',
// flags: {
-// maxresults: {
-// type: 'string',
-// single: true
+// name: {
+// alias: 'n',
+// description: 'Account display name'
+// },
+// phone: {
+// alias: 'p',
+// description: 'Account phone number'
+// },
+// avatar: {
+// alias: 'a',
+// description: 'Account avatar image URL'
// }
-// }
-// },
-// {
-// name: 'load',
-// description: 'Load a metadoc.',
-// handler: (meta, cb) => {
-// }
-// },
-// {
-// name: 'logout',
-// alias: 'signout',
-// handler: (meta, cb) => {
+// },
+
+// handler (meta, cb) {
// console.log(meta)
-// cb && cb()
// }
// }
// ]
+// }
+
+// const shell = new Shell({
+// name: 'test',
+// commands: [cfg]
// })
// shell.exec('account create')
-// // console.log('---------')
-// // shell.exec('blah')
-// t.pass('ok')
+// t.pass('Configuring subcommands does not throw an error')
// t.end()
// })
+
+test('Default command help (regression test)', t => {
+ const shell = new Shell({
+ name: 'test',
+ version: '1.0.0',
+ disableHelp: true,
+ // defaultHandler: () => console.log('yo'),
+ commands: [
+ {
+ name: 'account',
+ description: 'Perform operations on a user account.',
+ handler: (meta, cb) => {
+ console.log('TODO: Output account details')
+ },
+ commands: [
+ {
+ name: 'create',
+ description: 'Create a user account.',
+ arguments: '',
+ flags: {
+ name: {
+ alias: 'n',
+ description: 'Account display name'
+ },
+ phone: {
+ alias: 'p',
+ description: 'Account phone number'
+ },
+ avatar: {
+ alias: 'a',
+ description: 'Account avatar image URL'
+ }
+ }
+ // handler: (meta, cb) => {
+ // // console.log(meta);
+ // }
+ }
+ ]
+ },
+ {
+ name: 'find',
+ description: 'Search Metadoc for all the things.',
+ alias: 'search',
+ handler: (meta, cb) => {
+ },
+ flags: {
+ maxresults: {
+ type: 'string',
+ single: true
+ }
+ }
+ },
+ {
+ name: 'load',
+ description: 'Load a metadoc.',
+ handler: (meta, cb) => {
+ }
+ },
+ {
+ name: 'logout',
+ alias: 'signout',
+ handler: (meta, cb) => {
+ console.log(meta)
+ cb && cb()
+ }
+ }
+ ]
+ })
+
+ shell.exec('account create --help')
+ // console.log('---------')
+ // shell.exec('blah')
+ t.pass('ok')
+ t.end()
+})
From 194b86d6462292010b37eb29ddd1ed7e02528cd5 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 29 Apr 2020 22:23:23 -0500
Subject: [PATCH 039/152] Add support for edge case when help is disabled but a
--help flag is still provided (Was treated like an unknown command instead of
a flag)
---
src/shell.js | 8 +++++++-
test/unit/01-sanity/01-sanity.js | 2 +-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/shell.js b/src/shell.js
index 3a0669b..3d4f925 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -164,7 +164,13 @@ export default class Shell extends Base {
}
}, [])
- if (this.middleware.size === 0) {
+ if (args.trim().toLowerCase() === '--help') {
+ if (!this.autohelp) {
+ return await Command.reply()
+ }
+ }
+
+ if (this.middleware.size === 0) {
return await Command.reply(await processor.run(args, callback))
}
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index ba5356e..9f53242 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -195,7 +195,7 @@ test('Default command help (regression test)', t => {
]
})
- shell.exec('account create --help')
+ shell.exec('account')
// console.log('---------')
// shell.exec('blah')
t.pass('ok')
From 976ea009ed66d0297f4c04d925a05cd2f2bc098d Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 29 Apr 2020 22:24:00 -0500
Subject: [PATCH 040/152] Re-enabled unit tests.
---
package-lock.json | 2 +-
package.json | 2 +-
test/unit/01-sanity/01-sanity.js | 346 +++++++++++++++----------------
3 files changed, 175 insertions(+), 175 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 7fa5182..db2f906 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.12",
+ "version": "1.3.13",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 98b0495..3dd71e6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.12",
+ "version": "1.3.13",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index 9f53242..fe806f3 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -2,202 +2,202 @@ import 'source-map-support/register.js'
import test from 'tape'
import { Command, Shell, Formatter } from '../../.node/index.js'
-// test('Sanity Check - Shell', t => {
-// const shell = new Shell({
-// name: 'test'
-// })
-
-// t.ok(shell instanceof Shell, 'Basic shell instantiates correctly.')
-
-// t.end()
-// })
-
-// test('Sanity Check - Command', t => {
-// const mirror = new Command({
-// name: 'mirror',
-// description: 'Search metadoc for all the things.',
-// alias: 'search',
-// handler: (input, cb) => {
-// console.log(`Mirroring input: ${input}`)
-
-// cb && cb()
-// }
-// })
+test('Sanity Check - Shell', t => {
+ const shell = new Shell({
+ name: 'test'
+ })
-// t.ok(mirror instanceof Command, 'Command initialized successfully.')
+ t.ok(shell instanceof Shell, 'Basic shell instantiates correctly.')
-// const CLI = new Shell({
-// name: 'test',
-// description: 'test',
-// commands: [
-// mirror,
-// {
-// name: 'test',
-// description: 'Test command which has no custom handler.'
-// }
-// ]
-// })
+ t.end()
+})
-// t.ok(CLI instanceof Shell, 'Shell initialized with commands successfully.')
+test('Sanity Check - Command', t => {
+ const mirror = new Command({
+ name: 'mirror',
+ description: 'Search metadoc for all the things.',
+ alias: 'search',
+ handler: (input, cb) => {
+ console.log(`Mirroring input: ${input}`)
-// CLI.exec('test').then(data => {
-// t.pass('Default handler fires.')
-// t.end()
-// }).catch(e => {
-// console.log(e)
-// t.fail(e.message)
-// t.end()
-// })
-// })
+ cb && cb()
+ }
+ })
-// test('Output Formatting', t => {
-// const shell = new Shell({
-// name: 'test'
-// })
+ t.ok(mirror instanceof Command, 'Command initialized successfully.')
-// const cmd = new Command({
-// name: 'cmd',
-// alias: 'c',
-// flags: {
-// test: {
-// alias: 't',
-// description: 'test description'
-// },
-// more: {
-// aliases: ['m', 'mr'],
-// description: 'This is a longer description that should break onto more than one line, or perhaps even more than one extra line with especially poor grammar and spellling.'
-// },
-// none: {
-// description: 'Ignore me. I do not exist.'
-// }
-// }
-// })
+ const CLI = new Shell({
+ name: 'test',
+ description: 'test',
+ commands: [
+ mirror,
+ {
+ name: 'test',
+ description: 'Test command which has no custom handler.'
+ }
+ ]
+ })
-// shell.add(cmd)
+ t.ok(CLI instanceof Shell, 'Shell initialized with commands successfully.')
-// const formatter = new Formatter(cmd)
-// formatter.width = 80
+ CLI.exec('test').then(data => {
+ t.pass('Default handler fires.')
+ t.end()
+ }).catch(e => {
+ console.log(e)
+ t.fail(e.message)
+ t.end()
+ })
+})
-// t.ok(formatter instanceof Formatter, 'Basic formatter instantiates correctly.')
-// console.log(formatter.help)
-// t.end()
-// })
+test('Output Formatting', t => {
+ const shell = new Shell({
+ name: 'test'
+ })
-// test('Subcommand Config', t => {
-// const cfg = {
-// name: 'account',
-// description: 'Perform operations on a user account.',
-// handler (meta, cb) {
-// console.log('TODO: Output account details')
-// },
-// commands: [
-// {
-// name: 'create',
-// description: 'Create a user account.',
-// arguments: '',
-// flags: {
-// name: {
-// alias: 'n',
-// description: 'Account display name'
-// },
-// phone: {
-// alias: 'p',
-// description: 'Account phone number'
-// },
-// avatar: {
-// alias: 'a',
-// description: 'Account avatar image URL'
-// }
-// },
+ const cmd = new Command({
+ name: 'cmd',
+ alias: 'c',
+ flags: {
+ test: {
+ alias: 't',
+ description: 'test description'
+ },
+ more: {
+ aliases: ['m', 'mr'],
+ description: 'This is a longer description that should break onto more than one line, or perhaps even more than one extra line with especially poor grammar and spellling.'
+ },
+ none: {
+ description: 'Ignore me. I do not exist.'
+ }
+ }
+ })
-// handler (meta, cb) {
-// console.log(meta)
-// }
-// }
-// ]
-// }
+ shell.add(cmd)
-// const shell = new Shell({
-// name: 'test',
-// commands: [cfg]
-// })
+ const formatter = new Formatter(cmd)
+ formatter.width = 80
-// shell.exec('account create')
-// t.pass('Configuring subcommands does not throw an error')
-// t.end()
-// })
+ t.ok(formatter instanceof Formatter, 'Basic formatter instantiates correctly.')
+ console.log(formatter.help)
+ t.end()
+})
-test('Default command help (regression test)', t => {
- const shell = new Shell({
- name: 'test',
- version: '1.0.0',
- disableHelp: true,
- // defaultHandler: () => console.log('yo'),
+test('Subcommand Config', t => {
+ const cfg = {
+ name: 'account',
+ description: 'Perform operations on a user account.',
+ handler (meta, cb) {
+ console.log('TODO: Output account details')
+ },
commands: [
{
- name: 'account',
- description: 'Perform operations on a user account.',
- handler: (meta, cb) => {
- console.log('TODO: Output account details')
- },
- commands: [
- {
- name: 'create',
- description: 'Create a user account.',
- arguments: '',
- flags: {
- name: {
- alias: 'n',
- description: 'Account display name'
- },
- phone: {
- alias: 'p',
- description: 'Account phone number'
- },
- avatar: {
- alias: 'a',
- description: 'Account avatar image URL'
- }
- }
- // handler: (meta, cb) => {
- // // console.log(meta);
- // }
- }
- ]
- },
- {
- name: 'find',
- description: 'Search Metadoc for all the things.',
- alias: 'search',
- handler: (meta, cb) => {
- },
+ name: 'create',
+ description: 'Create a user account.',
+ arguments: '',
flags: {
- maxresults: {
- type: 'string',
- single: true
+ name: {
+ alias: 'n',
+ description: 'Account display name'
+ },
+ phone: {
+ alias: 'p',
+ description: 'Account phone number'
+ },
+ avatar: {
+ alias: 'a',
+ description: 'Account avatar image URL'
}
- }
- },
- {
- name: 'load',
- description: 'Load a metadoc.',
- handler: (meta, cb) => {
- }
- },
- {
- name: 'logout',
- alias: 'signout',
- handler: (meta, cb) => {
+ },
+
+ handler (meta, cb) {
console.log(meta)
- cb && cb()
}
}
]
+ }
+
+ const shell = new Shell({
+ name: 'test',
+ commands: [cfg]
})
- shell.exec('account')
- // console.log('---------')
- // shell.exec('blah')
- t.pass('ok')
+ shell.exec('account create')
+ t.pass('Configuring subcommands does not throw an error')
t.end()
})
+
+// test('Default command help (regression test)', t => {
+// const shell = new Shell({
+// name: 'test',
+// version: '1.0.0',
+// disableHelp: true,
+// // defaultHandler: () => console.log('yo'),
+// commands: [
+// {
+// name: 'account',
+// description: 'Perform operations on a user account.',
+// handler: (meta, cb) => {
+// console.log('TODO: Output account details')
+// },
+// commands: [
+// {
+// name: 'create',
+// description: 'Create a user account.',
+// arguments: '',
+// flags: {
+// name: {
+// alias: 'n',
+// description: 'Account display name'
+// },
+// phone: {
+// alias: 'p',
+// description: 'Account phone number'
+// },
+// avatar: {
+// alias: 'a',
+// description: 'Account avatar image URL'
+// }
+// }
+// // handler: (meta, cb) => {
+// // // console.log(meta);
+// // }
+// }
+// ]
+// },
+// {
+// name: 'find',
+// description: 'Search Metadoc for all the things.',
+// alias: 'search',
+// handler: (meta, cb) => {
+// },
+// flags: {
+// maxresults: {
+// type: 'string',
+// single: true
+// }
+// }
+// },
+// {
+// name: 'load',
+// description: 'Load a metadoc.',
+// handler: (meta, cb) => {
+// }
+// },
+// {
+// name: 'logout',
+// alias: 'signout',
+// handler: (meta, cb) => {
+// console.log(meta)
+// cb && cb()
+// }
+// }
+// ]
+// })
+
+// shell.exec('account')
+// // console.log('---------')
+// // shell.exec('blah')
+// t.pass('ok')
+// t.end()
+// })
From f540d8c31d832c4b0e4ba7d04c2c972cb6619fd0 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Fri, 1 May 2020 01:08:04 -0500
Subject: [PATCH 041/152] Refactored middleware (large code reduction). Added
unit tests and updated docs to reflect the changes.
---
README.md | 18 ++-
package-lock.json | 2 +-
package.json | 2 +-
src/base.js | 32 +++--
src/command.js | 100 +++++---------
src/index.js | 5 +-
src/middleware.js | 29 ++--
src/shell.js | 43 ++----
test/unit/01-sanity/01-sanity.js | 124 ++++++-----------
test/unit/01-sanity/02-middleware.js | 175 ++++++++++++++++++++++++
test/unit/01-sanity/03-help-defaults.js | 99 ++++++++++++++
11 files changed, 424 insertions(+), 205 deletions(-)
create mode 100644 test/unit/01-sanity/02-middleware.js
create mode 100644 test/unit/01-sanity/03-help-defaults.js
diff --git a/README.md b/README.md
index 33b7a50..89c4091 100644
--- a/README.md
+++ b/README.md
@@ -46,7 +46,7 @@ Sometimes single purpose tools grow into multipurpose tools over time. Tools whi
`npm install @author.io/node-shell`
-Please note, you'll need a verison of Node that supports ES Modules. In Node 12, this feature is behind the `--experimental-modules` flag. It is available in Node 13+ without a flag, but your `package.json` file must have the `"type": "module"` attribute. This feature will be generally available in Node 14.0.0 (release date April 21, 2020).
+Please note, you'll need a verison of Node that supports ES Modules. In Node 12, this feature is behind the `--experimental-modules` flag. It is available in Node 13+ without a flag, but your `package.json` file must have the `"type": "module"` attribute. This feature is generally available as of [Node 14.0.0](https://nodejs.org).
### For Legacy Node (CommonJS/require)
@@ -60,15 +60,17 @@ If you need to use the older CommonJS format (i.e. `require`), run `npm install
import { Shell, Command } from 'https://cdn.pika.dev/@author.io/browser-shell'
```
-Also available from [jsdelivr](https://www.jsdelivr.com/?query=%40author.io%2Fshell) and [unpkg](https://unpkg.com/@author.io/browser-shell).
+Also available from [jsdelivr](https://www.jsdelivr.com/package/npm/@author.io/browser-shell) and [unpkg](https://unpkg.com/@author.io/browser-shell).
**npm options**
If you wish to bundle this library in your build process, use the version most appropriate for your target runtimes:
-- `npm install @author.io/shell` (source)
- `npm install @author.io/browser-shell` (Minified ES Module)
- `npm install @author.io/browser-shell-es6` (IIFE Minified Module - globally accessible)
+- `npm install @author.io/shell` (source)
+
+**TAKE NOTICE: The source may not be what you think it is.** The source code may contain Node or browser code that is stripped out during the build process. We have a goal of making the _API_ runtime-agnostic, not the implementation. We do everything we can to avoid runtime-specific source code though, and it is rare to have node or browser-specific source code... we just can't guarantee the source will be easily embeddable. We recommend consuming the prebuilt editions.
### Debugging
@@ -94,7 +96,8 @@ const ListCommand = new Command({
// Any flag parsing options from the @author.io/arg library can be configured here.
// See https://github.com/author/arg#configuration-methods for a list.
flags: {
- l: {
+ long: {
+ alias: 'l',
description: 'Long format'.
type: 'boolean',
default: false
@@ -106,7 +109,7 @@ const ListCommand = new Command({
}
},
handler (metadata, callback) {
- // ... this is where your command actually runs ...
+ // ... this is where your command actually does something ...
// Data comes from @author.io/arg lib. It looks like:
// {
@@ -127,7 +130,10 @@ const ListCommand = new Command({
console.log(metadata)
// A single flag's value can be retrieved with this helper method.
- console.log(metadata.flag('l))
+ console.log(metadata.flag('long'))
+
+ // Any unrecognized flags can be retrieved by index number (0-based)
+ console.log(metadata.flag(0)) // The first unrecognized flag... returns null if it doesn't exist
// Execution callbacks are optional. If a callback is passed from the
// execution context to this handler, it will run after the command
diff --git a/package-lock.json b/package-lock.json
index db2f906..b6f859d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.13",
+ "version": "1.3.14",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 3dd71e6..17fe10c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.13",
+ "version": "1.3.14",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/base.js b/src/base.js
index 359573e..af53180 100644
--- a/src/base.js
+++ b/src/base.js
@@ -49,8 +49,8 @@ export default class Base {
cfg.disableHelp = cfg.disablehelp
}
- if (cfg.hasOwnProperty('disableHelp')) {
- this.#autohelp = !cfg.disableHelp
+ if (cfg.hasOwnProperty('disableHelp') && cfg.disableHelp === true) {
+ this.#autohelp = false
}
if (typeof cfg.help === 'function' || typeof cfg.help === 'string') {
@@ -113,6 +113,20 @@ export default class Base {
set (v) {
this.#width = v || 80
}
+ },
+ initializeMiddleware: {
+ enumerable: false,
+ configurable: false,
+ writable: false,
+ value: code => {
+ if (typeof code === 'string') {
+ this.use(Function('return ' + code)())
+ } else if (typeof code === 'function') {
+ this.use(code)
+ } else {
+ throw new Error('Invalid middleware: ' + code.toString())
+ }
+ }
}
})
}
@@ -165,6 +179,10 @@ export default class Base {
return typeof this.#customHelp === 'function' ? this.#customHelp(this) : this.#customHelp
}
+ if (!this.autohelp) {
+ return ''
+ }
+
this.updateHelp()
return this.#formattedDefaultHelp.help
@@ -244,7 +262,7 @@ export default class Base {
}
}
- use() {
+ use () {
for (const arg of arguments) {
if (typeof arg !== 'function') {
throw new Error(`All "use()" arguments must be valid functions.\n${arg.toString().substring(0, 50)} ${arg.toString().length > 50 ? '...' : ''}`)
@@ -253,7 +271,7 @@ export default class Base {
this.#middleware.use(arg)
}
- this.__processors.forEach(subCmd => subCmd.use(...arguments))
+ this.#processors.forEach(subCmd => subCmd.use(...arguments))
}
get middleware () {
@@ -261,7 +279,7 @@ export default class Base {
}
get commands() {
- return this.__processors
+ return this.#processors
}
add () {
@@ -274,10 +292,6 @@ export default class Base {
}
}
- // if (!command.hasCustomDefaultHandler) {
- // command.defaultHandler = this.defaultHandler
- // }
-
command.autohelp = this.autohelp
if (this instanceof Shell) {
diff --git a/src/command.js b/src/command.js
index 5064eb3..13d5bb9 100644
--- a/src/command.js
+++ b/src/command.js
@@ -30,7 +30,7 @@ export default class Command extends Base {
super(cfg)
if (cfg.hasOwnProperty('middleware') && Array.isArray(cfg.middleware)) {
- cfg.middleware.forEach(code => this.use(Function(code)))
+ cfg.middleware.forEach(code => this.initializeMiddleware(code))
}
this.#fn = cfg.handler
@@ -117,6 +117,31 @@ export default class Command extends Base {
return flags
}
+ },
+ getTerminalCommand: {
+ enumerable: false,
+ configurable: false,
+ writable: false,
+ value: input => {
+ let args = input.trim().split(/\t+|\s+/)
+ let cmd = this
+
+ while (args.length > 0) {
+ const arg = args[0]
+ const subcmd = cmd.getCommand(arg)
+ if (subcmd) {
+ cmd = subcmd
+ args.shift()
+ } else {
+ break
+ }
+ }
+
+ return {
+ command: cmd,
+ arguments: args.join(' ')
+ }
+ }
}
})
@@ -373,79 +398,20 @@ export default class Command extends Base {
}
async run (input, callback) {
- let fn = (this.#fn || this.defaultHandler).bind(this)
- let data = typeof input === 'string' ? this.parse(input) : input
- const parsed = SUBCOMMAND_PATTERN.exec(input)
+ const fn = (this.#fn || this.defaultHandler).bind(this)
+ const data = typeof input === 'string' ? this.parse(input) : input
arguments[0] = this.deepParse(input)
-
- // A possible subcommand was input
- if (parsed) {
- let cmd = parsed[1]
- let args = parsed.length > 2 ? parsed[2] : ''
- let command = null
- let subcommand = this.__commands.get(cmd)
-
- if (!subcommand) {
- for (const [name, id] of this.__commands) {
- const subcmd = this.__processors.get(id)
-
- if (subcmd.aliases.indexOf(cmd)) {
- subcommand = subcmd
- break
- }
- }
- }
-
- // If the prospective subcommand is not recognized, run the main processor
- if (!subcommand) {
- return await (new Promise((resolve, reject) => {
- try {
- if (this.autohelp && data.help.requested) {
- console.log(this.help)
- resolve()
- } else {
- try {
- this.middleware.use(fn)
- resolve(() => this.middleware.run(data, () => callback && callback()))
- } catch (ee) {
- reject(ee)
- }
- }
- } catch (e) {
- reject(e)
- }
- }))
- }
-
- const processor = this.__processors.get(subcommand)
-
- if (this.autohelp) {
- if (data.help.requested) {
- if (processor) {
- return console.log(processor.help)
- } else {
- return console.log(this.help)
- }
- }
- }
-
- if (!processor) {
- return new Promise((resolve, reject) => reject(new Error(`${ this.name } "${cmd}" command not found.`)))
- }
-
- if (this.middleware.size > 0) {
- this.middleware.use(async meta => await Command.reply(fn(meta, callback)))
- return this.middleware.run(...arguments, () => {})
- }
- return Command.reply(await processor.run(args, callback))
+ const parentMiddleware = this.shell.getCommandMiddleware(this.commandroot.replace(new RegExp(`^${this.shell.name}`, 'i'), '').trim())
+
+ if (parentMiddleware.length > 0) {
+ this.middleware.use(...parentMiddleware)
}
// No subcommand was recognized
if (this.middleware.size > 0) {
- this.middleware.use(async meta => await Command.reply(fn(meta, callback)))
- return this.middleware.run(...arguments, () => {})
+ return this.middleware.run(arguments[0], async meta => await Command.reply(fn(meta, callback)))
}
return Command.reply(fn(data, callback))
diff --git a/src/index.js b/src/index.js
index cbdc682..4e8cc76 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,5 +1,6 @@
import Command from './command.js'
import Shell from './shell.js'
+import Middleware from './middleware.js'
import { Formatter, Table } from './format.js'
-const all = { Shell, Command, Formatter, Table }
-export { Command, Shell, Formatter, Table, all as default }
+const all = { Shell, Command, Formatter, Table, Middleware }
+export { Command, Shell, Formatter, Table, Middleware, all as default }
diff --git a/src/middleware.js b/src/middleware.js
index 80f4280..6519ecf 100644
--- a/src/middleware.js
+++ b/src/middleware.js
@@ -1,8 +1,10 @@
-const last = a => a[a.length - 1]
-const reduce = a => a.slice(0, -1)
-
export default class Middleware {
- constructor () { Object.defineProperty(this, '_data', { enumerable: false, value: [] }) }
+ constructor () {
+ Object.defineProperties(this, {
+ _data: { enumerable: false, configurable: false, value: [] },
+ go: { enumerable: false, configurable: false, writable: true, value: (...args) => { args.pop().apply(this, args) } }
+ })
+ }
get size () { return this._data.length }
@@ -14,13 +16,20 @@ export default class Middleware {
this._data.push(methodBody)
}
- this.run = ((stack) => (...args) => stack(...reduce(args), () => {
- const next = last(args)
- method.apply(this, [...reduce(args), next.bind.apply(next, [null, ...reduce(args)])])
- }))(this.run)
+ this.go = (stack => (...args) => {
+ let next = args.pop()
+ stack(...args, () => {
+ method.apply(this, [...args, next.bind(null, ...args)])
+ })
+ })(this.go)
}
- run (...args) {
- last(args).apply(this, reduce(args))
+ run () {
+ const args = Array.from(arguments)
+ if (args.length === 0 || typeof args[args.length - 1] !== 'function') {
+ args.push(() => {})
+ }
+
+ this.go(...args)
}
}
diff --git a/src/shell.js b/src/shell.js
index 3d4f925..eb68754 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -24,7 +24,7 @@ export default class Shell extends Base {
super(cfg)
if (cfg.hasOwnProperty('middleware') && Array.isArray(cfg.middleware)) {
- cfg.middleware.forEach(code => this.use(Function('return ' + code)()))
+ cfg.middleware.forEach(code => this.initializeMiddleware(code))
}
this.#version = cfg.version || '1.0.0'
@@ -110,7 +110,7 @@ export default class Shell extends Base {
const fns = Array.from(arguments).slice(1)
- commands.forEach(cmd => this.#middlewareGroups.set(cmd, (this.#middlewareGroups.get(cmd) || []).concat(fns)))
+ commands.forEach(cmd => this.#middlewareGroups.set(cmd.trim(), (this.#middlewareGroups.get(cmd.trim()) || []).concat(fns)))
}
async exec (input, callback) {
@@ -125,6 +125,8 @@ export default class Shell extends Base {
if (parsed === null) {
if (input.indexOf('version') !== -1 || input.indexOf('-v') !== -1) {
return console.log(this.version)
+ } else if (input.indexOf('help') !== -1) {
+ return console.log(this.help)
}
return Command.stderr(this.help)
@@ -146,38 +148,23 @@ export default class Shell extends Base {
return Command.stderr(this.help)
}
- const processor = this.__processors.get(action)
+ let processor = this.__processors.get(action)
if (!processor) {
return Command.stderr('Command not found.')
}
- // Apply command-specific middleware (configured via useWith)
- processor.commandroot.replace(new RegExp('^' + this.name, 'i'), '')
- .trim()
- .split(/\s+/)
- .reduce((cmdpath, name) => {
- cmdpath.push(name)
- const fns = this.#middlewareGroups.get(cmdpath.join(' '))
- if (fns) {
- processor.use(...fns)
- }
- }, [])
-
- if (args.trim().toLowerCase() === '--help') {
- if (!this.autohelp) {
- return await Command.reply()
- }
- }
-
- if (this.middleware.size === 0) {
- return await Command.reply(await processor.run(args, callback))
- }
+ const term = processor.getTerminalCommand(args)
+ return await Command.reply(await term.command.run(term.arguments, callback))
+ }
- arguments[0] = processor.deepParse(args)
+ getCommandMiddleware (cmd) {
+ let results = []
+ cmd.split(/\s+/).forEach((c, i, a) => {
+ let r = this.#middlewareGroups.get(a.slice(0, i + 1).join(' '))
+ r && results.push(r.flat(Infinity))
+ })
- return this.middleware.run(
- ...arguments,
- async () => await Command.reply(await processor.run(args)))
+ return results.flat(Infinity)
}
}
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index fe806f3..56ff2af 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -1,7 +1,7 @@
import 'source-map-support/register.js'
import test from 'tape'
import { Command, Shell, Formatter } from '../../.node/index.js'
-
+import fs from 'fs'
test('Sanity Check - Shell', t => {
const shell = new Shell({
name: 'test'
@@ -44,7 +44,6 @@ test('Sanity Check - Command', t => {
t.pass('Default handler fires.')
t.end()
}).catch(e => {
- console.log(e)
t.fail(e.message)
t.end()
})
@@ -79,11 +78,21 @@ test('Output Formatting', t => {
formatter.width = 80
t.ok(formatter instanceof Formatter, 'Basic formatter instantiates correctly.')
- console.log(formatter.help)
+ // fs.writeFileSync('./test.txt', Buffer.from(formatter.help))
+ t.ok(formatter.help === `test cmd|c [FLAGS]
+
+Flags:
+ -test [-t] test description
+ -more [-m, -mr] This is a longer description that should break onto
+ more than one line, or perhaps even more than one
+ extra line with especially poor grammar and
+ spellling.
+ -none Ignore me. I do not exist. `, 'Correctly generated default help message.')
t.end()
})
test('Subcommand Config', t => {
+ let ok = false
const cfg = {
name: 'account',
description: 'Perform operations on a user account.',
@@ -111,7 +120,7 @@ test('Subcommand Config', t => {
},
handler (meta, cb) {
- console.log(meta)
+ ok = true
}
}
]
@@ -122,82 +131,35 @@ test('Subcommand Config', t => {
commands: [cfg]
})
- shell.exec('account create')
- t.pass('Configuring subcommands does not throw an error')
- t.end()
+ shell.exec('account create').then(r => {
+ t.ok(ok, 'Configuring subcommands does not throw an error')
+ }).catch(e => t.fail(e.message))
+ .finally(() => t.end())
})
-// test('Default command help (regression test)', t => {
-// const shell = new Shell({
-// name: 'test',
-// version: '1.0.0',
-// disableHelp: true,
-// // defaultHandler: () => console.log('yo'),
-// commands: [
-// {
-// name: 'account',
-// description: 'Perform operations on a user account.',
-// handler: (meta, cb) => {
-// console.log('TODO: Output account details')
-// },
-// commands: [
-// {
-// name: 'create',
-// description: 'Create a user account.',
-// arguments: '',
-// flags: {
-// name: {
-// alias: 'n',
-// description: 'Account display name'
-// },
-// phone: {
-// alias: 'p',
-// description: 'Account phone number'
-// },
-// avatar: {
-// alias: 'a',
-// description: 'Account avatar image URL'
-// }
-// }
-// // handler: (meta, cb) => {
-// // // console.log(meta);
-// // }
-// }
-// ]
-// },
-// {
-// name: 'find',
-// description: 'Search Metadoc for all the things.',
-// alias: 'search',
-// handler: (meta, cb) => {
-// },
-// flags: {
-// maxresults: {
-// type: 'string',
-// single: true
-// }
-// }
-// },
-// {
-// name: 'load',
-// description: 'Load a metadoc.',
-// handler: (meta, cb) => {
-// }
-// },
-// {
-// name: 'logout',
-// alias: 'signout',
-// handler: (meta, cb) => {
-// console.log(meta)
-// cb && cb()
-// }
-// }
-// ]
-// })
-
-// shell.exec('account')
-// // console.log('---------')
-// // shell.exec('blah')
-// t.pass('ok')
-// t.end()
-// })
+test('Default command help (regression test)', t => {
+ const shell = new Shell({
+ name: 'test',
+ version: '1.0.0',
+ disableHelp: true,
+ commands: [
+ {
+ name: 'account',
+ description: 'Perform operations on a user account.',
+ handler: (meta, cb) => {},
+ commands: [
+ {
+ name: 'create',
+ description: 'Create a user account.',
+ arguments: ''
+ }
+ ]
+ }
+ ]
+ })
+
+ shell.exec('account')
+
+ t.pass('Ran without error.')
+ t.end()
+})
diff --git a/test/unit/01-sanity/02-middleware.js b/test/unit/01-sanity/02-middleware.js
new file mode 100644
index 0000000..82c0c74
--- /dev/null
+++ b/test/unit/01-sanity/02-middleware.js
@@ -0,0 +1,175 @@
+import 'source-map-support/register.js'
+import test from 'tape'
+import { Shell, Middleware } from '../../.node/index.js'
+
+test('Sync Middleware', t => {
+ const mw = new Middleware()
+
+ mw.use((m, next) => { count++; next() })
+ mw.use((m, next) => { count++; next() })
+ mw.use((m, next) => { count++; next() })
+
+ let count = 0
+ mw.run({ test: true }, () => {
+ t.ok(count === 3, `Ran 3 middleware operations. Recognized ${count}.`)
+ t.end()
+ })
+})
+
+test('Async Middleware w/ Final Method', t => {
+ const mw = new Middleware()
+
+ mw.use((m, next) => { count++; next() })
+ mw.use((m, next) => setTimeout(() => { count++; next() }, 10))
+ mw.use((m, next) => { count++; next() })
+
+ let count = 0
+ mw.run({ test: true }, () => {
+ count++
+ t.ok(count === mw.size + 1, `Ran ${mw.size + 1} total middleware operations (w/ final op) with one async operation. Recognized ${count}.`)
+ t.end()
+ })
+})
+
+test('Async Middleware w/o Final Method', t => {
+ const mw = new Middleware()
+
+ mw.use(next => { count++; next() })
+ mw.use(next => {
+ setTimeout(() => { count++; next() }, 10)
+ })
+ mw.use(next => { count++; next() })
+
+ let count = 0
+
+ mw.run()
+ setTimeout(() => {
+ t.ok(count === mw.size, `Ran ${mw.size} total middleware operations (w/o final op) with one async operation. Recognized ${count}.`)
+ t.end()
+ }, 300)
+})
+
+test('Basic Shell & Command Middleware', t => {
+ let ok = false
+
+ const shell = new Shell({
+ name: 'test',
+ commands: [{
+ name: 'a',
+ handler () {},
+ commands: [{
+ name: 'b',
+ middleware: [(meta, next) => { count++; next() }],
+ handler () {},
+ commands: [{
+ name: 'c',
+ handler () {
+ ok = true
+ }
+ }]
+ }]
+ }]
+ })
+
+ shell.use((meta, next) => { count++; next() })
+
+ let count = 0
+ shell.exec('a b c')
+
+ t.ok(count === 2, `Expected 2 middleware operations to run. Recognized ${count}.`)
+ t.ok(ok, 'Handler executes at the end.')
+ t.end()
+})
+
+test('Command Specific Middleware', t => {
+ let ok = false
+
+ const shell = new Shell({
+ name: 'test',
+ commands: [{
+ name: 'a',
+ handler () { },
+ commands: [{
+ name: 'b',
+ middleware: [(meta, next) => { count++; next() }],
+ handler () { },
+ commands: [{
+ name: 'c',
+ handler () {
+ ok = true
+ }
+ }]
+ }]
+ }]
+ })
+
+ shell.useWith(['a b'], (meta, next) => { count++; next() })
+
+ let count = 0
+ shell.exec('a b c').then(r => {
+ t.ok(count === 2, `Expected 2 middleware operations to run. Recognized ${count}.`)
+ t.ok(ok, 'Handler executes at the end.')
+ t.end()
+ })
+})
+
+// test('Regression Test: Middleware Duplication', t => {
+// let count = 0
+
+// const shell = new Shell({
+// name: 'Metadoc CLI',
+// version: '1.0.0',
+// middleware: [
+// (meta, next) => {
+// console.log('A')
+// count++
+// next()
+// }
+// ],
+// commands: [
+// {
+// name: 'account',
+// description: 'Perform operations on a user account.',
+// handler: (meta, cb) => { },
+// commands: [
+// {
+// name: 'create',
+// description: 'Create a user account.',
+// arguments: '',
+// middleware: [(d, next) => {
+// console.log('C')
+// count++
+// next()
+// }],
+// commands: [
+// {
+// name: 'bleh',
+// handler () { },
+// commands: [{
+// name: 'more',
+// handler (meta) { }
+// }]
+// }
+// ],
+// handler: (meta, cb) => { }
+// }
+// ]
+// }
+// ]
+// })
+
+// shell.use((meta, next) => {
+// setTimeout(() => {
+// console.log('B')
+// count++
+// next()
+// }, 10)
+// })
+
+// shell.exec('account create bleh').then(r => {
+// setTimeout(() => {
+// t.ok(count === 3, `Ran each middleware operation once. Expected 3 operations, recognized ${count}.`)
+// }, 300)
+// }).catch(e => t.fail(e.message))
+// .finally(() => t.end())
+// })
diff --git a/test/unit/01-sanity/03-help-defaults.js b/test/unit/01-sanity/03-help-defaults.js
new file mode 100644
index 0000000..b588265
--- /dev/null
+++ b/test/unit/01-sanity/03-help-defaults.js
@@ -0,0 +1,99 @@
+import 'source-map-support/register.js'
+import test from 'tape'
+import { Shell, Middleware } from '../../.node/index.js'
+import fs from 'fs'
+
+let msg = ''
+const cfg = () => {
+ return {
+ name: 'mycli',
+ description: 'My command line.',
+ commands: [{
+ name: 'a',
+ description: 'A fine letter.',
+ handler () { },
+ commands: [{
+ name: 'b',
+ description: 'Beautiful commands.',
+ handler () { },
+ commands: [{
+ name: 'c',
+ description: 'Choices are great.',
+ handler (meta) {
+ msg = meta.command.help
+ // msg = meta.help.message
+ }
+ }]
+ }]
+ }]
+ }
+}
+
+test('Request help via flag', t => {
+ const c = cfg()
+ const shell = new Shell(c)
+
+ shell.exec('a b c --help')
+ .then(r => {
+ // fs.writeFileSync('./test.txt', Buffer.from(msg))
+ t.ok(msg === `mycli a b c
+
+ Choices are great.`, 'Displayed correct default help message')
+ })
+ .catch(e => t.fail(e.message))
+ .finally(() => t.end())
+})
+
+test('Default help when no handler exists', t => {
+ const c = cfg()
+ delete c.commands[0].commands[0].commands[0].handler
+ const shell = new Shell(c)
+
+ shell.exec('a b c')
+ .then(r => {
+ t.ok(msg === `mycli a b c
+
+ Choices are great.`, 'Displayed correct default help message when no handler exists')
+ })
+ .catch(e => t.fail(e.message))
+ .finally(() => t.end())
+})
+
+test('Display custom help when defined', t => {
+ const c = cfg()
+ c.commands[0].commands[0].commands[0].help = () => 'custom help is awesome'
+ const shell = new Shell(c)
+
+ shell.exec('a b c')
+ .then(r => {
+ t.ok(msg === 'custom help is awesome', 'Displayed custom help message')
+ })
+ .catch(e => t.fail(e.message))
+ .finally(() => t.end())
+})
+
+test('Disabled help', t => {
+ const c = cfg()
+ c.disableHelp = true
+ const shell = new Shell(c)
+
+ shell.exec('a b c --help')
+ .then(r => {
+ // fs.writeFileSync('./test.txt', Buffer.from(msg))
+ t.ok(msg.trim() === '', `Expected no help message. Received "${msg}"`)
+ })
+ .catch(e => t.fail(e.message))
+ .finally(() => t.end())
+})
+
+test('Display custom help when defined', t => {
+ const c = cfg()
+ const shell = new Shell(c)
+
+ shell.exec('--help')
+ .then(r => {
+ t.pass('Passing --help directly to shell does not fail.')
+ })
+ .catch(e => t.fail(e.message))
+ .finally(() => t.end())
+})
From a7ea611aecd8db2dd27fc65b2eae76852d0325b3 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Fri, 1 May 2020 01:08:53 -0500
Subject: [PATCH 042/152] Removed unnecessary import (browser tests should work
now)
---
test/unit/01-sanity/03-help-defaults.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/unit/01-sanity/03-help-defaults.js b/test/unit/01-sanity/03-help-defaults.js
index b588265..a9672c3 100644
--- a/test/unit/01-sanity/03-help-defaults.js
+++ b/test/unit/01-sanity/03-help-defaults.js
@@ -1,7 +1,7 @@
import 'source-map-support/register.js'
import test from 'tape'
import { Shell, Middleware } from '../../.node/index.js'
-import fs from 'fs'
+// import fs from 'fs'
let msg = ''
const cfg = () => {
From 99d7fa5f12858fc4621ad568d2806dc75ffe89b8 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Fri, 1 May 2020 14:13:44 -0500
Subject: [PATCH 043/152] Fixed issue when help is requested and not displayed
(silent unit test failure)
---
package-lock.json | 2 +-
package.json | 2 +-
src/command.js | 6 +++++-
test/unit/01-sanity/01-sanity.js | 3 ++-
4 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index b6f859d..b8c27a0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.14",
+ "version": "1.3.15",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 17fe10c..c85703c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.14",
+ "version": "1.3.15",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/command.js b/src/command.js
index 13d5bb9..9e76c6d 100644
--- a/src/command.js
+++ b/src/command.js
@@ -398,7 +398,7 @@ export default class Command extends Base {
}
async run (input, callback) {
- const fn = (this.#fn || this.defaultHandler).bind(this)
+ let fn = (this.#fn || this.defaultHandler).bind(this)
const data = typeof input === 'string' ? this.parse(input) : input
arguments[0] = this.deepParse(input)
@@ -414,6 +414,10 @@ export default class Command extends Base {
return this.middleware.run(arguments[0], async meta => await Command.reply(fn(meta, callback)))
}
+ if (arguments[0].help && arguments[0].help.requested) {
+ return Command.reply(fn(data, () => console.log(this.help)))
+ }
+
return Command.reply(fn(data, callback))
}
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index 56ff2af..ad61253 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -1,7 +1,8 @@
import 'source-map-support/register.js'
import test from 'tape'
import { Command, Shell, Formatter } from '../../.node/index.js'
-import fs from 'fs'
+// import fs from 'fs'
+
test('Sanity Check - Shell', t => {
const shell = new Shell({
name: 'test'
From dedf9fd8367faa7c91ea22e6c0a3de85bc1d7f33 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Fri, 1 May 2020 14:37:08 -0500
Subject: [PATCH 044/152] Properly fixed the help flag and rigged up the unit
tests to output accordingly.
---
package-lock.json | 2 +-
package.json | 2 +-
src/command.js | 8 ++++----
test/unit/01-sanity/03-help-defaults.js | 8 ++++----
4 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index b8c27a0..7a9cfc1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.15",
+ "version": "1.3.16",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index c85703c..2e92898 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.15",
+ "version": "1.3.16",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/command.js b/src/command.js
index 9e76c6d..ad273a0 100644
--- a/src/command.js
+++ b/src/command.js
@@ -409,15 +409,15 @@ export default class Command extends Base {
this.middleware.use(...parentMiddleware)
}
+ if (arguments[0].help && arguments[0].help.requested) {
+ return console.log(this.help)
+ }
+
// No subcommand was recognized
if (this.middleware.size > 0) {
return this.middleware.run(arguments[0], async meta => await Command.reply(fn(meta, callback)))
}
- if (arguments[0].help && arguments[0].help.requested) {
- return Command.reply(fn(data, () => console.log(this.help)))
- }
-
return Command.reply(fn(data, callback))
}
diff --git a/test/unit/01-sanity/03-help-defaults.js b/test/unit/01-sanity/03-help-defaults.js
index a9672c3..b009089 100644
--- a/test/unit/01-sanity/03-help-defaults.js
+++ b/test/unit/01-sanity/03-help-defaults.js
@@ -36,9 +36,9 @@ test('Request help via flag', t => {
shell.exec('a b c --help')
.then(r => {
// fs.writeFileSync('./test.txt', Buffer.from(msg))
- t.ok(msg === `mycli a b c
+ t.ok(shell.getCommand('a b c').help === `mycli a b c
- Choices are great.`, 'Displayed correct default help message')
+ Choices are great.`, 'XDisplayed correct default help message')
})
.catch(e => t.fail(e.message))
.finally(() => t.end())
@@ -51,7 +51,7 @@ test('Default help when no handler exists', t => {
shell.exec('a b c')
.then(r => {
- t.ok(msg === `mycli a b c
+ t.ok(shell.getCommand('a b c').help === `mycli a b c
Choices are great.`, 'Displayed correct default help message when no handler exists')
})
@@ -80,7 +80,7 @@ test('Disabled help', t => {
shell.exec('a b c --help')
.then(r => {
// fs.writeFileSync('./test.txt', Buffer.from(msg))
- t.ok(msg.trim() === '', `Expected no help message. Received "${msg}"`)
+ t.ok(shell.getCommand('a b c').help.trim() === '', `Expected no help message. Received "${msg}"`)
})
.catch(e => t.fail(e.message))
.finally(() => t.end())
From 66439d8d8f84b277e8908e91833c76cb4b69ec34 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Fri, 1 May 2020 22:19:21 -0500
Subject: [PATCH 045/152] Added a data mapping feature that maps arguments to
unrecognized flags.
---
package.json | 2 +-
src/base.js | 12 +++-
src/command.js | 64 ++++++++++++++---
test/unit/01-sanity/04-metadata.js | 109 +++++++++++++++++++++++++++++
4 files changed, 175 insertions(+), 12 deletions(-)
create mode 100644 test/unit/01-sanity/04-metadata.js
diff --git a/package.json b/package.json
index 2e92898..7dad381 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.3.16",
+ "version": "1.4.0",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/base.js b/src/base.js
index af53180..f302203 100644
--- a/src/base.js
+++ b/src/base.js
@@ -66,13 +66,13 @@ export default class Base {
}
if (typeof cfg.arguments === 'string') {
- cfg.arguments = cfg.arguments.split(/\s+\,/)
+ cfg.arguments = cfg.arguments.split(/\s+|\t+|\,+|\;+/).map(arg => arg.trim())
}
if (Array.isArray(cfg.arguments)) {
- this.#arguments = new Set([...cfg.arguments])
+ this.#arguments = cfg.arguments
}
-
+
this.#name = (cfg.name || 'unknown').trim().split(/\s+/)[0]
this.#description = cfg.description || null
@@ -114,6 +114,12 @@ export default class Base {
this.#width = v || 80
}
},
+ arguments: {
+ enumerable: false,
+ get () {
+ return this.#arguments
+ }
+ },
initializeMiddleware: {
enumerable: false,
configurable: false,
diff --git a/src/command.js b/src/command.js
index ad273a0..c34d3c5 100644
--- a/src/command.js
+++ b/src/command.js
@@ -6,6 +6,7 @@ import Base from './base.js'
const SUBCOMMAND_PATTERN = /^([^"'][\S\b]+)[\s+]?([^-].*)$/i
const FLAG_PATTERN = /((?:"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|\/[^\/\\]*(?:\\[\S\s][^\/\\]*)*\/[gimy]*(?=\s|$)|(?:\\\s|\S))+)(?=\s|$)/g
const METHOD_PATTERN = /^([\w]+\s?)\(.*\)\s?{/i
+const STRIP_QUOTE_PATTERN = /"([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'/ig
export default class Command extends Base {
#pattern
@@ -334,13 +335,12 @@ export default class Command extends Base {
}
}
- // let source = input.replace(STRIP_EQUAL_SIGNS, '').trim() + ' '
-
const flags = Array.from(FLAG_PATTERN[Symbol.matchAll](input), x => x[0])
const parser = new Parser(flags, flagConfig)
-
- let recognized = parser.data
-
+ const pdata = parser.data
+ const recognized = {}
+
+ parser.recognizedFlags.forEach(flag => recognized[flag] = pdata[flag])
parser.unrecognizedFlags.forEach(arg => delete recognized[arg])
data.flags = { recognized, unrecognized: parser.unrecognizedFlags }
@@ -348,8 +348,8 @@ export default class Command extends Base {
data.violations = parser.violations
data.parsed = {}
- if (Object.keys(parser.data.flagSource).length > 0) {
- for (const [key, src] of Object.entries(parser.data.flagSource)) {
+ if (Object.keys(pdata.flagSource).length > 0) {
+ for (const [key, src] of Object.entries(pdata.flagSource)) {
data.parsed[src.name] = src.inputName
}
}
@@ -362,6 +362,8 @@ export default class Command extends Base {
data.help.message = this.help
}
+ const args = this.arguments
+
Object.defineProperties(data, {
flag: {
enumerable: true,
@@ -372,7 +374,7 @@ export default class Command extends Base {
if (typeof name === 'number') {
return Array.from(parser.unrecognizedFlags)[name]
} else {
- return parser.data.flagSource[name].value
+ return pdata.flagSource[name].value
}
} catch (e) {
return undefined
@@ -386,6 +388,52 @@ export default class Command extends Base {
shell: {
enumerable: true,
get: () => this.shell
+ },
+ data: {
+ enumerable: true,
+ get () {
+ let uf = parser.unrecognizedFlags
+ let result = Object.assign({}, recognized)
+ delete result.help
+
+ if (uf.length > 0) {
+ args.forEach((name, i) => {
+ let value = uf[i]
+ let normalizedValue = Object.keys(pdata).filter(key => key.toLowerCase() === value)
+ normalizedValue = (normalizedValue.length > 0 ? normalizedValue.pop() : value)
+
+ if (normalizedValue !== undefined) {
+ normalizedValue = normalizedValue.trim()
+
+ if (STRIP_QUOTE_PATTERN.test(normalizedValue)) {
+ normalizedValue = normalizedValue.substring(1, normalizedValue.length - 1)
+ }
+ }
+
+ if (result.hasOwnProperty(name)) {
+ result[name] = Array.isArray(result[name]) ? result[name]: [result[name]]
+ result[name].push(normalizedValue)
+ } else {
+ result[name] = normalizedValue
+ }
+ })
+
+ if (uf.length > args.length) {
+ uf.slice(args.length)
+ .forEach((flag, i) => {
+ let name = `unknown${i + 1}`
+ while (result.hasOwnProperty(name)) {
+ let number = name.substring(7)
+ name = 'unknown' + (parseInt(number) + 1)
+ }
+
+ result[name] = flag
+ })
+ }
+ }
+
+ return result
+ }
}
})
diff --git a/test/unit/01-sanity/04-metadata.js b/test/unit/01-sanity/04-metadata.js
new file mode 100644
index 0000000..e3c6ea2
--- /dev/null
+++ b/test/unit/01-sanity/04-metadata.js
@@ -0,0 +1,109 @@
+import 'source-map-support/register.js'
+import test from 'tape'
+import { Shell } from '../../.node/index.js'
+
+test('Map unnamed argument', t => {
+ const shell = new Shell({
+ name: 'account',
+ commands: [{
+ name: 'create',
+ arguments: 'email',
+ handler (meta) {
+ t.ok(meta.data.hasOwnProperty('email'), 'Automapped data exists.')
+ t.ok(meta.data.email === 'me@domain.com', `Attribute named email expected a value of "me@domain.com". Received "${meta.data.email}".`)
+ }
+ }]
+ })
+
+ shell.exec('create me@domain.com')
+ .catch(e => t.fail(e.message))
+ .finally(() => t.end())
+})
+
+test('Map unnamed arguments', t => {
+ const shell = new Shell({
+ name: 'account',
+ commands: [{
+ name: 'create',
+ arguments: 'email displayName',
+ handler (meta) {
+ t.ok(meta.data.hasOwnProperty('email'), 'Automapped email data exists.')
+ t.ok(meta.data.email === 'me@domain.com', `Attribute named email expected a value of "me@domain.com". Received "${meta.data.email}".`)
+ t.ok(meta.data.hasOwnProperty('displayName'), 'Automapped displayName data exists.')
+ t.ok(meta.data.displayName === 'John Doe', `Attribute named displayName expected a value of "John Doe". Received "${meta.data.displayName}".`)
+ }
+ }]
+ })
+
+ shell.exec('create me@domain.com "John Doe"')
+ .catch(e => t.fail(e.message))
+ .finally(() => t.end())
+})
+
+test('Map extra unnamed arguments as unknown', t => {
+ const shell = new Shell({
+ name: 'account',
+ commands: [{
+ name: 'create',
+ arguments: 'email displayName',
+ handler (meta) {
+ t.ok(meta.data.hasOwnProperty('email'), 'Automapped email data exists.')
+ t.ok(meta.data.email === 'me@domain.com', `Attribute named email expected a value of "me@domain.com". Received "${meta.data.email}".`)
+ t.ok(meta.data.hasOwnProperty('displayName'), 'Automapped displayName data exists.')
+ t.ok(meta.data.displayName === 'John Doe', `Attribute named displayName expected a value of "John Doe". Received "${meta.data.displayName}".`)
+ t.ok(meta.data.hasOwnProperty('unknown1'), 'Automapped unknown property to generic name.')
+ t.ok(meta.data.unknown1 === 'test1', `Unknown attribute expected a value of "test1". Received "${meta.data.unknown1}".`)
+ t.ok(meta.data.hasOwnProperty('unknown2'), 'Automapped extra unknown property to generic name.')
+ t.ok(meta.data.unknown2 === 'test2', `Extra unknown attribute expected a value of "test2". Received "${meta.data.unknown2}".`)
+ }
+ }]
+ })
+
+ shell.exec('create me@domain.com "John Doe" test1 test2')
+ .catch(e => t.fail(e.message))
+ .finally(() => t.end())
+})
+
+test('Map unnamed/unsupplied arguments as undefined', t => {
+ const shell = new Shell({
+ name: 'account',
+ commands: [{
+ name: 'create',
+ arguments: 'email displayName',
+ handler (meta) {
+ t.ok(meta.data.hasOwnProperty('email'), 'Automapped email data exists.')
+ t.ok(meta.data.email === 'me@domain.com', `Attribute named email expected a value of "me@domain.com". Received "${meta.data.email}".`)
+ t.ok(meta.data.hasOwnProperty('displayName'), 'Automapped displayName attribute exists.')
+ t.ok(meta.data.displayName === undefined, `Attribute named displayName expected a value of "undefined". Received "${meta.data.displayName}".`)
+ }
+ }]
+ })
+
+ shell.exec('create me@domain.com')
+ .catch(e => t.fail(e.message))
+ .finally(() => t.end())
+})
+
+test('Map unnamed arguments when duplicate names are supplied', t => {
+ const shell = new Shell({
+ name: 'account',
+ commands: [{
+ name: 'create',
+ flags: {
+ email: {
+ alias: 'e'
+ }
+ },
+ arguments: 'email displayName',
+ handler (meta) {
+ t.ok(meta.data.hasOwnProperty('email'), 'Automapped email data exists.')
+ t.ok(Array.isArray(meta.data.email) && meta.data.email[1] === 'me@domain.com' && meta.data.email[0] === 'bob@other.com', `Attribute named email expected a value of "['me@domain.com', 'bob@other.com']". Received "[${meta.data.email.map(i => '\'' + i + '\'').reverse().join(', ')}]".`)
+ t.ok(meta.data.displayName === undefined, `Attribute named displayName expected a value of "undefined". Received "${meta.data.displayName}".`)
+ }
+ }]
+ })
+
+ shell.exec('create me@domain.com -e bob@other.com')
+ .catch(e => t.fail(e.message))
+ .finally(() => t.end())
+})
From 4c5b51e9dc8ad97cf69d62b16b8d5b37df52b6a6 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sat, 2 May 2020 23:37:25 -0500
Subject: [PATCH 046/152] Added 'postware' concept, universal flags, and
upgraded the arg library to support the new validate attribute. Updated docs
to reflect this.
---
README.md | 333 +++++++++++++++++++++---
package-lock.json | 14 +-
package.json | 4 +-
src/base.js | 85 +++++-
src/command.js | 74 ++++--
src/format.js | 9 +-
src/shell.js | 15 +-
test/unit/01-sanity/02-middleware.js | 42 ++-
test/unit/01-sanity/03-help-defaults.js | 2 +-
test/unit/01-sanity/05-commonflags.js | 90 +++++++
10 files changed, 576 insertions(+), 92 deletions(-)
create mode 100644 test/unit/01-sanity/05-commonflags.js
diff --git a/README.md b/README.md
index 89c4091..267cc8e 100644
--- a/README.md
+++ b/README.md
@@ -40,44 +40,10 @@ Multipurpose tools require a layer of organizational overhead to help isolate di
Sometimes single purpose tools grow into multipurpose tools over time. Tools which start out using the `@author.io/arg` library can be transitioned into multipurpose tools using `@author.io/shell` (with reasonable ease). After all, they use the same code, just nicely separated by purpose.
-## Installation & Usage
-
-### For Modern Node (ES Modules)
-
-`npm install @author.io/node-shell`
-
-Please note, you'll need a verison of Node that supports ES Modules. In Node 12, this feature is behind the `--experimental-modules` flag. It is available in Node 13+ without a flag, but your `package.json` file must have the `"type": "module"` attribute. This feature is generally available as of [Node 14.0.0](https://nodejs.org).
-
-### For Legacy Node (CommonJS/require)
-
-If you need to use the older CommonJS format (i.e. `require`), run `npm install @author.io/node-shell-legacy` instead.
-
-### For Browsers
-
-**CDN**
-
-```javascript
-import { Shell, Command } from 'https://cdn.pika.dev/@author.io/browser-shell'
-```
-
-Also available from [jsdelivr](https://www.jsdelivr.com/package/npm/@author.io/browser-shell) and [unpkg](https://unpkg.com/@author.io/browser-shell).
-
-**npm options**
-
-If you wish to bundle this library in your build process, use the version most appropriate for your target runtimes:
-
-- `npm install @author.io/browser-shell` (Minified ES Module)
-- `npm install @author.io/browser-shell-es6` (IIFE Minified Module - globally accessible)
-- `npm install @author.io/shell` (source)
-
-**TAKE NOTICE: The source may not be what you think it is.** The source code may contain Node or browser code that is stripped out during the build process. We have a goal of making the _API_ runtime-agnostic, not the implementation. We do everything we can to avoid runtime-specific source code though, and it is rare to have node or browser-specific source code... we just can't guarantee the source will be easily embeddable. We recommend consuming the prebuilt editions.
-
-### Debugging
-
-Each distribution has a corresponding `-debug` version that should be installed _alongside_ the main module (the debugging is an add-on module). For example, `npm install @author.io/node-shell-debug --save-dev` would install the debugging code for Node.
-
## Basic Examples
+See the [Installation Guide](#installation) when you're ready to get started.
+
There is a complete working example of a CLI app (with a mini tutorial) in the examples directory.
_This example imports the library for Node. Simply swap the Node import for the appropriate browser import if you're building a web utility. Everything else is the same for both Node and browser environments._
@@ -90,8 +56,8 @@ const ListCommand = new Command({
name: 'list',
description: 'List the contents of the directory.',
disableHelp: false, // Set to true to turn off default help messages for the entire shell (you can still provide your own). Defaults to false.
- // arguments are listed after the command in the default help screen. Ex: "dir list "
- arguments: '',
+ // arguments are listed after the command in the default help screen. Ex: "dir list path"
+ arguments: 'path', // Can be space/comma/tab/semicolon delimited or an array.
alias: 'ls',
// Any flag parsing options from the @author.io/arg library can be configured here.
// See https://github.com/author/arg#configuration-methods for a list.
@@ -105,7 +71,8 @@ const ListCommand = new Command({
rootDir: {
description: 'The root directory to list.',
aliases: ['input', 'in', 'src'],
- single: true
+ single: true,
+ // validate: RegExp/Function (see github.com/author/arg)
}
},
handler (metadata, callback) {
@@ -125,7 +92,8 @@ const ListCommand = new Command({
// },
// valid: false,
// violations: [],
- // flag (name) { return String }
+ // flag (name) { return String },
+ // data (getter)
// }
console.log(metadata)
@@ -148,10 +116,19 @@ const shell = new Shell({
name: 'myapp',
version: '1.0.0',
description: 'My demo app.',
+ // This middleware runs before all command handlers.
+ use: [
+ (meta, next) => { ...; next() }
+ ],
+ // Trailers are like "post-middleware" that run after command handlers.
+ trailer: [
+ (meta, next) => { ...; next() }
+ (meta, next) => { console.log('All done!') }
+ ],
commands: [
// These can be instances of Command...
list,
-
+
// or just the configuration of a Command
{
name: 'find',
@@ -221,7 +198,10 @@ Each command has a handler function, which is responsible for doing something. T
- **`flag()`** is a special method for retrieving the value of any flag (recognized or unrecognized). See below.
- **valid** indicates whether the input conforms to the parsing rules.
- **violations** is an array of strings, where each string represents a violation of the parsing rules.
+- **data** _(getter)_ returns a key/value object with all of the known flags, as well as an _attempt_ to map any unrecognized flags with known argument names. (See basic example for argument example)
+
+Understanding flag()
_The `flag()` method_ is a shortcut to help developers create more maintainable and understandable code. Consider the following example that does **not** use the flag method:
```javascript
@@ -255,6 +235,179 @@ const cmd = new Command({
```
While the differences aren't extreme, it abstracts the need to know whether a flag is recognized or not (or even exists). If a `flag()` is executed for a non-existant flag, it will return `null`.
+
+
+
+Understanding data
+The `data` attribute supplied to handlers in the metadata argument contains the values for known flags, and _**attempts to map unknown arguments** to configured argument names_.
+
+For example,
+
+```javascript
+const shell = new Shell({
+ name: 'account',
+ commands: [{
+ name: 'create',
+ arguments: 'email displayName',
+ handler (meta) {
+ console.log(meta.data)
+ }
+ }]
+})
+
+shell.exec('create me@domain.com "John Doe" test1 test2')
+```
+
+_Output:_
+
+```json
+{
+ "email": "me@domain.com",
+ "displayName": "John Doe",
+ "unknown1": "test1",
+ "unknown2": "test2
+}
+```
+
+If there is a name conflict, the output will contain an array of values. For example:
+
+```javascript
+const shell = new Shell({
+ name: 'account',
+ commands: [{
+ name: 'create',
+ arguments: 'email displayName',
+ flags: {
+ email: {
+ alias: 'e'
+ }
+ },
+ handler (meta) {
+ console.log(meta.data)
+ }
+ }]
+})
+
+shell.exec('create me@domain.com -e bob@other.com')
+```
+
+_Output:_
+
+```json
+{
+ "email": ["bob@other.com", "me@domain.com"],
+ "displayName": "John Doe",
+}
+```
+
+> Notice the values from the known flags are _first_.
+
+
+## Universal Flags
+_Common flags are automatically applied to multiple commands._
+
+Sometimes a CLI app has multiple commands/subcommands that need the same flag associated with each command/subcommand. For example, if a `--note` flag were needed on every command, it would be a pain to copy/paste the config into every single command. Common flags resolve this by automatically applying to all commands from the point where the common flag is configured (i.e. the point where inheritance/nesting begins).
+
+
+Apply a common flag to ALL commands
+To include the same flag on all commands, add a common flag to the shell.
+
+```javascript
+const shell = new Shell({
+ name: 'mycli',
+ commmonflags: {
+ note: {
+ alias: 'n',
+ description: 'Save a note about the operation.'
+ }
+ },
+ commands: [{
+ name: 'create',
+ flag: {
+ writable: {
+ alias: 'w',
+ description: 'Make it writable.'
+ }
+ },
+ ...
+ }, {
+ name: 'read',
+ ...
+ }]
+})
+
+shell.exec('create --help')
+shell.exec('read --help')
+```
+
+create output:
+```sh
+mycli create
+
+Flags:
+ note [-n] Save a note about the operation.
+ writable [-w] Make it writable.
+```
+
+read` output:
+```sh
+mycli read
+
+Flags:
+ note [-n] Save a note about the operation.
+```
+
+
+
+Apply a common flag to a specific command/subcommands
+
+```javascript
+const shell = new Shell({
+ name: 'mycli',
+ commands: [{
+ name: 'create',
+ commmonflags: {
+ note: {
+ alias: 'n',
+ description: 'Save a note about the operation.'
+ }
+ },
+ flag: {
+ writable: {
+ alias: 'w',
+ description: 'Make it writable.'
+ }
+ },
+ commands: [...]
+ ...
+ }, {
+ name: 'read',
+ description: 'Read a directory.',
+ ...
+ }]
+})
+
+shell.exec('create --help')
+shell.exec('read --help')
+```
+
+_`create` output:_
+```sh
+mycli create
+
+Flags:
+ note [-n] Save a note about the operation.
+ writable [-w] Make it writable.
+```
+
+_`read` output:_
+```sh
+mycli read
+
+ Read a directory.
+
+```
+
## Middleware
@@ -368,11 +521,58 @@ const v = new Command({
shell.add(v)
```
-### Other Middleware
+### Middleware Libraries
One development goal of this framework is to remain as lightweight and unopinionated as possible. Another is to be as simple to use as possible. These two goals often conflict with each other (the more features you add, the heavier it becomes). In an attempt to find a comfortable balance, some additional middleware libraries are available for those who want a little extra functionality.
1. [@author.io/shell-middleware](https://github.com/author/shell-middleware)
+1. Submit a PR to add yours here.
+
+### Trailers
+_(Postware/Afterware)_
+
+Trailers operate just like middleware, but they execute _after_ the command handler is executed.
+
+```javascript
+const shell = new Shell({
+ name: 'mycli',
+ trailer: [
+ function () { console.log('Done!' ) }
+ ],
+ command: [{
+ name: 'dir',
+ handler () {
+ console.log('ls -l')
+ },
+ // Subcommands
+ commands: [{
+ name: 'perm',
+ description: 'Permissions',
+ handler () {
+ console.log('Display permissions for a directory.')
+ }
+ }]
+ }]
+})
+
+// Execute the "dir" command
+shell.exec('dir')
+
+// Execute the "perm" subcommand
+shell.exec('dir perm')
+```
+
+_`dir` command output:_
+```sh
+ls -l
+Done!
+```
+
+_`dir perm` subcommand output:_
+```sh
+Display permissions for a directory.
+Done!
+```
### Customized Help/Usage Messages
@@ -428,6 +628,55 @@ console.log(shell.data)
Simple CLI utilities can also be loaded entirely from a JSON file by passing the object into the shell constructor as the only argument. The limitation is no imports or hoisted variables/methods will be recognized in a shell which is loaded this way.
+## Installation
+
+### Node.js
+
+
+Modern (ES Modules)
+
+
+```sh
+npm install @author.io/node-shell
+```
+
+Please note, you'll need a verison of Node that supports ES Modules. In Node 12, this feature is behind the `--experimental-modules` flag. It is available in Node 13+ without a flag, but your `package.json` file must have the `"type": "module"` attribute. This feature is generally available as of [Node 14.0.0](https://nodejs.org).
+
+
+
+Legacy (CommonJS/require)
+
+
+If you need to use the older CommonJS format (i.e. `require`), run `npm install @author.io/node-shell-legacy` instead.
+
+
+### Browsers
+
+**CDN**
+
+```javascript
+import { Shell, Command } from 'https://cdn.pika.dev/@author.io/browser-shell'
+```
+
+Also available from [jsdelivr](https://www.jsdelivr.com/package/npm/@author.io/browser-shell) and [unpkg](https://unpkg.com/@author.io/browser-shell).
+
+
+npm options
+
+
+If you wish to bundle this library in your build process, use the version most appropriate for your target runtimes:
+
+- `npm install @author.io/browser-shell` (Minified ES Module)
+- `npm install @author.io/browser-shell-es6` (IIFE Minified Module - globally accessible)
+- `npm install @author.io/shell` (source)
+
+**TAKE NOTICE: The source may not be what you think it is.** The source code may contain Node or browser code that is stripped out during the build process. We have a goal of making the _API_ runtime-agnostic, not the implementation. We do everything we can to avoid runtime-specific source code though, and it is rare to have node or browser-specific source code... we just can't guarantee the source will be easily embeddable. We recommend consuming the prebuilt editions.
+
+
+### Debugging
+
+Each distribution has a corresponding `-debug` version that should be installed _alongside_ the main module (the debugging is an add-on module). For example, `npm install @author.io/node-shell-debug --save-dev` would install the debugging code for Node.
+
### Related Modules
1. [@author.io/table](https://github.com/author/table) - Used to generate the default usage/help messages for the shell and subcommands.
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 7a9cfc1..3942fd5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,18 +1,18 @@
{
"name": "@author.io/shell",
- "version": "1.3.16",
+ "version": "1.5.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@author.io/arg": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.2.5.tgz",
- "integrity": "sha512-i+6F2ViIojVDqs+GS6Att/79SPDvdTijYzNg0VmNXF/03MIPWKnVwyRLOCpTx0pRjZNa3WQJwGZ3vqGN36lG1w=="
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.0.tgz",
+ "integrity": "sha512-lKVMWqhVjqLVKvNfMmb9feC7BE/s3xc6wr+ZQrryx1KsudknLXLDafVEbJbiKHTQMWwGqBobHhX0Bme/GFShOA=="
},
"@author.io/table": {
- "version": "1.0.0-beta.4",
- "resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.0.0-beta.4.tgz",
- "integrity": "sha512-EHKSpNDsejV4U5284UxoJtJW41aTHQJKyPUUzyl0x+AAq6F5wzmrXHun/MmfsxF+I/pZyXaUscPhMpanJVThcg=="
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.0.1.tgz",
+ "integrity": "sha512-WbLWxBtZOSUeXFTQQO/OINifAFYJtU6pwTrh8b0gdqLRkQRoaHM3ymEa+KYbLuCbbexMt8oULDXbIyY88h/0zw=="
}
}
}
diff --git a/package.json b/package.json
index 7dad381..23b3e49 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.4.0",
+ "version": "1.5.0",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
@@ -51,7 +51,7 @@
]
},
"dependencies": {
- "@author.io/arg": "^1.2.6",
+ "@author.io/arg": "^1.3.0",
"@author.io/table": "^1.0.1"
}
}
diff --git a/src/base.js b/src/base.js
index f302203..bcdd803 100644
--- a/src/base.js
+++ b/src/base.js
@@ -15,6 +15,8 @@ export default class Base {
#width = 80
#name = 'Unknown'
#middleware = new Middleware()
+ #trailer = new Middleware()
+ #commonflags = {}
#hasCustomDefaultHandler = false
#defaultHandler = function (meta) {
if (this.parent !== null && this.parent.hasCustomDefaultHandler) {
@@ -86,27 +88,51 @@ export default class Base {
}
}
+ if (cfg.hasOwnProperty('middleware')) {
+ console.warn('The "middleware" attribute has been replaced with the "use" attribute.')
+ cfg.use = cfg.middleware
+ delete cfg.middleware
+ }
+
+ if (!cfg.hasOwnProperty('commonflag')) {
+ if (cfg.hasOwnProperty('commonFlag')) {
+ cfg.commonflag = cfg.commonFlag
+ } else if (cfg.hasOwnProperty('commonflags')) {
+ cfg.commonflag = cfg.commonflags
+ } else if (cfg.hasOwnProperty('commonFlag')) {
+ cfg.commonflag = cfg.commonFlag
+ } else if (cfg.hasOwnProperty('commonFlags')) {
+ cfg.commonflag = cfg.commonFlags
+ }
+ }
+
+ if (cfg.hasOwnProperty('commonflag')) {
+ if (typeof cfg.commonflag !== 'object') {
+ throw new Error('The "commonflag" configuration attribute must be an object.')
+ }
+ }
+
Object.defineProperties(this, {
__arguments: {
- enumerable: true,
+ enumerable: false,
get() {
return this.#arguments
}
},
__processors: {
- enumerable: true,
+ enumerable: false,
get() {
return this.#processors
}
},
__commands: {
- enumerable: true,
+ enumerable: false,
get() {
return this.#commands
}
},
__width: {
- enumerable: true,
+ enumerable: false,
get() {
return this.#width
},
@@ -114,6 +140,15 @@ export default class Base {
this.#width = v || 80
}
},
+ __commonflags: {
+ enumerable: false,
+ get () {
+ return this.#commonflags
+ },
+ set (value) {
+ this.#commonflags = value
+ }
+ },
arguments: {
enumerable: false,
get () {
@@ -133,6 +168,20 @@ export default class Base {
throw new Error('Invalid middleware: ' + code.toString())
}
}
+ },
+ initializeTrailer: {
+ enumerable: false,
+ configurable: false,
+ writable: false,
+ value: code => {
+ if (typeof code === 'string') {
+ this.trailer(Function('return ' + code)())
+ } else if (typeof code === 'function') {
+ this.trailer(code)
+ } else {
+ throw new Error('Invalid trailer: ' + code.toString())
+ }
+ }
}
})
}
@@ -235,6 +284,18 @@ export default class Base {
return commands
}
+ get middleware() {
+ return this.#middleware
+ }
+
+ get trailers () {
+ return this.#trailer
+ }
+
+ get commands() {
+ return this.#processors
+ }
+
getCommand(name = null) {
if (!name) {
return null
@@ -280,12 +341,18 @@ export default class Base {
this.#processors.forEach(subCmd => subCmd.use(...arguments))
}
- get middleware () {
- return this.#middleware
- }
+ trailer () {
+ this.#trailer = this.#trailer || new Middleware()
- get commands() {
- return this.#processors
+ for (const arg of arguments) {
+ if (typeof arg !== 'function') {
+ throw new Error(`All "trailer()" arguments must be valid functions.\n${arg.toString().substring(0, 50)} ${arg.toString().length > 50 ? '...' : ''}`)
+ }
+
+ this.#trailer.use(arg)
+ }
+
+ this.#processors.forEach(subCmd => subCmd.trailer(...arguments))
}
add () {
diff --git a/src/command.js b/src/command.js
index c34d3c5..782f420 100644
--- a/src/command.js
+++ b/src/command.js
@@ -13,7 +13,7 @@ export default class Command extends Base {
#oid
#aliases = new Set()
#fn
- #flagConfig = null
+ #flagConfig = {}
#parent = null
#shell = null
@@ -30,8 +30,12 @@ export default class Command extends Base {
super(cfg)
- if (cfg.hasOwnProperty('middleware') && Array.isArray(cfg.middleware)) {
- cfg.middleware.forEach(code => this.initializeMiddleware(code))
+ if (cfg.hasOwnProperty('use') && Array.isArray(cfg.use)) {
+ cfg.use.forEach(code => this.initializeMiddleware(code))
+ }
+
+ if (cfg.hasOwnProperty('trailer') && Array.isArray(cfg.trailer)) {
+ cfg.trailer.forEach(code => this.initializeTrailer(code))
}
this.#fn = cfg.handler
@@ -97,25 +101,37 @@ export default class Command extends Base {
'name',
'handler',
'middleware',
- 'arguments'
+ 'use',
+ 'arguments',
+ 'commonflag',
+ 'commonflags',
+ 'trailer'
])
const unrecognized = Object.keys(cfg).filter(attribute => !attributes.has(attribute))
if (unrecognized.length > 0) {
- throw new Error(`Unrecognized shell configuration attribute(s): ${unrecognized.join(', ')}`)
+ throw new Error(`Unrecognized configuration attribute(s): ${unrecognized.join(', ')}`)
}
Object.defineProperties(this, {
- __flagConfig: {
+ __commonFlags: {
enumerable: false,
get () {
- const flags = new Map()
- if (this.#flagConfig !== null) {
- Object.keys(this.#flagConfig).forEach(key => flags.set(key, this.#flagConfig[key]))
- flags.delete('help')
+ let flags = Object.assign({}, this.__commonflags, this.#flagConfig)
+
+ if (this.parent !== null) {
+ flags = Object.assign(flags, this.parent.__commonFlags)
}
+ return Object.assign({}, this.shell.__commonflags, flags)
+ }
+ },
+ __flagConfig: {
+ enumerable: false,
+ get () {
+ let flags = new Map(Object.entries(Object.assign(this.__commonFlags, this.#flagConfig || {})))
+ flags.delete('help')
return flags
}
},
@@ -146,6 +162,8 @@ export default class Command extends Base {
}
})
+ this.__commonflags = cfg.commonflags || {}
+
this.__width = this.shell === null ? 80 : this.shell.tableWidth || 80
this.updateHelp()
@@ -159,7 +177,7 @@ export default class Command extends Base {
handler = handler.replace(METHOD_PATTERN.exec(handler)[1], 'function ')
}
- let flags = this.#flagConfig || {}
+ let flags = Object.assign(this.__commonFlags, this.#flagConfig || {})
for (let [key, value] of Object.entries(flags)) {
value.aliases = value.aliases || []
@@ -182,7 +200,9 @@ export default class Command extends Base {
flags,
handler,
commands,
- middleware: this.middleware.data
+ disableHelp: !this.autohelp,
+ use: this.middleware.data,
+ trailer: this.trailers.data
}
for (let [key, value] of Object.entries(data.flags)) {
@@ -287,7 +307,6 @@ export default class Command extends Base {
}
}
- this.#flagConfig = this.#flagConfig || {}
this.#flagConfig[name] = cfg
}
@@ -324,7 +343,7 @@ export default class Command extends Base {
// Parse the command input for flags
const data = { command: this.name, input: input.trim() }
- let flagConfig = this.#flagConfig || {}
+ let flagConfig = Object.assign(this.__commonFlags, this.#flagConfig || {})
if (!flagConfig.hasOwnProperty('help')) {
flagConfig.help = {
@@ -339,7 +358,7 @@ export default class Command extends Base {
const parser = new Parser(flags, flagConfig)
const pdata = parser.data
const recognized = {}
-
+
parser.recognizedFlags.forEach(flag => recognized[flag] = pdata[flag])
parser.unrecognizedFlags.forEach(arg => delete recognized[arg])
@@ -457,16 +476,34 @@ export default class Command extends Base {
this.middleware.use(...parentMiddleware)
}
+ let trailers = this.trailers
+
if (arguments[0].help && arguments[0].help.requested) {
- return console.log(this.help)
+ console.log(this.help)
+
+ if (trailers.size > 0) {
+ trailers.run(arguments[0])
+ }
+
+ return
}
// No subcommand was recognized
if (this.middleware.size > 0) {
- return this.middleware.run(arguments[0], async meta => await Command.reply(fn(meta, callback)))
+ this.middleware.run(arguments[0], async meta => await Command.reply(fn(meta, callback)))
+
+ if (trailers.size > 0) {
+ trailers.run(arguments[0])
+ }
+
+ return
}
- return Command.reply(fn(data, callback))
+ Command.reply(fn(data, callback))
+
+ if (trailers.size > 0) {
+ trailers.run(arguments[0])
+ }
}
static stderr (err) {
@@ -483,6 +520,7 @@ export default class Command extends Base {
if (typeof callback === 'function') {
callback()
}
+
resolve()
} catch (e) {
reject(e)
diff --git a/src/format.js b/src/format.js
index ab50901..976a686 100644
--- a/src/format.js
+++ b/src/format.js
@@ -29,7 +29,7 @@ class Formatter {
if (this.#data instanceof Command) {
const aliases = this.#data.aliases
- const out = [`${this.#data.commandroot}${aliases.length > 0 ? '|' + aliases.join('|') : ''}${this.#data.__flagConfig.size > 0 ? ' [FLAGS]' : ''}${this.#data.__arguments.size > 0 ? ' ' + Array.from(this.#data.__arguments).join(', ') : ''}`]
+ const out = [`${this.#data.commandroot}${aliases.length > 0 ? '|' + aliases.join('|') : ''}${this.#data.__flagConfig.size > 0 ? ' [FLAGS]' : ''}${this.#data.__arguments.size > 0 ? ' ' + Array.from(this.#data.__arguments).map(i => '<' + i + '>').join(', ') : ''}`]
if (desc.trim().length > 0 && out !== desc) {
out.push(new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output)
@@ -37,7 +37,7 @@ class Formatter {
return out.join('\n')
} else if (this.#data instanceof Shell) {
- return `${this.#data.name}${this.#data.__processors.size > 0 ? ' [COMMAND]' : ''}\n${desc.trim().length > 0 ? new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output : ''}${this.#data.__arguments.size > 0 ? ' ' + Array.from(this.#data.__arguments).join(', ') : ''}\n`.trim()
+ return `${this.#data.name}${this.#data.__processors.size > 0 ? ' [COMMAND]' : ''}\n${desc.trim().length > 0 ? new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output : ''}${this.#data.__arguments.size > 0 ? ' ' + Array.from(this.#data.__arguments).map(i => '[' + i + ']').join(', ') : ''}\n`.trim()
}
return ''
@@ -52,14 +52,13 @@ class Formatter {
if (flags.size > 0) {
flags.forEach((cfg, flag) => {
- let aliases = Array.from(cfg.aliases||[])
+ let aliases = Array.from(cfg.aliases||cfg.alias||[])
aliases = aliases.length === 0 ? '' : '[' + aliases.map(a => `-${a}`).join(', ') + ']'
- rows.push(['-' + flag, aliases, cfg.description])
+ rows.push(['-' + flag, aliases || '', cfg.description || ''])
})
}
const table = new Table(rows, this.#colAlign, this.#colWidth, this.#tableWidth, [2, 0, usage.length > 0 ? 1 : 0, 0])
-
return usage + (flags.size > 0 ? '\n\nFlags:' + table.output : '')
} else if (this.#data instanceof Shell) {
const rows = Array.from(this.#data.__processors.values()).map(cmd => {
diff --git a/src/shell.js b/src/shell.js
index eb68754..193d4b4 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -23,8 +23,14 @@ export default class Shell extends Base {
constructor (cfg = { maxhistory: 100 }) {
super(cfg)
- if (cfg.hasOwnProperty('middleware') && Array.isArray(cfg.middleware)) {
- cfg.middleware.forEach(code => this.initializeMiddleware(code))
+ this.__commonflags = cfg.commonflags || {}
+
+ if (cfg.hasOwnProperty('use') && Array.isArray(cfg.use)) {
+ cfg.use.forEach(code => this.initializeMiddleware(code))
+ }
+
+ if (cfg.hasOwnProperty('trailer') && Array.isArray(cfg.trailer)) {
+ cfg.trailer.forEach(code => this.initializeTrailer(code))
}
this.#version = cfg.version || '1.0.0'
@@ -40,11 +46,12 @@ export default class Shell extends Base {
description: this.description,
version: this.version,
commands,
- middleware: this.middleware.data,
+ use: this.middleware.data,
+ trailer: this.trailers.data,
help: this.help,
usage: this.usage,
defaultHandler: this.defaultHandler.toString(),
- authohelp: this.autohelp,
+ disableHelp: !this.autohelp,
runtime: this.#runtime,
maxHistoryItems: this.#maxHistoryItems
}
diff --git a/test/unit/01-sanity/02-middleware.js b/test/unit/01-sanity/02-middleware.js
index 82c0c74..32b2dc4 100644
--- a/test/unit/01-sanity/02-middleware.js
+++ b/test/unit/01-sanity/02-middleware.js
@@ -59,7 +59,7 @@ test('Basic Shell & Command Middleware', t => {
handler () {},
commands: [{
name: 'b',
- middleware: [(meta, next) => { count++; next() }],
+ use: [(meta, next) => { count++; next() }],
handler () {},
commands: [{
name: 'c',
@@ -91,7 +91,7 @@ test('Command Specific Middleware', t => {
handler () { },
commands: [{
name: 'b',
- middleware: [(meta, next) => { count++; next() }],
+ use: [(meta, next) => { count++; next() }],
handler () { },
commands: [{
name: 'c',
@@ -113,13 +113,47 @@ test('Command Specific Middleware', t => {
})
})
+test('Basic Trailers', t => {
+ let ok = false
+ let after = 0
+
+ const shell = new Shell({
+ name: 'test',
+ commands: [{
+ name: 'a',
+ handler () { },
+ commands: [{
+ name: 'b',
+ use: [(meta, next) => { next() }],
+ handler () { },
+ commands: [{
+ name: 'c',
+ handler () {
+ ok = true
+ },
+ trailer: [
+ (meta, next) => { after++; next() },
+ meta => {
+ t.ok(after === 1, `Expected 1 trailer to run. Recognized ${after}.`)
+ t.pass('Ran trailer.')
+ t.end()
+ }
+ ]
+ }]
+ }]
+ }]
+ })
+
+ shell.exec('a b c')
+})
+
// test('Regression Test: Middleware Duplication', t => {
// let count = 0
// const shell = new Shell({
// name: 'Metadoc CLI',
// version: '1.0.0',
-// middleware: [
+// use: [
// (meta, next) => {
// console.log('A')
// count++
@@ -136,7 +170,7 @@ test('Command Specific Middleware', t => {
// name: 'create',
// description: 'Create a user account.',
// arguments: '',
-// middleware: [(d, next) => {
+// use: [(d, next) => {
// console.log('C')
// count++
// next()
diff --git a/test/unit/01-sanity/03-help-defaults.js b/test/unit/01-sanity/03-help-defaults.js
index b009089..0480f11 100644
--- a/test/unit/01-sanity/03-help-defaults.js
+++ b/test/unit/01-sanity/03-help-defaults.js
@@ -38,7 +38,7 @@ test('Request help via flag', t => {
// fs.writeFileSync('./test.txt', Buffer.from(msg))
t.ok(shell.getCommand('a b c').help === `mycli a b c
- Choices are great.`, 'XDisplayed correct default help message')
+ Choices are great.`, 'Displayed correct default help message')
})
.catch(e => t.fail(e.message))
.finally(() => t.end())
diff --git a/test/unit/01-sanity/05-commonflags.js b/test/unit/01-sanity/05-commonflags.js
new file mode 100644
index 0000000..0145bd3
--- /dev/null
+++ b/test/unit/01-sanity/05-commonflags.js
@@ -0,0 +1,90 @@
+import 'source-map-support/register.js'
+import test from 'tape'
+import { Shell } from '../../.node/index.js'
+
+test('Common flags (entire shell)', t => {
+ const shell = new Shell({
+ name: 'account',
+ commonflags: {
+ typical: {
+ alias: 't',
+ description: 'A typical flag on all commands.',
+ default: true
+ }
+ },
+ commands: [{
+ name: 'create',
+ handler (meta) {
+ t.ok(meta.flag('typical'), `Retrieved common flag value. Expected true, received ${meta.flag('typical')}`)
+ }
+ }]
+ })
+
+ shell.exec('create')
+ .catch(e => t.fail(e.message))
+ .finally(() => t.end())
+})
+
+test('Common flags (command-specific)', t => {
+ const shell = new Shell({
+ name: 'account',
+ commonflags: {
+ typical: {
+ alias: 't',
+ description: 'A typical flag on all commands.',
+ default: true
+ }
+ },
+ commands: [{
+ name: 'create',
+ handler (meta) {
+ t.ok(meta.flag('typical'), `Retrieved common flag value. Expected true, received ${meta.flag('typical')}`)
+ },
+ commands: [{
+ name: 'noop',
+ handler (meta) {
+ t.ok(
+ meta.flags.recognized.hasOwnProperty('typical') &&
+ !meta.flags.recognized.hasOwnProperty('org')
+ , 'Recognized global flag but not those of other commands.'
+ )
+ }
+ }, {
+ name: 'account',
+ commonflags: {
+ org: {
+ alias: 'o',
+ description: 'Indicates the account is for an org.',
+ type: Boolean,
+ default: false
+ }
+ },
+ commands: [{
+ name: 'test',
+ flags: {
+ any: {
+ alias: 'a',
+ description: 'a'
+ }
+ },
+ handler (meta) {
+ t.ok(
+ meta.flags.recognized.hasOwnProperty('typical') &&
+ meta.flags.recognized.hasOwnProperty('org') &&
+ meta.flags.recognized.hasOwnProperty('any'),
+ 'Expected 3 flags (inherited)'
+ )
+ }
+ }]
+ }]
+ }]
+ })
+
+ shell.exec('create account test')
+ .then(r => {
+ shell.exec('create noop')
+ .catch(e => console.log(e.stack) && t.fail(e.message))
+ .finally(() => t.end())
+ })
+ .catch(e => console.log(e.stack) && t.fail(e.message) && t.end())
+})
From fb4e88a5686bfe2d8d76351fe773ff6de2df98fc Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sun, 3 May 2020 00:02:46 -0500
Subject: [PATCH 047/152] Cleaned up README
---
README.md | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/README.md b/README.md
index 267cc8e..4d8e5b1 100644
--- a/README.md
+++ b/README.md
@@ -30,16 +30,42 @@ There are two types of text-based apps:
**tl;dr** Use this library to create multipurpose tools. Use [@author.io/arg](https://github.com/author/arg) to create single purpose tools.
+
+Detailed Explanation
+
+
This framework was designed to support multipurpose CLI tools. At the core, it provides a clean, easily-understood, repeatable pattern for building maintainable multipurpose CLI applications.
Multipurpose tools require a layer of organizational overhead to help isolate different commands and features. This overhead is unnecessary in single purpose tools. Single purpose tools just need argument parsing, which the [@author.io/arg](https://github.com/author/arg) does very well.
`@author.io/arg` is embedded in this framework, making `@author.io/shell` _capable_ of creating single purpose tools, but it's merely unnecessary overhead for single purpose commands.
+
+
**Think about how your tooling evolves...**
Sometimes single purpose tools grow into multipurpose tools over time. Tools which start out using the `@author.io/arg` library can be transitioned into multipurpose tools using `@author.io/shell` (with reasonable ease). After all, they use the same code, just nicely separated by purpose.
+## Differentiating Features
+
+1. Supports **middleware** (express-style)
+1. Supports **postware** (middleware that runs after a command)
+1. **Customizable** help/usage screens
+1. **Introspectable**: Produces/consumes JSON (load a compatible JSON file and have a working CLI)
+1. Dynamically add/remove commands.
+1. Command/execution **history** tracking
+1. **Universal flags**: define a flag once, reuse everywhere.
+
+
+Also has better source & distribution code
+
+1. Cross-runtime (browser & node)
+1. Separation of Concerns: Arg parsing and text formatting are separate microlibs.
+1. Modern ES Module syntax
+1. 40+ unit tests
+
+
+
## Basic Examples
See the [Installation Guide](#installation) when you're ready to get started.
From f1b1f7086e9ecaa1f86ad656c9dbf0ce27645469 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sun, 3 May 2020 00:04:05 -0500
Subject: [PATCH 048/152] Cleaned up README
---
README.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 4d8e5b1..41de215 100644
--- a/README.md
+++ b/README.md
@@ -228,7 +228,9 @@ Each command has a handler function, which is responsible for doing something. T
Understanding flag()
-_The `flag()` method_ is a shortcut to help developers create more maintainable and understandable code. Consider the following example that does **not** use the flag method:
+
+
+The `flag()` method is a shortcut to help developers create more maintainable and understandable code. Consider the following example that does **not** use the flag method:
```javascript
const cmd = new Command({
From 115eb46b02ecf750fec16cffde590f75fc62d84f Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sun, 3 May 2020 19:27:37 -0500
Subject: [PATCH 049/152] Added configuration attributes for customizing flag
help message output.
---
README.md | 46 +-
examples/cli/index.js | 2 +-
examples/cli/package.json | 5 +-
package-lock.json | 1480 ++++++++++++++++++++++++++++++++++++-
package.json | 2 +-
src/base.js | 69 +-
src/command.js | 6 +
src/format.js | 29 +-
src/shell.js | 2 +
9 files changed, 1623 insertions(+), 18 deletions(-)
diff --git a/README.md b/README.md
index 41de215..a53b526 100644
--- a/README.md
+++ b/README.md
@@ -72,7 +72,7 @@ See the [Installation Guide](#installation) when you're ready to get started.
There is a complete working example of a CLI app (with a mini tutorial) in the examples directory.
-_This example imports the library for Node. Simply swap the Node import for the appropriate browser import if you're building a web utility. Everything else is the same for both Node and browser environments._
+_This example imports the library for Node. Simply swap the Node import for the appropriate browser import if you're building a web utility. Everything else is the same for both Node and browser environments._
```javascript
import { Shell, Command } from '@author.io/node-shell'
@@ -604,9 +604,49 @@ Done!
### Customized Help/Usage Messages
-This library uses a vanilla dependency (i.e. no-subdependencies) called [@author.io/table](https://github.com/author/table) to format the usage and help messages of the shell. The `Table` library can be used to create your own custom screens, though most users will likely want to stick with the defaults. If you want to customize messages, the following example can be used as a starting point. The configuration options for the table can be found in the README of its repository.
+**Customizing Flag Appearance:**
+
+The `Shell` and `Command` classes can both accept several boolean attributes to customize the description of each flag within a command. Each of these is `true` by default.
+
+1. `describeDefault`: Display the default flag value.
+1. `describeOptions`: List the valid options for a flag.
+1. `describeMultipleValues`: Appends `Can be used multiple times.` to the flag description
+1. `describeRequired`: Prepends `Required.` to the flag description whenever a flag is required.
+
+
+Example
+
+
+```javascript
+const c = new Command({
+ name: '...',
+ flags: {
+ name: {
+ alias: 'nm',
+ required: true,
+ default: 'Rad Dev',
+ allowMultipleValues: true,
+ options: ['Mr Awesome', 'Mrs Awesome', 'Rad Dev'],
+ description: 'Specify a name.'
+ }
+ }
+})
+```
+
+The help message for this flag would look like:
-_Example:_
+```sh
+Flags:
+ -name ['nm'] Required. Specify a name. Options: Mr
+ Awesome, Mrs Awesome, Rad Dev. Can be
+ used multiple times. (Default Rad Dev)
+```
+
+
+
+**Customizing the Entire Message:**
+
+This library uses a vanilla dependency (i.e. no-subdependencies) called [@author.io/table](https://github.com/author/table) to format the usage and help messages of the shell. The `Table` library can be used to create your own custom screens, though most users will likely want to stick with the defaults. If you want to customize messages, the following example can be used as a starting point. The configuration options for the table can be found in the README of its repository.
```javascript
import { Shell, Command, Table } from '@author.io/node-shell'
diff --git a/examples/cli/index.js b/examples/cli/index.js
index 468f695..ce6abf8 100755
--- a/examples/cli/index.js
+++ b/examples/cli/index.js
@@ -1,4 +1,4 @@
-#!/usr/bin/env node --experimental-modules
+#!/usr/bin/env node --experimental-modules -r source-map-support/register
import fs from 'fs'
import path from 'path'
diff --git a/examples/cli/package.json b/examples/cli/package.json
index cebea26..1d5ec67 100644
--- a/examples/cli/package.json
+++ b/examples/cli/package.json
@@ -16,5 +16,8 @@
"engines": {
"node": "^12.0.0"
},
- "dependencies": {}
+ "dependencies": {},
+ "devDependencies": {
+ "@author.io/node-shell-debug": "^1.5.0"
+ }
}
diff --git a/package-lock.json b/package-lock.json
index 3942fd5..68442ec 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.0",
+ "version": "1.5.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -13,6 +13,1484 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.0.1.tgz",
"integrity": "sha512-WbLWxBtZOSUeXFTQQO/OINifAFYJtU6pwTrh8b0gdqLRkQRoaHM3ymEa+KYbLuCbbexMt8oULDXbIyY88h/0zw=="
+ },
+ "@babel/code-frame": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
+ "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.8.3"
+ }
+ },
+ "@babel/helper-validator-identifier": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz",
+ "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==",
+ "dev": true
+ },
+ "@babel/highlight": {
+ "version": "7.9.0",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz",
+ "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.9.0",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "@babel/runtime": {
+ "version": "7.9.6",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.6.tgz",
+ "integrity": "sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ==",
+ "dev": true,
+ "requires": {
+ "regenerator-runtime": "^0.13.4"
+ }
+ },
+ "@nodelib/fs.scandir": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
+ "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "2.0.3",
+ "run-parallel": "^1.1.9"
+ }
+ },
+ "@nodelib/fs.stat": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
+ "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==",
+ "dev": true
+ },
+ "@nodelib/fs.walk": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz",
+ "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.scandir": "2.1.3",
+ "fastq": "^1.6.0"
+ }
+ },
+ "@size-limit/file": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/@size-limit/file/-/file-4.4.5.tgz",
+ "integrity": "sha512-1kQu7HEwA57mIeRStYFTFiwCpIAnHdOrxE6H8q/iSnQvCnjtJuMFmW0uBAGnbW4yp8XantVlhCNaFavxkcqCjA==",
+ "dev": true,
+ "requires": {
+ "semver": "7.1.3"
+ }
+ },
+ "@size-limit/preset-app": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/@size-limit/preset-app/-/preset-app-4.4.5.tgz",
+ "integrity": "sha512-PsGTrj8tZltO4AJYCTp14/W4DJa19Dd/T83r8+sRoYBWN1pQxJ6sLhOleN8r6YU9ehYcl7nXd2iOt7KP6gVcbA==",
+ "dev": true,
+ "requires": {
+ "@size-limit/file": "4.4.5",
+ "@size-limit/time": "4.4.5"
+ }
+ },
+ "@size-limit/time": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/@size-limit/time/-/time-4.4.5.tgz",
+ "integrity": "sha512-kwTDCksKFbdeUIWzt29BlHT5KyZG3d4UfCVlqXYwdEVqEm4zAQKe0PAJmYgAh/WJR6pixla4Zbab9nzb4kUqlg==",
+ "dev": true,
+ "requires": {
+ "estimo": "^2.0.4",
+ "react": "^16.13.1"
+ }
+ },
+ "@types/color-name": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
+ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
+ "dev": true
+ },
+ "@types/mime-types": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.0.tgz",
+ "integrity": "sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=",
+ "dev": true
+ },
+ "@types/normalize-package-data": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+ "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==",
+ "dev": true
+ },
+ "@types/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
+ "dev": true
+ },
+ "agent-base": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz",
+ "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==",
+ "dev": true
+ },
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+ "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+ "dev": true,
+ "requires": {
+ "@types/color-name": "^1.1.1",
+ "color-convert": "^2.0.1"
+ }
+ },
+ "anymatch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
+ "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
+ "dev": true,
+ "requires": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ }
+ },
+ "array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true
+ },
+ "async-limiter": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
+ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
+ "dev": true
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "dev": true
+ },
+ "binary-extensions": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
+ "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+ "dev": true
+ },
+ "buffer-from": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+ "dev": true
+ },
+ "bytes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+ "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
+ "dev": true
+ },
+ "callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true
+ },
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true
+ },
+ "chalk": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz",
+ "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "chokidar": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz",
+ "integrity": "sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==",
+ "dev": true,
+ "requires": {
+ "anymatch": "~3.1.1",
+ "braces": "~3.0.2",
+ "fsevents": "~2.1.2",
+ "glob-parent": "~5.1.0",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.4.0"
+ }
+ },
+ "ci-job-number": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/ci-job-number/-/ci-job-number-1.2.2.tgz",
+ "integrity": "sha512-CLOGsVDrVamzv8sXJGaILUVI6dsuAkouJP/n6t+OxLPeeA4DDby7zn9SB6EUpa1H7oIKoE+rMmkW80zYsFfUjA==",
+ "dev": true
+ },
+ "cli-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+ "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+ "dev": true,
+ "requires": {
+ "restore-cursor": "^3.1.0"
+ }
+ },
+ "cli-spinners": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.3.0.tgz",
+ "integrity": "sha512-Xs2Hf2nzrvJMFKimOR7YR0QwZ8fc0u98kdtwN1eNAZzNQgH3vK2pXzff6GJtKh7S5hoJ87ECiAiZFS2fb5Ii2w==",
+ "dev": true
+ },
+ "cliui": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+ "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+ "dev": true,
+ "requires": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^6.2.0"
+ }
+ },
+ "clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
+ "dev": true
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "dev": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
+ "cosmiconfig": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
+ "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
+ "dev": true,
+ "requires": {
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.1.0",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.7.2"
+ }
+ },
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "dev": true
+ },
+ "defaults": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
+ "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=",
+ "dev": true,
+ "requires": {
+ "clone": "^1.0.2"
+ }
+ },
+ "dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "requires": {
+ "path-type": "^4.0.0"
+ }
+ },
+ "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
+ },
+ "error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "requires": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true
+ },
+ "estimo": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/estimo/-/estimo-2.0.4.tgz",
+ "integrity": "sha512-to1uzlbJwvTO0WEMXsmTP4TC/FiUMEOoF0twuEviuIe8zLrwyijkukGH3pJ3i9ZOExp+ldLE1rhXePOftzUbFQ==",
+ "dev": true,
+ "requires": {
+ "nanoid": "^2.1.11",
+ "puppeteer-core": "^2.1.1",
+ "tracium": "^0.2.1",
+ "yargs": "^15.3.0"
+ }
+ },
+ "extract-zip": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz",
+ "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==",
+ "dev": true,
+ "requires": {
+ "concat-stream": "^1.6.2",
+ "debug": "^2.6.9",
+ "mkdirp": "^0.5.4",
+ "yauzl": "^2.10.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "fast-glob": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.2.tgz",
+ "integrity": "sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.0",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.2",
+ "picomatch": "^2.2.1"
+ }
+ },
+ "fastq": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.7.0.tgz",
+ "integrity": "sha512-YOadQRnHd5q6PogvAR/x62BGituF2ufiEA6s8aavQANw5YKHERI4AREboX6KotzP8oX2klxYF2wcV/7bn1clfQ==",
+ "dev": true,
+ "requires": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
+ "dev": true,
+ "requires": {
+ "pend": "~1.2.0"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "fsevents": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
+ "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
+ "dev": true,
+ "optional": true
+ },
+ "get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true
+ },
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
+ "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "globby": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.0.tgz",
+ "integrity": "sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg==",
+ "dev": true,
+ "requires": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.1.1",
+ "ignore": "^5.1.4",
+ "merge2": "^1.3.0",
+ "slash": "^3.0.0"
+ }
+ },
+ "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
+ },
+ "hosted-git-info": {
+ "version": "2.8.8",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
+ "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
+ "dev": true
+ },
+ "https-proxy-agent": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz",
+ "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==",
+ "dev": true,
+ "requires": {
+ "agent-base": "5",
+ "debug": "4"
+ }
+ },
+ "ignore": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz",
+ "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==",
+ "dev": true
+ },
+ "import-fresh": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
+ "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
+ "dev": true,
+ "requires": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ }
+ },
+ "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-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+ "dev": true
+ },
+ "is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "requires": {
+ "binary-extensions": "^2.0.0"
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-interactive": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
+ "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
+ "dev": true
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+ "dev": true
+ },
+ "lines-and-columns": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
+ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
+ "dev": true
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "log-symbols": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
+ "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.2"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dev": true,
+ "requires": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ }
+ },
+ "merge2": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz",
+ "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==",
+ "dev": true
+ },
+ "micromatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
+ "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.0.5"
+ }
+ },
+ "mime": {
+ "version": "2.4.5",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.5.tgz",
+ "integrity": "sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==",
+ "dev": true
+ },
+ "mime-db": {
+ "version": "1.44.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
+ "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
+ "dev": true
+ },
+ "mime-types": {
+ "version": "2.1.27",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
+ "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
+ "dev": true,
+ "requires": {
+ "mime-db": "1.44.0"
+ }
+ },
+ "mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+ "dev": true
+ },
+ "mkdirp": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.5"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "mute-stream": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+ "dev": true
+ },
+ "nanoid": {
+ "version": "2.1.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz",
+ "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==",
+ "dev": true
+ },
+ "normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "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
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "dev": true
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "onetime": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz",
+ "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==",
+ "dev": true,
+ "requires": {
+ "mimic-fn": "^2.1.0"
+ }
+ },
+ "ora": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-4.0.4.tgz",
+ "integrity": "sha512-77iGeVU1cIdRhgFzCK8aw1fbtT1B/iZAvWjS+l/o1x0RShMgxHUZaD2yDpWsNCPwXg9z1ZA78Kbdvr8kBmG/Ww==",
+ "dev": true,
+ "requires": {
+ "chalk": "^3.0.0",
+ "cli-cursor": "^3.1.0",
+ "cli-spinners": "^2.2.0",
+ "is-interactive": "^1.0.0",
+ "log-symbols": "^3.0.0",
+ "mute-stream": "0.0.8",
+ "strip-ansi": "^6.0.0",
+ "wcwidth": "^1.0.1"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+ "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ }
+ }
+ },
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true
+ },
+ "parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "requires": {
+ "callsites": "^3.0.0"
+ }
+ },
+ "parse-json": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz",
+ "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1",
+ "lines-and-columns": "^1.1.6"
+ }
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true
+ },
+ "path-parse": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+ "dev": true
+ },
+ "path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true
+ },
+ "pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
+ "dev": true
+ },
+ "picomatch": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
+ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
+ "dev": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
+ },
+ "progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "dev": true
+ },
+ "prop-types": {
+ "version": "15.7.2",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
+ "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
+ "dev": true,
+ "requires": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.8.1"
+ }
+ },
+ "proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+ "dev": true
+ },
+ "puppeteer-core": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-2.1.1.tgz",
+ "integrity": "sha512-n13AWriBMPYxnpbb6bnaY5YoY6rGj8vPLrz6CZF3o0qJNEwlcfJVxBzYZ0NJsQ21UbdJoijPCDrM++SUVEz7+w==",
+ "dev": true,
+ "requires": {
+ "@types/mime-types": "^2.1.0",
+ "debug": "^4.1.0",
+ "extract-zip": "^1.6.6",
+ "https-proxy-agent": "^4.0.0",
+ "mime": "^2.0.3",
+ "mime-types": "^2.1.25",
+ "progress": "^2.0.1",
+ "proxy-from-env": "^1.0.0",
+ "rimraf": "^2.6.1",
+ "ws": "^6.1.0"
+ }
+ },
+ "react": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz",
+ "integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==",
+ "dev": true,
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1",
+ "prop-types": "^15.6.2"
+ }
+ },
+ "react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "dev": true
+ },
+ "read-pkg": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+ "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+ "dev": true,
+ "requires": {
+ "@types/normalize-package-data": "^2.4.0",
+ "normalize-package-data": "^2.5.0",
+ "parse-json": "^5.0.0",
+ "type-fest": "^0.6.0"
+ },
+ "dependencies": {
+ "type-fest": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+ "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
+ "dev": true
+ }
+ }
+ },
+ "read-pkg-up": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+ "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
+ "dev": true,
+ "requires": {
+ "find-up": "^4.1.0",
+ "read-pkg": "^5.2.0",
+ "type-fest": "^0.8.1"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "readdirp": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz",
+ "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==",
+ "dev": true,
+ "requires": {
+ "picomatch": "^2.2.1"
+ }
+ },
+ "regenerator-runtime": {
+ "version": "0.13.5",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
+ "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==",
+ "dev": true
+ },
+ "require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+ "dev": true
+ },
+ "require-main-filename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+ "dev": true
+ },
+ "resolve": {
+ "version": "1.17.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
+ "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
+ "dev": true,
+ "requires": {
+ "path-parse": "^1.0.6"
+ }
+ },
+ "resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true
+ },
+ "restore-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+ "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+ "dev": true,
+ "requires": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "run-parallel": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz",
+ "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==",
+ "dev": true
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "semver": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.1.3.tgz",
+ "integrity": "sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==",
+ "dev": true
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+ "dev": true
+ },
+ "signal-exit": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
+ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
+ "dev": true
+ },
+ "size-limit": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/size-limit/-/size-limit-4.4.5.tgz",
+ "integrity": "sha512-BSczblK8xSm5ErI+8DTYvnIZN23EdlzadAlzaIEBIu+6HzuwM70fbDWUkb5eL0YLIm61vF6BO9uYaO3XLz8vDw==",
+ "dev": true,
+ "requires": {
+ "bytes": "^3.1.0",
+ "chalk": "^4.0.0",
+ "chokidar": "^3.3.1",
+ "ci-job-number": "^1.2.1",
+ "cosmiconfig": "^6.0.0",
+ "globby": "^11.0.0",
+ "ora": "^4.0.3",
+ "read-pkg-up": "^7.0.1"
+ }
+ },
+ "slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true
+ },
+ "spdx-correct": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+ "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+ "dev": true,
+ "requires": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-exceptions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+ "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
+ "dev": true
+ },
+ "spdx-expression-parse": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+ "dev": true,
+ "requires": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-license-ids": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
+ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+ "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+ "dev": true,
+ "requires": {
+ "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"
+ }
+ },
+ "tracium": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/tracium/-/tracium-0.2.1.tgz",
+ "integrity": "sha512-ERoaMqbl9h9qxXrHIh15ZMe2MuYKSN3lXoIrkvDnlQh09Ribn3fzrCQN774ewwS/DbX1wwuipyrhOFqrp5/1qg==",
+ "dev": true,
+ "requires": {
+ "debug": "^4.1.1"
+ }
+ },
+ "type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "dev": true
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+ "dev": true
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dev": true,
+ "requires": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "wcwidth": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
+ "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=",
+ "dev": true,
+ "requires": {
+ "defaults": "^1.0.3"
+ }
+ },
+ "which-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+ "dev": true
+ },
+ "wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "ws": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
+ "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
+ "dev": true,
+ "requires": {
+ "async-limiter": "~1.0.0"
+ }
+ },
+ "y18n": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+ "dev": true
+ },
+ "yaml": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.9.2.tgz",
+ "integrity": "sha512-HPT7cGGI0DuRcsO51qC1j9O16Dh1mZ2bnXwsi0jrSpsLz0WxOLSLXfkABVl6bZO629py3CU+OMJtpNHDLB97kg==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.9.2"
+ }
+ },
+ "yargs": {
+ "version": "15.3.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz",
+ "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==",
+ "dev": true,
+ "requires": {
+ "cliui": "^6.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^4.1.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^4.2.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^18.1.1"
+ }
+ },
+ "yargs-parser": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+ "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ },
+ "yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
+ "dev": true,
+ "requires": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
}
}
}
diff --git a/package.json b/package.json
index 23b3e49..0f49904 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.0",
+ "version": "1.5.1",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/base.js b/src/base.js
index bcdd803..9c5da3a 100644
--- a/src/base.js
+++ b/src/base.js
@@ -17,6 +17,13 @@ export default class Base {
#middleware = new Middleware()
#trailer = new Middleware()
#commonflags = {}
+ #display = {
+ // These are all null, representing they're NOT configured.
+ Default: null,
+ Options: null,
+ MultipleValues: null,
+ Required: null
+ }
#hasCustomDefaultHandler = false
#defaultHandler = function (meta) {
if (this.parent !== null && this.parent.hasCustomDefaultHandler) {
@@ -72,7 +79,7 @@ export default class Base {
}
if (Array.isArray(cfg.arguments)) {
- this.#arguments = cfg.arguments
+ this.#arguments = new Set(cfg.arguments)
}
this.#name = (cfg.name || 'unknown').trim().split(/\s+/)[0]
@@ -113,12 +120,6 @@ export default class Base {
}
Object.defineProperties(this, {
- __arguments: {
- enumerable: false,
- get() {
- return this.#arguments
- }
- },
__processors: {
enumerable: false,
get() {
@@ -182,6 +183,26 @@ export default class Base {
throw new Error('Invalid trailer: ' + code.toString())
}
}
+ },
+ initializeHelpAnnotations: {
+ enumerable: false,
+ configurable: false,
+ writable: false,
+ value: cfg => {
+ if (cfg.hasOwnProperty('describeDefault') && typeof cfg.describeDefault === 'boolean') {
+ console.log('HERE')
+ this.#display.Default = cfg.describeDefault
+ }
+ if (cfg.hasOwnProperty('describeOptions') && typeof cfg.describeOptions === 'boolean') {
+ this.#display.Options = cfg.describeOptions
+ }
+ if (cfg.hasOwnProperty('describeMultipleValues') && typeof cfg.describeMultipleValues === 'boolean') {
+ this.#display.MultipleValues = cfg.describeMultipleValues
+ }
+ if (cfg.hasOwnProperty('describeRequired') && typeof cfg.describeRequired === 'boolean') {
+ this.#display.Required = cfg.describeRequired
+ }
+ }
}
})
}
@@ -211,6 +232,40 @@ export default class Base {
this.#formattedDefaultHelp.width = this.#width
}
+ describeHelp (attr, prop) {
+ if (this.#display[prop] !== null) {
+ return this.#display[prop]
+ }
+
+ if (this instanceof Command) {
+ if (this.shell[attr] !== null) {
+ return this.shell[attr]
+ }
+
+ if (this.parent !== null) {
+ return this.parent[attr]
+ }
+ }
+
+ return true
+ }
+
+ get describeDefault () {
+ return this.describeHelp('describeDefault', 'Default')
+ }
+
+ get describeOptions () {
+ return this.describeHelp('describeOptions', 'Options')
+ }
+
+ get describeMultipleValues () {
+ return this.describeHelp('describeMultipleValues', 'MultipleValues')
+ }
+
+ get describeRequired () {
+ return this.describeHelp('describeRequired', 'Required')
+ }
+
get usage() {
if (this.#customUsage !== null) {
return typeof this.#customUsage === 'function' ? this.#customUsage() : this.#customUsage
diff --git a/src/command.js b/src/command.js
index 782f420..11e7c9f 100644
--- a/src/command.js
+++ b/src/command.js
@@ -38,6 +38,8 @@ export default class Command extends Base {
cfg.trailer.forEach(code => this.initializeTrailer(code))
}
+ this.initializeHelpAnnotations(cfg)
+
this.#fn = cfg.handler
this.#oid = Symbol(((cfg.name || cfg.usage) || cfg.pattern) || 'command')
this.#pattern = cfg.pattern || /[\s\S]+/i
@@ -91,6 +93,10 @@ export default class Command extends Base {
'subcommands',
'defaultHandler',
'disableHelp',
+ 'describeDefault',
+ 'describeOptions',
+ 'describeMultipleValues',
+ 'describeRequired',
'flags',
'alias',
'aliases',
diff --git a/src/format.js b/src/format.js
index 976a686..8b40547 100644
--- a/src/format.js
+++ b/src/format.js
@@ -29,7 +29,7 @@ class Formatter {
if (this.#data instanceof Command) {
const aliases = this.#data.aliases
- const out = [`${this.#data.commandroot}${aliases.length > 0 ? '|' + aliases.join('|') : ''}${this.#data.__flagConfig.size > 0 ? ' [FLAGS]' : ''}${this.#data.__arguments.size > 0 ? ' ' + Array.from(this.#data.__arguments).map(i => '<' + i + '>').join(', ') : ''}`]
+ const out = [`${this.#data.commandroot}${aliases.length > 0 ? '|' + aliases.join('|') : ''}${this.#data.__flagConfig.size > 0 ? ' [FLAGS]' : ''}${this.#data.arguments.size > 0 ? ' ' + Array.from(this.#data.arguments).map(i => '<' + i + '>').join(', ') : ''}`]
if (desc.trim().length > 0 && out !== desc) {
out.push(new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output)
@@ -37,7 +37,7 @@ class Formatter {
return out.join('\n')
} else if (this.#data instanceof Shell) {
- return `${this.#data.name}${this.#data.__processors.size > 0 ? ' [COMMAND]' : ''}\n${desc.trim().length > 0 ? new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output : ''}${this.#data.__arguments.size > 0 ? ' ' + Array.from(this.#data.__arguments).map(i => '[' + i + ']').join(', ') : ''}\n`.trim()
+ return `${this.#data.name}${this.#data.__processors.size > 0 ? ' [COMMAND]' : ''}\n${desc.trim().length > 0 ? new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output : ''}${this.#data.arguments.size > 0 ? ' ' + Array.from(this.#data.arguments).map(i => '[' + i + ']').join(', ') : ''}\n`.trim()
}
return ''
@@ -49,12 +49,33 @@ class Formatter {
if (this.#data instanceof Command) {
const flags = this.#data.__flagConfig
const rows = []
-
+
if (flags.size > 0) {
flags.forEach((cfg, flag) => {
let aliases = Array.from(cfg.aliases||cfg.alias||[])
aliases = aliases.length === 0 ? '' : '[' + aliases.map(a => `-${a}`).join(', ') + ']'
- rows.push(['-' + flag, aliases || '', cfg.description || ''])
+
+ let dsc = [cfg.description || '']
+
+ if (cfg.hasOwnProperty('options') && this.#data.describeOptions) {
+ dsc.push(`Options: ${cfg.options.join(', ')}.`)
+ }
+
+ if (cfg.hasOwnProperty('allowMultipleValues') && cfg.allowMultipleValues === true && this.#data.describeMultipleValues) {
+ dsc.push('Can be used multiple times.')
+ }
+
+ if (cfg.hasOwnProperty('default') && this.#data.describeDefault) {
+ dsc.push(`(Default: ${cfg.default.toString()})`)
+ }
+
+ if (cfg.hasOwnProperty('required') && cfg.required === true && this.#data.describeRequired) {
+ dsc.unshift('Required.')
+ }
+
+ dsc = dsc.join(' ').trim()
+
+ rows.push(['-' + flag, aliases || '', dsc || ''])
})
}
diff --git a/src/shell.js b/src/shell.js
index 193d4b4..999a718 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -23,6 +23,8 @@ export default class Shell extends Base {
constructor (cfg = { maxhistory: 100 }) {
super(cfg)
+ this.initializeHelpAnnotations(cfg)
+
this.__commonflags = cfg.commonflags || {}
if (cfg.hasOwnProperty('use') && Array.isArray(cfg.use)) {
From d57877351d908829949e2623bc89bd19aa8b4893 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sun, 3 May 2020 19:50:07 -0500
Subject: [PATCH 050/152] Fixed argument mapping.
---
package-lock.json | 2 +-
package.json | 2 +-
src/command.js | 60 +++++++++++++++++++++++------------------------
3 files changed, 31 insertions(+), 33 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 68442ec..4558808 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.1",
+ "version": "1.5.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 0f49904..d0f79ff 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.1",
+ "version": "1.5.2",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/command.js b/src/command.js
index 11e7c9f..bf14056 100644
--- a/src/command.js
+++ b/src/command.js
@@ -387,7 +387,7 @@ export default class Command extends Base {
data.help.message = this.help
}
- const args = this.arguments
+ const args = Array.from(this.arguments)
Object.defineProperties(data, {
flag: {
@@ -420,41 +420,39 @@ export default class Command extends Base {
let uf = parser.unrecognizedFlags
let result = Object.assign({}, recognized)
delete result.help
+
+ args.forEach((name, i) => {
+ let value = uf[i]
+ let normalizedValue = Object.keys(pdata).filter(key => key.toLowerCase() === value)
+ normalizedValue = (normalizedValue.length > 0 ? normalizedValue.pop() : value)
- if (uf.length > 0) {
- args.forEach((name, i) => {
- let value = uf[i]
- let normalizedValue = Object.keys(pdata).filter(key => key.toLowerCase() === value)
- normalizedValue = (normalizedValue.length > 0 ? normalizedValue.pop() : value)
-
- if (normalizedValue !== undefined) {
- normalizedValue = normalizedValue.trim()
+ if (normalizedValue !== undefined) {
+ normalizedValue = normalizedValue.trim()
- if (STRIP_QUOTE_PATTERN.test(normalizedValue)) {
- normalizedValue = normalizedValue.substring(1, normalizedValue.length - 1)
- }
+ if (STRIP_QUOTE_PATTERN.test(normalizedValue)) {
+ normalizedValue = normalizedValue.substring(1, normalizedValue.length - 1)
}
+ }
- if (result.hasOwnProperty(name)) {
- result[name] = Array.isArray(result[name]) ? result[name]: [result[name]]
- result[name].push(normalizedValue)
- } else {
- result[name] = normalizedValue
- }
- })
-
- if (uf.length > args.length) {
- uf.slice(args.length)
- .forEach((flag, i) => {
- let name = `unknown${i + 1}`
- while (result.hasOwnProperty(name)) {
- let number = name.substring(7)
- name = 'unknown' + (parseInt(number) + 1)
- }
-
- result[name] = flag
- })
+ if (result.hasOwnProperty(name)) {
+ result[name] = Array.isArray(result[name]) ? result[name]: [result[name]]
+ result[name].push(normalizedValue)
+ } else {
+ result[name] = normalizedValue
}
+ })
+
+ if (uf.length > args.length) {
+ uf.slice(args.length)
+ .forEach((flag, i) => {
+ let name = `unknown${i + 1}`
+ while (result.hasOwnProperty(name)) {
+ let number = name.substring(7)
+ name = 'unknown' + (parseInt(number) + 1)
+ }
+
+ result[name] = flag
+ })
}
return result
From 057913ddb37ccd17523002334d831170ad2085b6 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sun, 3 May 2020 21:48:59 -0500
Subject: [PATCH 051/152] Added ability to retrieve named flag using metadata
flag() method.
---
package-lock.json | 2 +-
package.json | 2 +-
src/command.js | 4 ++++
3 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 4558808..3571c5d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.2",
+ "version": "1.5.3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index d0f79ff..af957c4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.2",
+ "version": "1.5.3",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/command.js b/src/command.js
index bf14056..37a51fb 100644
--- a/src/command.js
+++ b/src/command.js
@@ -402,6 +402,10 @@ export default class Command extends Base {
return pdata.flagSource[name].value
}
} catch (e) {
+ if (this.arguments.has(name)) {
+ return Array.from(parser.unrecognizedFlags)[args.indexOf(name)]
+ }
+
return undefined
}
}
From f32d06a939b2050cd520907f52b56248a8088b85 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 4 May 2020 14:51:05 -0500
Subject: [PATCH 052/152] Updated arg dependency to support ordered named
arguments.
---
.github/FUNDING.yml | 12 -
.github/workflows/deploy.yml | 130 ---
package-lock.json | 1486 +---------------------------
package.json | 4 +-
test/unit/01-sanity/04-metadata.js | 90 ++
5 files changed, 96 insertions(+), 1626 deletions(-)
delete mode 100644 .github/FUNDING.yml
delete mode 100644 .github/workflows/deploy.yml
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index eaf9b65..0000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-# These are supported funding model platforms
-
-github: coreybutler
-patreon: # coreybutler
-open_collective: # Replace with a single Open Collective username
-ko_fi: # Replace with a single Ko-fi username
-tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
-community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
-liberapay: # Replace with a single Liberapay username
-issuehunt: # Replace with a single IssueHunt username
-otechie: # Replace with a single Otechie username
-custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
\ No newline at end of file
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
deleted file mode 100644
index b8464dc..0000000
--- a/.github/workflows/deploy.yml
+++ /dev/null
@@ -1,130 +0,0 @@
-name: Tag, Release, & Publish
-
-on:
- push:
- branches:
- - master
-
-jobs:
- build:
- runs-on: ubuntu-latest
- steps:
- # Checkout updated source code
- - uses: actions/checkout@v2
-
- # If the version has changed, create a new git tag for it.
- - name: Tag
- id: autotagger
- uses: butlerlogic/action-autotag@master
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- # The remaining steps all depend on whether or not
- # a new tag was created. There is no need to release/publish
- # updates until the code base is in a releaseable state.
-
- # If the new version/tag is a pre-release (i.e. 1.0.0-beta.1), create
- # an environment variable indicating it is a prerelease.
- - name: Pre-release
- if: steps.autotagger.outputs.tagname != ''
- run: |
- if [[ "${{ steps.autotagger.output.version }}" == *"-"* ]]; then echo "::set-env IS_PRERELEASE=true";else echo "::set-env IS_PRERELEASE=''";fi
-
- # Create a github release
- # This will create a snapshot of the module,
- # available in the "Releases" section on Github.
- - name: Release
- id: create_release
- if: steps.autotagger.outputs.tagname != ''
- uses: actions/create-release@v1.0.0
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- with:
- tag_name: ${{ steps.autotagger.outputs.tagname }}
- release_name: ${{ steps.autotagger.outputs.tagname }}
- body: ${{ steps.autotagger.outputs.tagmessage }}
- draft: false
- prerelease: env.IS_PRERELEASE != ''
-
- - uses: actions/setup-node@v1
- if: steps.create_release.outputs.id != ''
- with:
- node-version: '13'
-
- # Build tarballs of the module code.
- - name: Build Release Artifacts
- id: build_release
- if: steps.create_release.outputs.id != ''
- run: |
- npm install
- cd ./build && npm install && cd ../
- npm run build --if-present
- for d in .dist/*/*/ ; do tar -cvzf ${d%%/}-${{ steps.autotagger.outputs.version }}.tar.gz ${d%%}*; done;
- if [[ ${{ github.ref }} == *"-"* ]]; then echo ::set-output isprerelease=true;else echo ::set-output isprerelease=false;fi
- # Upload tarballs to the release.
- - name: Upload Release Artifacts
- uses: AButler/upload-release-assets@v2.0
- if: steps.create_release.outputs.id != ''
- with:
- files: './.dist/**/*.tar.gz'
- repo-token: ${{ secrets.GITHUB_TOKEN }}
- release-tag: ${{ steps.autotagger.outputs.tagname }}
-
- # Build npm packages
- - name: Build Module Artifacts
- id: build_npm
- if: steps.create_release.outputs.id != ''
- run: |
- npm install
- cd ./build && npm install && cd ../
- npm run build --if-present
- # Use this action to publish a single module to npm.
- - name: Publish
- id: publish_npm
- if: steps.autotagger.outputs.tagname != ''
- uses: author/action-publish@master
- with:
- scan: .dist
- env:
- REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
-
- - name: Rollback Release
- if: failure() && steps.create_release.outputs.id != ''
- uses: author/action-rollback@stable
- with:
- tag: ${{ steps.autotagger.outputs.tagname }}
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Failure Notification
- if: failure() && steps.create_release.outputs.id != ''
- env:
- SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
- SLACK_USERNAME: Github # Optional. (defaults to webhook app)
- SLACK_CHANNEL: author # Optional. (defaults to webhook)
- SLACK_AVATAR: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/320px-Npm-logo.svg.png"
- uses: Ilshidur/action-slack@master
- with:
- args: '@author.io/shell ${{ steps.autotagger.outputs.tagname }} failed to publish and was rolled back.' # Optional
-
- - name: Success Notification
- if: success() && steps.autotagger.outputs.tagname != ''
- env:
- SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
- SLACK_USERNAME: Github # Optional. (defaults to webhook app)
- SLACK_CHANNEL: author # Optional. (defaults to webhook)
- SLACK_AVATAR: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/320px-Npm-logo.svg.png"
- uses: Ilshidur/action-slack@master
- with:
- args: '@author.io/shell ${{ steps.autotagger.outputs.tagname }} published to npm.' # Optional
-
- - name: Inaction Notification
- if: steps.autotagger.outputs.tagname == ''
- env:
- SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
- SLACK_USERNAME: Github # Optional. (defaults to webhook app)
- SLACK_CHANNEL: author # Optional. (defaults to webhook)
- SLACK_AVATAR: "https://cdn.freebiesupply.com/logos/large/2x/nodejs-icon-logo-png-transparent.png" # Optional. can be (repository, sender, an URL) (defaults to webhook app avatar)
- uses: Ilshidur/action-slack@master
- with:
- args: "New code was added to author/shell master branch." # Optional
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 3571c5d..36f62b4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,1496 +1,18 @@
{
"name": "@author.io/shell",
- "version": "1.5.3",
+ "version": "1.5.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@author.io/arg": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.0.tgz",
- "integrity": "sha512-lKVMWqhVjqLVKvNfMmb9feC7BE/s3xc6wr+ZQrryx1KsudknLXLDafVEbJbiKHTQMWwGqBobHhX0Bme/GFShOA=="
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.1.tgz",
+ "integrity": "sha512-yD/ZIBYLFDIqBE2MAnZ/uCgtm0Mp+OL0TAHWsJOFdtqoSnVwJhm17A8F13/LOk2hO/wqM4UqxbQeG108b0Z36w=="
},
"@author.io/table": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.0.1.tgz",
"integrity": "sha512-WbLWxBtZOSUeXFTQQO/OINifAFYJtU6pwTrh8b0gdqLRkQRoaHM3ymEa+KYbLuCbbexMt8oULDXbIyY88h/0zw=="
- },
- "@babel/code-frame": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
- "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.8.3"
- }
- },
- "@babel/helper-validator-identifier": {
- "version": "7.9.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz",
- "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==",
- "dev": true
- },
- "@babel/highlight": {
- "version": "7.9.0",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz",
- "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.9.0",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
- "dev": true
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
- }
- },
- "@babel/runtime": {
- "version": "7.9.6",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.6.tgz",
- "integrity": "sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ==",
- "dev": true,
- "requires": {
- "regenerator-runtime": "^0.13.4"
- }
- },
- "@nodelib/fs.scandir": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
- "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==",
- "dev": true,
- "requires": {
- "@nodelib/fs.stat": "2.0.3",
- "run-parallel": "^1.1.9"
- }
- },
- "@nodelib/fs.stat": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
- "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==",
- "dev": true
- },
- "@nodelib/fs.walk": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz",
- "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==",
- "dev": true,
- "requires": {
- "@nodelib/fs.scandir": "2.1.3",
- "fastq": "^1.6.0"
- }
- },
- "@size-limit/file": {
- "version": "4.4.5",
- "resolved": "https://registry.npmjs.org/@size-limit/file/-/file-4.4.5.tgz",
- "integrity": "sha512-1kQu7HEwA57mIeRStYFTFiwCpIAnHdOrxE6H8q/iSnQvCnjtJuMFmW0uBAGnbW4yp8XantVlhCNaFavxkcqCjA==",
- "dev": true,
- "requires": {
- "semver": "7.1.3"
- }
- },
- "@size-limit/preset-app": {
- "version": "4.4.5",
- "resolved": "https://registry.npmjs.org/@size-limit/preset-app/-/preset-app-4.4.5.tgz",
- "integrity": "sha512-PsGTrj8tZltO4AJYCTp14/W4DJa19Dd/T83r8+sRoYBWN1pQxJ6sLhOleN8r6YU9ehYcl7nXd2iOt7KP6gVcbA==",
- "dev": true,
- "requires": {
- "@size-limit/file": "4.4.5",
- "@size-limit/time": "4.4.5"
- }
- },
- "@size-limit/time": {
- "version": "4.4.5",
- "resolved": "https://registry.npmjs.org/@size-limit/time/-/time-4.4.5.tgz",
- "integrity": "sha512-kwTDCksKFbdeUIWzt29BlHT5KyZG3d4UfCVlqXYwdEVqEm4zAQKe0PAJmYgAh/WJR6pixla4Zbab9nzb4kUqlg==",
- "dev": true,
- "requires": {
- "estimo": "^2.0.4",
- "react": "^16.13.1"
- }
- },
- "@types/color-name": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
- "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
- "dev": true
- },
- "@types/mime-types": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.0.tgz",
- "integrity": "sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=",
- "dev": true
- },
- "@types/normalize-package-data": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
- "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==",
- "dev": true
- },
- "@types/parse-json": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
- "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
- "dev": true
- },
- "agent-base": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz",
- "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==",
- "dev": true
- },
- "ansi-regex": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
- "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
- "dev": true
- },
- "ansi-styles": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
- "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
- "dev": true,
- "requires": {
- "@types/color-name": "^1.1.1",
- "color-convert": "^2.0.1"
- }
- },
- "anymatch": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
- "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
- "dev": true,
- "requires": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- }
- },
- "array-union": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
- "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
- "dev": true
- },
- "async-limiter": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
- "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
- "dev": true
- },
- "balanced-match": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
- "dev": true
- },
- "binary-extensions": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
- "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==",
- "dev": true
- },
- "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"
- }
- },
- "buffer-crc32": {
- "version": "0.2.13",
- "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
- "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
- "dev": true
- },
- "buffer-from": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
- "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
- "dev": true
- },
- "bytes": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
- "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
- "dev": true
- },
- "callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true
- },
- "camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
- "dev": true
- },
- "chalk": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz",
- "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "chokidar": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz",
- "integrity": "sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==",
- "dev": true,
- "requires": {
- "anymatch": "~3.1.1",
- "braces": "~3.0.2",
- "fsevents": "~2.1.2",
- "glob-parent": "~5.1.0",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.4.0"
- }
- },
- "ci-job-number": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/ci-job-number/-/ci-job-number-1.2.2.tgz",
- "integrity": "sha512-CLOGsVDrVamzv8sXJGaILUVI6dsuAkouJP/n6t+OxLPeeA4DDby7zn9SB6EUpa1H7oIKoE+rMmkW80zYsFfUjA==",
- "dev": true
- },
- "cli-cursor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
- "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
- "dev": true,
- "requires": {
- "restore-cursor": "^3.1.0"
- }
- },
- "cli-spinners": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.3.0.tgz",
- "integrity": "sha512-Xs2Hf2nzrvJMFKimOR7YR0QwZ8fc0u98kdtwN1eNAZzNQgH3vK2pXzff6GJtKh7S5hoJ87ECiAiZFS2fb5Ii2w==",
- "dev": true
- },
- "cliui": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
- "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
- "dev": true,
- "requires": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.0",
- "wrap-ansi": "^6.2.0"
- }
- },
- "clone": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
- "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
- "dev": true
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
- "dev": true
- },
- "concat-stream": {
- "version": "1.6.2",
- "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
- "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
- "dev": true,
- "requires": {
- "buffer-from": "^1.0.0",
- "inherits": "^2.0.3",
- "readable-stream": "^2.2.2",
- "typedarray": "^0.0.6"
- }
- },
- "core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
- "dev": true
- },
- "cosmiconfig": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
- "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
- "dev": true,
- "requires": {
- "@types/parse-json": "^4.0.0",
- "import-fresh": "^3.1.0",
- "parse-json": "^5.0.0",
- "path-type": "^4.0.0",
- "yaml": "^1.7.2"
- }
- },
- "debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
- "dev": true,
- "requires": {
- "ms": "^2.1.1"
- }
- },
- "decamelize": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
- "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
- "dev": true
- },
- "defaults": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
- "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=",
- "dev": true,
- "requires": {
- "clone": "^1.0.2"
- }
- },
- "dir-glob": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
- "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
- "dev": true,
- "requires": {
- "path-type": "^4.0.0"
- }
- },
- "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
- },
- "error-ex": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
- "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
- "dev": true,
- "requires": {
- "is-arrayish": "^0.2.1"
- }
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
- "dev": true
- },
- "estimo": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/estimo/-/estimo-2.0.4.tgz",
- "integrity": "sha512-to1uzlbJwvTO0WEMXsmTP4TC/FiUMEOoF0twuEviuIe8zLrwyijkukGH3pJ3i9ZOExp+ldLE1rhXePOftzUbFQ==",
- "dev": true,
- "requires": {
- "nanoid": "^2.1.11",
- "puppeteer-core": "^2.1.1",
- "tracium": "^0.2.1",
- "yargs": "^15.3.0"
- }
- },
- "extract-zip": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz",
- "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==",
- "dev": true,
- "requires": {
- "concat-stream": "^1.6.2",
- "debug": "^2.6.9",
- "mkdirp": "^0.5.4",
- "yauzl": "^2.10.0"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
- "dev": true
- }
- }
- },
- "fast-glob": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.2.tgz",
- "integrity": "sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A==",
- "dev": true,
- "requires": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.0",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.2",
- "picomatch": "^2.2.1"
- }
- },
- "fastq": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.7.0.tgz",
- "integrity": "sha512-YOadQRnHd5q6PogvAR/x62BGituF2ufiEA6s8aavQANw5YKHERI4AREboX6KotzP8oX2klxYF2wcV/7bn1clfQ==",
- "dev": true,
- "requires": {
- "reusify": "^1.0.4"
- }
- },
- "fd-slicer": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
- "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
- "dev": true,
- "requires": {
- "pend": "~1.2.0"
- }
- },
- "fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
- "requires": {
- "to-regex-range": "^5.0.1"
- }
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "dev": true,
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
- "dev": true
- },
- "fsevents": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
- "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
- "dev": true,
- "optional": true
- },
- "get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true
- },
- "glob": {
- "version": "7.1.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
- "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "glob-parent": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
- "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
- "dev": true,
- "requires": {
- "is-glob": "^4.0.1"
- }
- },
- "globby": {
- "version": "11.0.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.0.tgz",
- "integrity": "sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg==",
- "dev": true,
- "requires": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.1.1",
- "ignore": "^5.1.4",
- "merge2": "^1.3.0",
- "slash": "^3.0.0"
- }
- },
- "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
- },
- "hosted-git-info": {
- "version": "2.8.8",
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
- "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
- "dev": true
- },
- "https-proxy-agent": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz",
- "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==",
- "dev": true,
- "requires": {
- "agent-base": "5",
- "debug": "4"
- }
- },
- "ignore": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz",
- "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==",
- "dev": true
- },
- "import-fresh": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
- "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
- "dev": true,
- "requires": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- }
- },
- "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-arrayish": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
- "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
- "dev": true
- },
- "is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
- "requires": {
- "binary-extensions": "^2.0.0"
- }
- },
- "is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
- "is-glob": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
- "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
- "dev": true,
- "requires": {
- "is-extglob": "^2.1.1"
- }
- },
- "is-interactive": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
- "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
- "dev": true
- },
- "is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true
- },
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
- },
- "js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
- },
- "json-parse-better-errors": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
- "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
- "dev": true
- },
- "lines-and-columns": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
- "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
- "dev": true
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "dev": true,
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "log-symbols": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
- "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==",
- "dev": true,
- "requires": {
- "chalk": "^2.4.2"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
- "dev": true
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
- }
- },
- "loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dev": true,
- "requires": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- }
- },
- "merge2": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz",
- "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==",
- "dev": true
- },
- "micromatch": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
- "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
- "dev": true,
- "requires": {
- "braces": "^3.0.1",
- "picomatch": "^2.0.5"
- }
- },
- "mime": {
- "version": "2.4.5",
- "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.5.tgz",
- "integrity": "sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==",
- "dev": true
- },
- "mime-db": {
- "version": "1.44.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
- "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
- "dev": true
- },
- "mime-types": {
- "version": "2.1.27",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
- "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
- "dev": true,
- "requires": {
- "mime-db": "1.44.0"
- }
- },
- "mimic-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
- "dev": true
- },
- "minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "minimist": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
- "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
- "dev": true
- },
- "mkdirp": {
- "version": "0.5.5",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
- "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
- "dev": true,
- "requires": {
- "minimist": "^1.2.5"
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "mute-stream": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
- "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
- "dev": true
- },
- "nanoid": {
- "version": "2.1.11",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz",
- "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==",
- "dev": true
- },
- "normalize-package-data": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
- "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
- "dev": true,
- "requires": {
- "hosted-git-info": "^2.1.4",
- "resolve": "^1.10.0",
- "semver": "2 || 3 || 4 || 5",
- "validate-npm-package-license": "^3.0.1"
- },
- "dependencies": {
- "semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "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
- },
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true
- },
- "once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "dev": true,
- "requires": {
- "wrappy": "1"
- }
- },
- "onetime": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz",
- "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==",
- "dev": true,
- "requires": {
- "mimic-fn": "^2.1.0"
- }
- },
- "ora": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/ora/-/ora-4.0.4.tgz",
- "integrity": "sha512-77iGeVU1cIdRhgFzCK8aw1fbtT1B/iZAvWjS+l/o1x0RShMgxHUZaD2yDpWsNCPwXg9z1ZA78Kbdvr8kBmG/Ww==",
- "dev": true,
- "requires": {
- "chalk": "^3.0.0",
- "cli-cursor": "^3.1.0",
- "cli-spinners": "^2.2.0",
- "is-interactive": "^1.0.0",
- "log-symbols": "^3.0.0",
- "mute-stream": "0.0.8",
- "strip-ansi": "^6.0.0",
- "wcwidth": "^1.0.1"
- },
- "dependencies": {
- "chalk": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
- "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- }
- }
- },
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "requires": {
- "p-try": "^2.0.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true
- },
- "parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
- "requires": {
- "callsites": "^3.0.0"
- }
- },
- "parse-json": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz",
- "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-better-errors": "^1.0.1",
- "lines-and-columns": "^1.1.6"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
- "dev": true
- },
- "path-parse": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
- "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
- "dev": true
- },
- "path-type": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
- "dev": true
- },
- "pend": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
- "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
- "dev": true
- },
- "picomatch": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
- "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
- "dev": true
- },
- "process-nextick-args": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
- "dev": true
- },
- "progress": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
- "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
- "dev": true
- },
- "prop-types": {
- "version": "15.7.2",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
- "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.8.1"
- }
- },
- "proxy-from-env": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
- "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
- "dev": true
- },
- "puppeteer-core": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-2.1.1.tgz",
- "integrity": "sha512-n13AWriBMPYxnpbb6bnaY5YoY6rGj8vPLrz6CZF3o0qJNEwlcfJVxBzYZ0NJsQ21UbdJoijPCDrM++SUVEz7+w==",
- "dev": true,
- "requires": {
- "@types/mime-types": "^2.1.0",
- "debug": "^4.1.0",
- "extract-zip": "^1.6.6",
- "https-proxy-agent": "^4.0.0",
- "mime": "^2.0.3",
- "mime-types": "^2.1.25",
- "progress": "^2.0.1",
- "proxy-from-env": "^1.0.0",
- "rimraf": "^2.6.1",
- "ws": "^6.1.0"
- }
- },
- "react": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz",
- "integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1",
- "prop-types": "^15.6.2"
- }
- },
- "react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
- },
- "read-pkg": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
- "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
- "dev": true,
- "requires": {
- "@types/normalize-package-data": "^2.4.0",
- "normalize-package-data": "^2.5.0",
- "parse-json": "^5.0.0",
- "type-fest": "^0.6.0"
- },
- "dependencies": {
- "type-fest": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
- "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
- "dev": true
- }
- }
- },
- "read-pkg-up": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
- "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
- "dev": true,
- "requires": {
- "find-up": "^4.1.0",
- "read-pkg": "^5.2.0",
- "type-fest": "^0.8.1"
- }
- },
- "readable-stream": {
- "version": "2.3.7",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
- "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "readdirp": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz",
- "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==",
- "dev": true,
- "requires": {
- "picomatch": "^2.2.1"
- }
- },
- "regenerator-runtime": {
- "version": "0.13.5",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
- "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==",
- "dev": true
- },
- "require-directory": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
- "dev": true
- },
- "require-main-filename": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
- "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
- "dev": true
- },
- "resolve": {
- "version": "1.17.0",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
- "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
- "dev": true,
- "requires": {
- "path-parse": "^1.0.6"
- }
- },
- "resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true
- },
- "restore-cursor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
- "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
- "dev": true,
- "requires": {
- "onetime": "^5.1.0",
- "signal-exit": "^3.0.2"
- }
- },
- "reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "dev": true
- },
- "rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
- "dev": true,
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "run-parallel": {
- "version": "1.1.9",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz",
- "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==",
- "dev": true
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "semver": {
- "version": "7.1.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.1.3.tgz",
- "integrity": "sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==",
- "dev": true
- },
- "set-blocking": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
- "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
- "dev": true
- },
- "signal-exit": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
- "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
- "dev": true
- },
- "size-limit": {
- "version": "4.4.5",
- "resolved": "https://registry.npmjs.org/size-limit/-/size-limit-4.4.5.tgz",
- "integrity": "sha512-BSczblK8xSm5ErI+8DTYvnIZN23EdlzadAlzaIEBIu+6HzuwM70fbDWUkb5eL0YLIm61vF6BO9uYaO3XLz8vDw==",
- "dev": true,
- "requires": {
- "bytes": "^3.1.0",
- "chalk": "^4.0.0",
- "chokidar": "^3.3.1",
- "ci-job-number": "^1.2.1",
- "cosmiconfig": "^6.0.0",
- "globby": "^11.0.0",
- "ora": "^4.0.3",
- "read-pkg-up": "^7.0.1"
- }
- },
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true
- },
- "spdx-correct": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
- "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
- "dev": true,
- "requires": {
- "spdx-expression-parse": "^3.0.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "spdx-exceptions": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
- "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
- "dev": true
- },
- "spdx-expression-parse": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
- "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
- "dev": true,
- "requires": {
- "spdx-exceptions": "^2.1.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "spdx-license-ids": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
- "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
- "dev": true
- },
- "string-width": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
- "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.0"
- }
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- },
- "strip-ansi": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
- "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.0"
- }
- },
- "supports-color": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
- "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
- "dev": true,
- "requires": {
- "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"
- }
- },
- "tracium": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/tracium/-/tracium-0.2.1.tgz",
- "integrity": "sha512-ERoaMqbl9h9qxXrHIh15ZMe2MuYKSN3lXoIrkvDnlQh09Ribn3fzrCQN774ewwS/DbX1wwuipyrhOFqrp5/1qg==",
- "dev": true,
- "requires": {
- "debug": "^4.1.1"
- }
- },
- "type-fest": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
- "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
- "dev": true
- },
- "typedarray": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
- "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
- "dev": true
- },
- "util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
- "dev": true
- },
- "validate-npm-package-license": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
- "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
- "dev": true,
- "requires": {
- "spdx-correct": "^3.0.0",
- "spdx-expression-parse": "^3.0.0"
- }
- },
- "wcwidth": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
- "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=",
- "dev": true,
- "requires": {
- "defaults": "^1.0.3"
- }
- },
- "which-module": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
- "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
- "dev": true
- },
- "wrap-ansi": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
- "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
- "dev": true
- },
- "ws": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
- "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
- "dev": true,
- "requires": {
- "async-limiter": "~1.0.0"
- }
- },
- "y18n": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
- "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
- "dev": true
- },
- "yaml": {
- "version": "1.9.2",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.9.2.tgz",
- "integrity": "sha512-HPT7cGGI0DuRcsO51qC1j9O16Dh1mZ2bnXwsi0jrSpsLz0WxOLSLXfkABVl6bZO629py3CU+OMJtpNHDLB97kg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.9.2"
- }
- },
- "yargs": {
- "version": "15.3.1",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz",
- "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==",
- "dev": true,
- "requires": {
- "cliui": "^6.0.0",
- "decamelize": "^1.2.0",
- "find-up": "^4.1.0",
- "get-caller-file": "^2.0.1",
- "require-directory": "^2.1.1",
- "require-main-filename": "^2.0.0",
- "set-blocking": "^2.0.0",
- "string-width": "^4.2.0",
- "which-module": "^2.0.0",
- "y18n": "^4.0.0",
- "yargs-parser": "^18.1.1"
- }
- },
- "yargs-parser": {
- "version": "18.1.3",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
- "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
- "dev": true,
- "requires": {
- "camelcase": "^5.0.0",
- "decamelize": "^1.2.0"
- }
- },
- "yauzl": {
- "version": "2.10.0",
- "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
- "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
- "dev": true,
- "requires": {
- "buffer-crc32": "~0.2.3",
- "fd-slicer": "~1.1.0"
- }
}
}
}
diff --git a/package.json b/package.json
index af957c4..46f42d6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.3",
+ "version": "1.5.4",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
@@ -51,7 +51,7 @@
]
},
"dependencies": {
- "@author.io/arg": "^1.3.0",
+ "@author.io/arg": "^1.3.1",
"@author.io/table": "^1.0.1"
}
}
diff --git a/test/unit/01-sanity/04-metadata.js b/test/unit/01-sanity/04-metadata.js
index e3c6ea2..f7bc854 100644
--- a/test/unit/01-sanity/04-metadata.js
+++ b/test/unit/01-sanity/04-metadata.js
@@ -107,3 +107,93 @@ test('Map unnamed arguments when duplicate names are supplied', t => {
.catch(e => t.fail(e.message))
.finally(() => t.end())
})
+
+test('wtf', t => {
+ const shell = new Shell({
+ name: 'cli',
+ commands: [{
+ name: 'account',
+ description: 'Perform operations on a user account.',
+
+ handler (meta, cb) {
+ console.log('TODO: Output account details')
+ cb()
+ },
+
+ commands: [
+ {
+ name: 'create',
+ description: 'Create a user account.',
+ arguments: 'email password',
+
+ flags: {
+ name: {
+ alias: 'n',
+ description: 'Account display name'
+ },
+
+ phone: {
+ alias: 'p',
+ description: 'Account phone number'
+ },
+
+ avatar: {
+ alias: 'a',
+ description: 'Account avatar image URL'
+ },
+
+ validate: {
+ alias: 'v',
+ description: 'Validate email'
+ }
+ },
+
+ handler (meta, cb) {
+ t.ok(meta.flag('email') === 'test@domain.com', 'Correct')
+ t.ok(meta.flag('password') === 'pwd', 'Correct')
+ t.end()
+ }
+ },
+
+ {
+ name: 'delete',
+ description: 'Delete your Metadoc account',
+
+ handler (meta, cb) {
+ const confirmed = window.confirm('All your preferences, notes, bookmarks, and workspaces will be PERMANENTLY DELETED. THIS CANNOT BE UNDONE. Are you sure you want to delete your account?')
+
+ if (!confirmed) {
+ return
+ }
+
+ API.run('deleteAccount', meta.data, err => {
+ if (err) {
+ return alert(err.message)
+ }
+
+ console.log('DELETED')
+ })
+ }
+ },
+
+ {
+ name: 'verify',
+ description: 'Verify an account',
+ arguments: 'code',
+
+ handler (meta, cb) {
+ API.run('verifyAccount', meta.data, err => {
+ if (err) {
+ return alert(err.message)
+ }
+
+ console.log('VERIFIED')
+ })
+ }
+ }
+ ]
+ }]
+ })
+
+ shell.exec('account create test@domain.com pwd')
+})
From 5bdc1d04defab54554d53c0816d4c54e1ae81b66 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 4 May 2020 14:59:00 -0500
Subject: [PATCH 053/152] Add Node 14 to test suite
---
.travis.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.travis.yml b/.travis.yml
index ba798fc..f501893 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,7 @@
language: node_js
node_js:
- '13.5.0'
+- '14.0.0'
install:
- npm run setup
From c7ba7cbbdf83a2fd8098cf6ee068599178a02bb9 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 4 May 2020 15:09:09 -0500
Subject: [PATCH 054/152] Update test suite to prevent running in browser
(Sauce Labs always fails)
---
.travis.yml | 3 +-
test/unit/01-sanity/04-metadata.js | 46 +++---------------------------
2 files changed, 6 insertions(+), 43 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index f501893..b99cef3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,6 +9,7 @@ install:
- cd ./test && rm -rf node_modules/yaml && npm i yaml@1.7.2 && cd ../
script:
- - npm test
+ # Only run node tests since sauce labs fails all the time
+ - npm run test:browser
# - ls -l
# - cd ./test && ls -l && npm run node
\ No newline at end of file
diff --git a/test/unit/01-sanity/04-metadata.js b/test/unit/01-sanity/04-metadata.js
index f7bc854..50daf2e 100644
--- a/test/unit/01-sanity/04-metadata.js
+++ b/test/unit/01-sanity/04-metadata.js
@@ -108,7 +108,7 @@ test('Map unnamed arguments when duplicate names are supplied', t => {
.finally(() => t.end())
})
-test('wtf', t => {
+test('Ordered Named Arguments', t => {
const shell = new Shell({
name: 'cli',
commands: [{
@@ -116,7 +116,6 @@ test('wtf', t => {
description: 'Perform operations on a user account.',
handler (meta, cb) {
- console.log('TODO: Output account details')
cb()
},
@@ -124,7 +123,7 @@ test('wtf', t => {
{
name: 'create',
description: 'Create a user account.',
- arguments: 'email password',
+ arguments: ['email', 'password'],
flags: {
name: {
@@ -149,47 +148,10 @@ test('wtf', t => {
},
handler (meta, cb) {
- t.ok(meta.flag('email') === 'test@domain.com', 'Correct')
- t.ok(meta.flag('password') === 'pwd', 'Correct')
+ t.ok(meta.flag('email') === 'test@domain.com', 'Correctly identifies first name argument')
+ t.ok(meta.flag('password') === 'pwd', 'Correct identifies second name argument')
t.end()
}
- },
-
- {
- name: 'delete',
- description: 'Delete your Metadoc account',
-
- handler (meta, cb) {
- const confirmed = window.confirm('All your preferences, notes, bookmarks, and workspaces will be PERMANENTLY DELETED. THIS CANNOT BE UNDONE. Are you sure you want to delete your account?')
-
- if (!confirmed) {
- return
- }
-
- API.run('deleteAccount', meta.data, err => {
- if (err) {
- return alert(err.message)
- }
-
- console.log('DELETED')
- })
- }
- },
-
- {
- name: 'verify',
- description: 'Verify an account',
- arguments: 'code',
-
- handler (meta, cb) {
- API.run('verifyAccount', meta.data, err => {
- if (err) {
- return alert(err.message)
- }
-
- console.log('VERIFIED')
- })
- }
}
]
}]
From 8caa646d4bb9e94384d76847dc2371a1d5772adf Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 4 May 2020 15:12:07 -0500
Subject: [PATCH 055/152] Updated to node only
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index b99cef3..f027827 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,6 +10,6 @@ install:
script:
# Only run node tests since sauce labs fails all the time
- - npm run test:browser
+ - npm run test:node
# - ls -l
# - cd ./test && ls -l && npm run node
\ No newline at end of file
From 845e1b440e33d5fe43a483a41eafb8b9a52726c8 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 4 May 2020 15:21:13 -0500
Subject: [PATCH 056/152] Added keyword for search
---
package.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 46f42d6..a4ef2d2 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,8 @@
"keywords": [
"cli",
"args",
- "arg"
+ "arg",
+ "shell"
],
"author": "Corey Butler",
"license": "MIT",
From 7de541fe83483c33956136174c3db1d43aef2a24 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 4 May 2020 15:35:50 -0500
Subject: [PATCH 057/152] Updated reset process to not remove the .github
folder
---
.github/FUNDING.yml | 12 ++++
.github/workflows/deploy.yml | 131 +++++++++++++++++++++++++++++++++++
build/lib/reset.js | 4 +-
3 files changed, 145 insertions(+), 2 deletions(-)
create mode 100644 .github/FUNDING.yml
create mode 100644 .github/workflows/deploy.yml
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..eaf9b65
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: coreybutler
+patreon: # coreybutler
+open_collective: # Replace with a single Open Collective username
+ko_fi: # Replace with a single Ko-fi username
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
\ No newline at end of file
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
new file mode 100644
index 0000000..609c374
--- /dev/null
+++ b/.github/workflows/deploy.yml
@@ -0,0 +1,131 @@
+name: Tag, Release, & Publish
+
+on:
+ push:
+ branches:
+ - master
+
+jobs:
+ build:
+ name: 'Build & Release'
+ runs-on: ubuntu-latest
+ steps:
+ # Checkout updated source code
+ - uses: actions/checkout@v2
+
+ # If the version has changed, create a new git tag for it.
+ - name: Tag
+ id: autotagger
+ uses: butlerlogic/action-autotag@master
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ # The remaining steps all depend on whether or not
+ # a new tag was created. There is no need to release/publish
+ # updates until the code base is in a releaseable state.
+
+ # If the new version/tag is a pre-release (i.e. 1.0.0-beta.1), create
+ # an environment variable indicating it is a prerelease.
+ - name: Pre-release
+ if: steps.autotagger.outputs.tagname != ''
+ run: |
+ if [[ "${{ steps.autotagger.output.version }}" == *"-"* ]]; then echo "::set-env IS_PRERELEASE=true";else echo "::set-env IS_PRERELEASE=''";fi
+
+ # Create a github release
+ # This will create a snapshot of the module,
+ # available in the "Releases" section on Github.
+ - name: Release
+ id: create_release
+ if: steps.autotagger.outputs.tagname != ''
+ uses: actions/create-release@v1.0.0
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ tag_name: ${{ steps.autotagger.outputs.tagname }}
+ release_name: ${{ steps.autotagger.outputs.tagname }}
+ body: ${{ steps.autotagger.outputs.tagmessage }}
+ draft: false
+ prerelease: env.IS_PRERELEASE != ''
+
+ - uses: actions/setup-node@v1
+ if: steps.create_release.outputs.id != ''
+ with:
+ node-version: '13'
+
+ # Build tarballs of the module code.
+ - name: Build Release Artifacts
+ id: build_release
+ if: steps.create_release.outputs.id != ''
+ run: |
+ npm install
+ cd ./build && npm install && cd ../
+ npm run build --if-present
+ for d in .dist/*/*/ ; do tar -cvzf ${d%%/}-${{ steps.autotagger.outputs.version }}.tar.gz ${d%%}*; done;
+ if [[ ${{ github.ref }} == *"-"* ]]; then echo ::set-output isprerelease=true;else echo ::set-output isprerelease=false;fi
+ # Upload tarballs to the release.
+ - name: Upload Release Artifacts
+ uses: AButler/upload-release-assets@v2.0
+ if: steps.create_release.outputs.id != ''
+ with:
+ files: './.dist/**/*.tar.gz'
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ release-tag: ${{ steps.autotagger.outputs.tagname }}
+
+ # Build npm packages
+ - name: Build Module Artifacts
+ id: build_npm
+ if: steps.create_release.outputs.id != ''
+ run: |
+ npm install
+ cd ./build && npm install && cd ../
+ npm run build --if-present
+ # Use this action to publish a single module to npm.
+ - name: Publish
+ id: publish_npm
+ if: steps.autotagger.outputs.tagname != ''
+ uses: author/action-publish@master
+ with:
+ scan: .dist
+ env:
+ REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
+
+ - name: Rollback Release
+ if: failure() && steps.create_release.outputs.id != ''
+ uses: author/action-rollback@stable
+ with:
+ tag: ${{ steps.autotagger.outputs.tagname }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Failure Notification
+ if: failure() && steps.create_release.outputs.id != ''
+ env:
+ SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
+ SLACK_USERNAME: Github # Optional. (defaults to webhook app)
+ SLACK_CHANNEL: author # Optional. (defaults to webhook)
+ SLACK_AVATAR: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/320px-Npm-logo.svg.png"
+ uses: Ilshidur/action-slack@master
+ with:
+ args: '@author.io/shell ${{ steps.autotagger.outputs.tagname }} failed to publish and was rolled back.' # Optional
+
+ - name: Success Notification
+ if: success() && steps.autotagger.outputs.tagname != ''
+ env:
+ SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
+ SLACK_USERNAME: Github # Optional. (defaults to webhook app)
+ SLACK_CHANNEL: author # Optional. (defaults to webhook)
+ SLACK_AVATAR: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/320px-Npm-logo.svg.png"
+ uses: Ilshidur/action-slack@master
+ with:
+ args: '@author.io/shell ${{ steps.autotagger.outputs.tagname }} published to npm.' # Optional
+
+ - name: Inaction Notification
+ if: steps.autotagger.outputs.tagname == ''
+ env:
+ SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
+ SLACK_USERNAME: Github # Optional. (defaults to webhook app)
+ SLACK_CHANNEL: author # Optional. (defaults to webhook)
+ SLACK_AVATAR: "https://cdn.freebiesupply.com/logos/large/2x/nodejs-icon-logo-png-transparent.png" # Optional. can be (repository, sender, an URL) (defaults to webhook app avatar)
+ uses: Ilshidur/action-slack@master
+ with:
+ args: "New code was added to author/shell master branch." # Optional
\ No newline at end of file
diff --git a/build/lib/reset.js b/build/lib/reset.js
index cfac5c0..1d2eada 100644
--- a/build/lib/reset.js
+++ b/build/lib/reset.js
@@ -5,8 +5,8 @@ fs
.readdirSync(path.resolve('./'))
.forEach(filepath => {
const fullpath = path.resolve(filepath)
- if (filepath.startsWith('.') && filepath !== '.git' && fs.statSync(fullpath).isDirectory()) {
+ if (filepath.startsWith('.') && filepath !== '.github' && filepath !== '.git' && fs.statSync(fullpath).isDirectory()) {
fs.rmdirSync(filepath, { recursive: true })
console.log(`Removed ${fullpath}`)
}
- })
\ No newline at end of file
+ })
From 52c913ea9c5a5e8e28b1dda1f396fd9c36219613 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 4 May 2020 21:59:22 -0500
Subject: [PATCH 058/152] Updated table dependency to support hard-split of
oversized columns in help output.
---
package.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index a4ef2d2..2ff08f8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.4",
+ "version": "1.5.5",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
@@ -53,6 +53,6 @@
},
"dependencies": {
"@author.io/arg": "^1.3.1",
- "@author.io/table": "^1.0.1"
+ "@author.io/table": "^1.0.2"
}
}
From 351bc4629f50e72e0f735b018143ce586f320a19 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 5 May 2020 00:45:51 -0500
Subject: [PATCH 059/152] Dependency version bump (fixed arg regression).
---
package.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index 2ff08f8..02cf241 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.5",
+ "version": "1.5.6",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
@@ -52,7 +52,7 @@
]
},
"dependencies": {
- "@author.io/arg": "^1.3.1",
+ "@author.io/arg": "^1.3.2",
"@author.io/table": "^1.0.2"
}
}
From e18af891b15590a2b07d11fce302bd2c265be8b2 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 5 May 2020 14:54:53 -0500
Subject: [PATCH 060/152] Added support for displaying subcommand help in
default help message.
---
package-lock.json | 14 +++++++-------
package.json | 2 +-
src/format.js | 43 ++++++++++++++++++++++++++++---------------
3 files changed, 36 insertions(+), 23 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 36f62b4..1bb398f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,18 +1,18 @@
{
"name": "@author.io/shell",
- "version": "1.5.4",
+ "version": "1.5.7",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@author.io/arg": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.1.tgz",
- "integrity": "sha512-yD/ZIBYLFDIqBE2MAnZ/uCgtm0Mp+OL0TAHWsJOFdtqoSnVwJhm17A8F13/LOk2hO/wqM4UqxbQeG108b0Z36w=="
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.2.tgz",
+ "integrity": "sha512-QGmAzBltGO4euYckWAwyt4e1tv4UQuA1skNzho/WXsD9ys4j0tnb4ISwh/ShnU/hjpU/OtvpMJTAoqKIobE/Vg=="
},
"@author.io/table": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.0.1.tgz",
- "integrity": "sha512-WbLWxBtZOSUeXFTQQO/OINifAFYJtU6pwTrh8b0gdqLRkQRoaHM3ymEa+KYbLuCbbexMt8oULDXbIyY88h/0zw=="
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.0.2.tgz",
+ "integrity": "sha512-LF/qv0/+yZ+qHT+iWtFjVx6Vq4Cm8NaoF3dCjdqhzGT7wtZHViqUb/2zc86mOZTdtZGwcVV6JZt1GgoZXtGCYw=="
}
}
}
diff --git a/package.json b/package.json
index 02cf241..db7547c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.6",
+ "version": "1.5.7",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/format.js b/src/format.js
index 8b40547..2e9903e 100644
--- a/src/format.js
+++ b/src/format.js
@@ -31,6 +31,10 @@ class Formatter {
const aliases = this.#data.aliases
const out = [`${this.#data.commandroot}${aliases.length > 0 ? '|' + aliases.join('|') : ''}${this.#data.__flagConfig.size > 0 ? ' [FLAGS]' : ''}${this.#data.arguments.size > 0 ? ' ' + Array.from(this.#data.arguments).map(i => '<' + i + '>').join(', ') : ''}`]
+ if (this.#data.__processors.size > 0) {
+ out[out.length - 1] += (this.#data.arguments.size > 0 || this.#data.__flagConfig.size > 0 ? ' |' : '') + ' [COMMAND]'
+ }
+
if (desc.trim().length > 0 && out !== desc) {
out.push(new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output)
}
@@ -43,6 +47,23 @@ class Formatter {
return ''
}
+ get subcommands () {
+ const rows = Array.from(this.#data.__processors.values()).map(cmd => {
+ let nm = [cmd.name].concat(cmd.aliases)
+ return [nm.join('|'), cmd.description]
+ })
+
+ let result = []
+
+ if (rows.length > 0) {
+ const table = new Table(rows, this.#colAlign, ['25%', '75%'], this.#tableWidth, [2])
+ result.push(`\nCommands:\n`)
+ result.push(table.output)
+ }
+
+ return result.join('\n')
+ }
+
get help () {
const usage = this.usage.trim()
@@ -80,22 +101,14 @@ class Formatter {
}
const table = new Table(rows, this.#colAlign, this.#colWidth, this.#tableWidth, [2, 0, usage.length > 0 ? 1 : 0, 0])
- return usage + (flags.size > 0 ? '\n\nFlags:' + table.output : '')
- } else if (this.#data instanceof Shell) {
- const rows = Array.from(this.#data.__processors.values()).map(cmd => {
- let nm = [cmd.name].concat(cmd.aliases)
- return [nm.join('|'), cmd.description]
- })
-
- let result = [usage]
-
- if (rows.length > 0) {
- const table = new Table(rows, this.#colAlign, ['25%', '75%'], this.#tableWidth, [2])
- result.push(`\nCommands:\n`)
- result.push(table.output)
- }
- return result.join('\n')
+ let subcommands = '\n' + this.subcommands
+ if (subcommands.trim().length === 0) {
+ subcommands = ''
+ }
+ return usage + (flags.size > 0 ? '\n\nFlags:' + table.output : '') + subcommands
+ } else if (this.#data instanceof Shell) {
+ return [usage, this.subcommands].join('\n')
}
return ''
From 98cf8a47b0ac219e168fde5db9ba59c2d032fadf Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 5 May 2020 17:01:58 -0500
Subject: [PATCH 061/152] Remove erroneous console.log
---
package-lock.json | 2 +-
package.json | 2 +-
src/base.js | 1 -
3 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 1bb398f..cfc71c3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.7",
+ "version": "1.5.8",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index db7547c..ee61379 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.7",
+ "version": "1.5.8",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/base.js b/src/base.js
index 9c5da3a..16e091e 100644
--- a/src/base.js
+++ b/src/base.js
@@ -190,7 +190,6 @@ export default class Base {
writable: false,
value: cfg => {
if (cfg.hasOwnProperty('describeDefault') && typeof cfg.describeDefault === 'boolean') {
- console.log('HERE')
this.#display.Default = cfg.describeDefault
}
if (cfg.hasOwnProperty('describeOptions') && typeof cfg.describeOptions === 'boolean') {
From 287bfdde05020e9a01b5b285a27b4d3da2014806 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 5 May 2020 18:07:14 -0500
Subject: [PATCH 062/152] Removed commas from argument list in default usage
message.
---
package.json | 2 +-
src/format.js | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/package.json b/package.json
index ee61379..eb383e2 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.8",
+ "version": "1.5.9",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/format.js b/src/format.js
index 2e9903e..03c8533 100644
--- a/src/format.js
+++ b/src/format.js
@@ -29,7 +29,7 @@ class Formatter {
if (this.#data instanceof Command) {
const aliases = this.#data.aliases
- const out = [`${this.#data.commandroot}${aliases.length > 0 ? '|' + aliases.join('|') : ''}${this.#data.__flagConfig.size > 0 ? ' [FLAGS]' : ''}${this.#data.arguments.size > 0 ? ' ' + Array.from(this.#data.arguments).map(i => '<' + i + '>').join(', ') : ''}`]
+ const out = [`${this.#data.commandroot}${aliases.length > 0 ? '|' + aliases.join('|') : ''}${this.#data.__flagConfig.size > 0 ? ' [FLAGS]' : ''}${this.#data.arguments.size > 0 ? ' ' + Array.from(this.#data.arguments).map(i => '<' + i + '>').join(' ') : ''}`]
if (this.#data.__processors.size > 0) {
out[out.length - 1] += (this.#data.arguments.size > 0 || this.#data.__flagConfig.size > 0 ? ' |' : '') + ' [COMMAND]'
@@ -41,7 +41,7 @@ class Formatter {
return out.join('\n')
} else if (this.#data instanceof Shell) {
- return `${this.#data.name}${this.#data.__processors.size > 0 ? ' [COMMAND]' : ''}\n${desc.trim().length > 0 ? new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output : ''}${this.#data.arguments.size > 0 ? ' ' + Array.from(this.#data.arguments).map(i => '[' + i + ']').join(', ') : ''}\n`.trim()
+ return `${this.#data.name}${this.#data.__processors.size > 0 ? ' [COMMAND]' : ''}\n${desc.trim().length > 0 ? new Table([[desc.trim().replace(/\n/gi, '\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output : ''}${this.#data.arguments.size > 0 ? ' ' + Array.from(this.#data.arguments).map(i => '[' + i + ']').join(' ') : ''}\n`.trim()
}
return ''
From 6843fa2019efaeb3cbfd4b1d2ebfad58440ec3d7 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 5 May 2020 18:32:11 -0500
Subject: [PATCH 063/152] Updated arg dependency to provide case-sensitive
unrecognized flag values (useful for arguments).
---
package-lock.json | 8 ++++----
package.json | 4 ++--
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index cfc71c3..d1f4c7d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,13 +1,13 @@
{
"name": "@author.io/shell",
- "version": "1.5.8",
+ "version": "1.5.10",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@author.io/arg": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.2.tgz",
- "integrity": "sha512-QGmAzBltGO4euYckWAwyt4e1tv4UQuA1skNzho/WXsD9ys4j0tnb4ISwh/ShnU/hjpU/OtvpMJTAoqKIobE/Vg=="
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.3.tgz",
+ "integrity": "sha512-TpBNJ0r6YbTwXeLci36GHZLHZx/9gWu9bBFNAinTgEY7H+oTt7OexYKce5UVrYG440Hc60jWZ4pelKCqlgAcIA=="
},
"@author.io/table": {
"version": "1.0.2",
diff --git a/package.json b/package.json
index eb383e2..b92df44 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.9",
+ "version": "1.5.10",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
@@ -52,7 +52,7 @@
]
},
"dependencies": {
- "@author.io/arg": "^1.3.2",
+ "@author.io/arg": "^1.3.3",
"@author.io/table": "^1.0.2"
}
}
From b607a1e352e1bc7d9862632a0fed35285406c2be Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 6 May 2020 18:59:13 -0500
Subject: [PATCH 064/152] Tweaked default help output to follow consistent
spacing patterns. Added a global reference (symbol) that can be detected by
devtools.
---
.gitignore | 1 +
src/command.js | 2 +-
src/format.js | 2 +-
src/shell.js | 3 +++
test/unit/01-sanity/01-sanity.js | 3 +++
5 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/.gitignore b/.gitignore
index 178c500..2190ef9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@
!.*.yml
node_modules
test/output/**/*
+test/*.txt
/**/*.old
test/package-lock.json
build/package-lock.json
diff --git a/src/command.js b/src/command.js
index 37a51fb..59eba05 100644
--- a/src/command.js
+++ b/src/command.js
@@ -45,7 +45,7 @@ export default class Command extends Base {
this.#pattern = cfg.pattern || /[\s\S]+/i
if (cfg.alias && !cfg.aliases) {
- cfg.aliases = Array.isArray(cfg.alias) ? cfg.alias : [cfg.alias]
+ cfg.aliases = typeof cfg.alias === 'string' ? [cfg.alias] : (Array.isArray(cfg.alias) ? cfg.alias : Array.from(cfg.alias))
delete cfg.alias
}
diff --git a/src/format.js b/src/format.js
index 03c8533..0b8e1ca 100644
--- a/src/format.js
+++ b/src/format.js
@@ -106,7 +106,7 @@ class Formatter {
if (subcommands.trim().length === 0) {
subcommands = ''
}
- return usage + (flags.size > 0 ? '\n\nFlags:' + table.output : '') + subcommands
+ return usage + (flags.size > 0 ? '\n\nFlags:\n' + table.output : '') + subcommands
} else if (this.#data instanceof Shell) {
return [usage, this.subcommands].join('\n')
}
diff --git a/src/shell.js b/src/shell.js
index 999a718..0c584b3 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -38,6 +38,9 @@ export default class Shell extends Base {
this.#version = cfg.version || '1.0.0'
this.#maxHistoryItems = cfg.maxhistory || cfg.maxHistoryItems || 100
this.#tabWidth = cfg.hasOwnProperty('tabWidth') ? cfg.tabWidth : 4
+
+ // This sets a global symbol that dev tools can find.
+ Object.defineProperty(globalThis, Symbol('SHELL_INTEGRATIONS'), { enumerable: false, get () { return this }})
}
get data () {
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index ad61253..d6c61eb 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -2,6 +2,7 @@ import 'source-map-support/register.js'
import test from 'tape'
import { Command, Shell, Formatter } from '../../.node/index.js'
// import fs from 'fs'
+// import path from 'path'
test('Sanity Check - Shell', t => {
const shell = new Shell({
@@ -80,9 +81,11 @@ test('Output Formatting', t => {
t.ok(formatter instanceof Formatter, 'Basic formatter instantiates correctly.')
// fs.writeFileSync('./test.txt', Buffer.from(formatter.help))
+ // console.log(formatter.help)
t.ok(formatter.help === `test cmd|c [FLAGS]
Flags:
+
-test [-t] test description
-more [-m, -mr] This is a longer description that should break onto
more than one line, or perhaps even more than one
From 44777f2ae2cdcf118838e7d82a3897b0622c0465 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 6 May 2020 18:59:27 -0500
Subject: [PATCH 065/152] Version bump
---
package-lock.json | 2 +-
package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index d1f4c7d..520e7ae 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.10",
+ "version": "1.5.11",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index b92df44..cc68102 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.10",
+ "version": "1.5.11",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
From 467754d92e094402421d2cf5a7885763c6d16869 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 6 May 2020 21:35:10 -0500
Subject: [PATCH 066/152] Fix discoverability feature (devtooling).
---
package-lock.json | 2 +-
package.json | 2 +-
src/shell.js | 2 +-
test/unit/01-sanity/01-sanity.js | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 520e7ae..b2d95e1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.11",
+ "version": "1.5.12",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index cc68102..094d045 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.11",
+ "version": "1.5.12",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/shell.js b/src/shell.js
index 0c584b3..7fa3bf2 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -40,7 +40,7 @@ export default class Shell extends Base {
this.#tabWidth = cfg.hasOwnProperty('tabWidth') ? cfg.tabWidth : 4
// This sets a global symbol that dev tools can find.
- Object.defineProperty(globalThis, Symbol('SHELL_INTEGRATIONS'), { enumerable: false, get () { return this }})
+ globalThis[Symbol('SHELL_INTEGRATIONS')] = this
}
get data () {
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index d6c61eb..7dcc7f6 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -10,7 +10,7 @@ test('Sanity Check - Shell', t => {
})
t.ok(shell instanceof Shell, 'Basic shell instantiates correctly.')
-
+ t.ok(Object.getOwnPropertySymbols(globalThis).filter(s => globalThis[s] instanceof Shell).length === 1, 'The shell is discoverable.')
t.end()
})
From ea354ccbef6bda7362c9fa8a72e05189b9ef7a79 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sat, 9 May 2020 09:55:36 -0500
Subject: [PATCH 067/152] Added clear command.
---
src/shell.js | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/shell.js b/src/shell.js
index 7fa3bf2..08b14cb 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -179,4 +179,12 @@ export default class Shell extends Base {
return results.flat(Infinity)
}
+
+ // Clear the terminal
+ clear () {
+ console.clear()
+ // .write('\x1b[0f') // regular clear
+ // .write('\x1b[2J') // full clear
+ // .write('\033[0;0f') //ubuntu
+ }
}
From b51e3d48088308cfd93ed7c03fd6c42f72d3cfc4 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sat, 9 May 2020 15:28:18 -0500
Subject: [PATCH 068/152] Updated dependencies (fixed a regression in the table
lib)
---
package-lock.json | 8 ++++----
package.json | 4 ++--
src/base.js | 14 ++++++++------
test/unit/01-sanity/01-sanity.js | 25 +++++++++++++++++++++++++
test/unit/01-sanity/100-regression.js | 27 +++++++++++++++++++++++++++
5 files changed, 66 insertions(+), 12 deletions(-)
create mode 100644 test/unit/01-sanity/100-regression.js
diff --git a/package-lock.json b/package-lock.json
index b2d95e1..d6e0e41 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.12",
+ "version": "1.5.13",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -10,9 +10,9 @@
"integrity": "sha512-TpBNJ0r6YbTwXeLci36GHZLHZx/9gWu9bBFNAinTgEY7H+oTt7OexYKce5UVrYG440Hc60jWZ4pelKCqlgAcIA=="
},
"@author.io/table": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.0.2.tgz",
- "integrity": "sha512-LF/qv0/+yZ+qHT+iWtFjVx6Vq4Cm8NaoF3dCjdqhzGT7wtZHViqUb/2zc86mOZTdtZGwcVV6JZt1GgoZXtGCYw=="
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.0.3.tgz",
+ "integrity": "sha512-JnsndB8kzcyLwYp42teOpdICCP4KZHmzOlFnL/uxfQCxGrQKEIH8Occq8LFQXO7OKri/tOYG5mOhrWxxuoRyzw=="
}
}
}
diff --git a/package.json b/package.json
index 094d045..a7cba6b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.12",
+ "version": "1.5.13",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
@@ -53,6 +53,6 @@
},
"dependencies": {
"@author.io/arg": "^1.3.3",
- "@author.io/table": "^1.0.2"
+ "@author.io/table": "^1.0.3"
}
}
diff --git a/src/base.js b/src/base.js
index 16e091e..45bccbb 100644
--- a/src/base.js
+++ b/src/base.js
@@ -204,6 +204,8 @@ export default class Base {
}
}
})
+
+ this.updateHelp()
}
get name () {
@@ -270,17 +272,17 @@ export default class Base {
return typeof this.#customUsage === 'function' ? this.#customUsage() : this.#customUsage
}
- this.updateHelp()
-
return this.#formattedDefaultHelp.usage
}
set usage (value) {
if (typeof value === 'string' && value.trim().length === 0) {
- this.#customUsage = null
+ value = null
}
this.#customUsage = value
+
+ this.updateHelp()
}
get help () {
@@ -292,17 +294,17 @@ export default class Base {
return ''
}
- this.updateHelp()
-
return this.#formattedDefaultHelp.help
}
set help (value) {
if (typeof value === 'string' && value.trim().length === 0) {
- this.#customHelp = null
+ value = null
}
this.#customHelp = value
+
+ this.updateHelp()
}
// @private
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index 7dcc7f6..af0cbb7 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -167,3 +167,28 @@ test('Default command help (regression test)', t => {
t.pass('Ran without error.')
t.end()
})
+
+test('Basic Introspection', t => {
+ const shell = new Shell({
+ name: 'test',
+ version: '1.0.0',
+ disableHelp: true,
+ commands: [
+ {
+ name: 'account',
+ description: 'Perform operations on a user account.',
+ handler: (meta, cb) => { },
+ commands: [
+ {
+ name: 'create',
+ description: 'Create a user account.',
+ arguments: ''
+ }
+ ]
+ }
+ ]
+ })
+
+ t.ok(typeof shell.data === 'object', 'Generates a data object representing the shell.')
+ t.end()
+})
diff --git a/test/unit/01-sanity/100-regression.js b/test/unit/01-sanity/100-regression.js
new file mode 100644
index 0000000..14f1384
--- /dev/null
+++ b/test/unit/01-sanity/100-regression.js
@@ -0,0 +1,27 @@
+import 'source-map-support/register.js'
+import test from 'tape'
+import { Shell } from '../../.node/index.js'
+
+// The range error was caused by the underlying table library.
+// When a default help message was generated, a negative column
+// width (representing "infinite" width) was not being converted
+// to the width of the content, causing a method to execute infinitely.
+test('Extending shell creates RangeError for data attribute', t => {
+ class CLIClient extends Shell {
+ exec (input, cb) {
+ console.log(input)
+ super.exec(...arguments)
+ }
+ }
+
+ const sh = new CLIClient({
+ name: 'test',
+ commands: [{
+ name: 'cmd',
+ handler () {}
+ }]
+ })
+
+ t.ok(sh.data.name === 'test', 'Extended shell still provides underlying data.')
+ t.end()
+})
From 200b50ae4f35fa23c1411a2d8ffd797116412f9c Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 11 May 2020 16:40:39 -0500
Subject: [PATCH 069/152] Updated command history to use cursors. Fixed history
method for exposing history to developer.
---
package-lock.json | 2 +-
package.json | 2 +-
src/shell.js | 21 +++++++++++++----
test/unit/01-sanity/06-history.js | 38 +++++++++++++++++++++++++++++++
4 files changed, 57 insertions(+), 6 deletions(-)
create mode 100644 test/unit/01-sanity/06-history.js
diff --git a/package-lock.json b/package-lock.json
index d6e0e41..ae1305a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.13",
+ "version": "1.5.14",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index a7cba6b..55384ff 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.13",
+ "version": "1.5.14",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/shell.js b/src/shell.js
index 08b14cb..d0d18b9 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -79,34 +79,47 @@ export default class Shell extends Base {
return []
}
- return this.#history.slice(0, count)
+ return count === null ? this.#history.slice() : this.#history.slice(0, count)
}
priorCommand (count = 0) {
+ if (this.#history.length === 0) {
+ return null
+ }
+
if (count < 0) {
return this.nextCommand(abs(count))
}
+ count = count % this.#history.length
+
this.#cursor += count
if (this.#cursor >= this.#history.length) {
this.#cursor = this.#history.length - 1
}
- return this.#history[this.#cursor]
+ return this.#history[this.#cursor].input
}
nextCommand (count = 1) {
+ if (this.#history.length === 0) {
+ return null
+ }
+
if (count < 0) {
return this.priorCommand(abs(count))
}
+ count = count % this.#history.length
+
this.#cursor -= count
if (this.#cursor < 0) {
this.#cursor = 0
+ return undefined
}
- return this.#history[this.#cursor]
+ return this.#history[this.#cursor].input
}
useWith (commands) {
@@ -126,7 +139,7 @@ export default class Shell extends Base {
}
async exec (input, callback) {
- this.#history.shift({ input, time: new Date().toLocaleString()})
+ this.#history.unshift({ input, time: new Date().toLocaleString()})
if (this.#history.length > this.#maxHistoryItems) {
this.#history.pop()
diff --git a/test/unit/01-sanity/06-history.js b/test/unit/01-sanity/06-history.js
new file mode 100644
index 0000000..d83f965
--- /dev/null
+++ b/test/unit/01-sanity/06-history.js
@@ -0,0 +1,38 @@
+import 'source-map-support/register.js'
+import test from 'tape'
+import { Shell } from '../../.node/index.js'
+
+test('Basic History', t => {
+ const sh = new Shell({
+ name: 'test',
+ maxhistory: 3,
+ commands: [{
+ name: 'cmd',
+ handler () { }
+ }]
+ })
+
+ sh.exec('cmd a')
+ sh.exec('cmd b')
+ sh.exec('cmd c')
+
+ t.ok(sh.history().length === 3, `Received a history of 3 items. Recognized ${sh.history().length}`)
+
+ sh.exec('cmd d')
+ t.ok(sh.history().length === 3 &&
+ sh.history()[0].input === 'cmd d' &&
+ sh.history()[2].input === 'cmd b',
+ `Received a history of 3 items, respecting maximum history levels. Recognized ${sh.history().length}`
+ )
+
+ let c = sh.priorCommand()
+ t.ok(c === 'cmd d', `Recognized prior command (cmd d). Returned ${c}`)
+ c = sh.nextCommand()
+ t.ok(c === undefined, 'Next command returns undefined when it does not exist.')
+ c = sh.priorCommand(1)
+ t.ok(c === 'cmd c', `Recognized 2 prior commands (cmd b). Returned ${c}`)
+ c = sh.nextCommand()
+ t.ok(c === 'cmd d', 'Next command returns proper command when it exists.' + `cmd d = ${c}`)
+
+ t.end()
+})
From 15974c89fa5a3dba2812aacf28d5c22e2747f276 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 13 May 2020 00:41:03 -0500
Subject: [PATCH 070/152] Added hint feature for shell, with tests. Abstracted
constant Regex patterns into a utility module.
---
src/command.js | 9 ++---
src/shell.js | 60 ++++++++++++++++++++++++++++++--
src/utility.js | 24 +++++++++++++
test/unit/01-sanity/07-hints.js | 61 +++++++++++++++++++++++++++++++++
4 files changed, 145 insertions(+), 9 deletions(-)
create mode 100644 src/utility.js
create mode 100644 test/unit/01-sanity/07-hints.js
diff --git a/src/command.js b/src/command.js
index 59eba05..62ec81f 100644
--- a/src/command.js
+++ b/src/command.js
@@ -1,12 +1,7 @@
import { Parser } from '../node_modules/@author.io/arg/index.js'
import Shell from './shell.js'
import Base from './base.js'
-
-// const STRIP_EQUAL_SIGNS = /(\=+)(?=([^'"\\]*(\\.|['"]([^'"\\]*\\.)*[^'"\\]*['"]))*[^'"]*$)/g
-const SUBCOMMAND_PATTERN = /^([^"'][\S\b]+)[\s+]?([^-].*)$/i
-const FLAG_PATTERN = /((?:"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|\/[^\/\\]*(?:\\[\S\s][^\/\\]*)*\/[gimy]*(?=\s|$)|(?:\\\s|\S))+)(?=\s|$)/g
-const METHOD_PATTERN = /^([\w]+\s?)\(.*\)\s?{/i
-const STRIP_QUOTE_PATTERN = /"([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'/ig
+import { METHOD_PATTERN, FLAG_PATTERN, STRIP_QUOTE_PATTERN } from './utility.js'
export default class Command extends Base {
#pattern
@@ -124,7 +119,7 @@ export default class Command extends Base {
__commonFlags: {
enumerable: false,
get () {
- let flags = Object.assign({}, this.__commonflags, this.#flagConfig)
+ let flags = this.__commonflags //Object.assign({}, this.__commonflags, this.#flagConfig)
if (this.parent !== null) {
flags = Object.assign(flags, this.parent.__commonFlags)
diff --git a/src/shell.js b/src/shell.js
index d0d18b9..1ec2330 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -1,7 +1,7 @@
import Command from './command.js'
import Base from './base.js'
-
-const COMMAND_PATTERN = /^(\w+)\s+([\s\S]+)?/i
+import { Parser } from '../node_modules/@author.io/arg/index.js'
+import { COMMAND_PATTERN } from './utility.js'
export default class Shell extends Base {
#middlewareGroups = new Map()
@@ -62,6 +62,62 @@ export default class Shell extends Base {
}
}
+ hint (cmd) {
+ cmd = cmd.toLowerCase()
+ let args = cmd.match(COMMAND_PATTERN)
+ let commands = []
+
+ if (args) {
+ args = args.slice(1)
+
+ commands = Array.from(this.__commands.keys()).filter(name => name.toLowerCase().indexOf(args[0]) >= 0)
+
+ switch (args.length) {
+ case 1:
+ break
+
+ default:
+ if ((['version', 'help']).indexOf(args[0]) >= 0) {
+ return null
+ }
+
+ let command = this.__commands.get(args[0])
+ if (!command) {
+ return null
+ }
+
+ command = this.__processors.get(command)
+ command = command.getTerminalCommand(cmd.replace(new RegExp(`^${args[0]}\\s+`, 'i'), ''))
+ const subcmd = command.command
+ const flags = subcmd.__flagConfig
+
+ return {
+ commands: Array.from(subcmd.__commands.keys()).filter(name => {
+ return name.toLowerCase().indexOf(command.arguments.toLowerCase()) >= 0
+ || subcmd.__processors.get(subcmd.__commands.get(name)).aliases.filter(a => a.toLowerCAse().indexOf(command.arguments) >= 0).length > 0
+ }),
+ flags: Array.from(flags.entries()).filter(keypair => {
+ const name = keypair[0]
+ const flag = keypair.pop()
+
+ return name.toLowerCase().indexOf(command.arguments.toLowerCase()) >= 0
+ || (flag.aliases || []).filter(a => a.toLowerCase().indexOf(command.arguments) >= 0).length > 0
+ || (flag.alias || '').toLowerCase().indexOf(command.arguments) >= 0
+ })
+ }
+ }
+ }
+
+ if (commands.length > 0) {
+ return {
+ commands,
+ flags: []
+ }
+ }
+
+ return null
+ }
+
get version () {
return this.#version || 'Unknown'
}
diff --git a/src/utility.js b/src/utility.js
new file mode 100644
index 0000000..e84de40
--- /dev/null
+++ b/src/utility.js
@@ -0,0 +1,24 @@
+// const STRIP_EQUAL_SIGNS = /(\=+)(?=([^'"\\]*(\\.|['"]([^'"\\]*\\.)*[^'"\\]*['"]))*[^'"]*$)/g
+
+const SUBCOMMAND_PATTERN = /^([^"'][\S\b]+)[\s+]?([^-].*)$/i
+const FLAG_PATTERN = /((?:"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|\/[^\/\\]*(?:\\[\S\s][^\/\\]*)*\/[gimy]*(?=\s|$)|(?:\\\s|\S))+)(?=\s|$)/g
+const METHOD_PATTERN = /^([\w]+\s?)\(.*\)\s?{/i
+const STRIP_QUOTE_PATTERN = /"([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'/ig
+const COMMAND_PATTERN = /^(\w+)\s+([\s\S]+)?/i
+const CONSTANTS = Object.freeze({
+ SUBCOMMAND_PATTERN,
+ FLAG_PATTERN,
+ METHOD_PATTERN,
+ STRIP_QUOTE_PATTERN,
+ COMMAND_PATTERN
+})
+
+export {
+ CONSTANTS as default,
+ CONSTANTS,
+ SUBCOMMAND_PATTERN,
+ FLAG_PATTERN,
+ METHOD_PATTERN,
+ STRIP_QUOTE_PATTERN,
+ COMMAND_PATTERN
+}
diff --git a/test/unit/01-sanity/07-hints.js b/test/unit/01-sanity/07-hints.js
new file mode 100644
index 0000000..090d68c
--- /dev/null
+++ b/test/unit/01-sanity/07-hints.js
@@ -0,0 +1,61 @@
+import 'source-map-support/register.js'
+import test from 'tape'
+import { Shell } from '../../.node/index.js'
+
+test('Basic History', t => {
+ const sh = new Shell({
+ name: 'test',
+ maxhistory: 3,
+ commonflags: {
+ universal: {
+ alias: 'u',
+ description: 'Grand master flash, err, flag.'
+ }
+ },
+ commands: [{
+ name: 'cmd',
+ flags: {
+ main: {
+ alias: 'm',
+ description: 'Main flag.'
+ }
+ },
+ handler () { console.log('test') },
+ commands: [{
+ name: 'subcommand',
+ description: 'This is a subcommand',
+ flags: {
+ flaga: {
+ alias: 'a',
+ description: 'The A team.'
+ },
+ flagb: {
+ alias: 'b',
+ description: 'The B team.',
+ type: String
+ },
+ flagc: {
+ alias: 'c',
+ description: 'The C club.'
+ }
+ },
+ handler () {}
+ }, {
+ name: 'extra',
+ description: 'another cmd',
+ handler () {},
+ commands: [{
+ name: 'more',
+ description: 'nested commands',
+ handler () {}
+ }]
+ }]
+ }]
+ })
+
+ t.ok(typeof sh.hint('cmd ext') === 'object', 'Received a hint object for a valid partial command.')
+ t.ok(sh.hint('xcmd ext') === null, 'Received a null value for an invalid partial command.')
+ t.ok(typeof sh.hint('cmd') === 'object', 'Received a hint object for a valid full command.')
+ t.ok(typeof sh.hint('c') === 'object', 'Received a hint object for a valid partial root command.')
+ t.end()
+})
From 340f018dbed781f457e125489742fb72e4fcc8d2 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 13 May 2020 01:01:19 -0500
Subject: [PATCH 071/152] Updated README to reflect latest updates.
---
README.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/README.md b/README.md
index a53b526..f9ba0e5 100644
--- a/README.md
+++ b/README.md
@@ -696,6 +696,60 @@ console.log(shell.data)
Simple CLI utilities can also be loaded entirely from a JSON file by passing the object into the shell constructor as the only argument. The limitation is no imports or hoisted variables/methods will be recognized in a shell which is loaded this way.
+### Autocompletion/Input Hints
+
+This library provides a _command hinting_ feature using the shell `hint()` method.
+
+Consider the following shell:
+
+```javascript
+const shell = new Shell({
+ name: 'mycli',
+ command: [{
+ name: 'dir',
+ handler () {
+ console.log('ls -l')
+ },
+ // Subcommands
+ commands: [{
+ name: 'perm',
+ description: 'Permissions',
+ handler () {
+ console.log('Display permissions for a directory.')
+ }
+ }, {
+ name: 'payload',
+ description: 'Payload',
+ handler () {
+ console.log('Display payload/footprint for a directory.')
+ }
+ }]
+ }]
+})
+
+// Help us figure out what we can do!
+console.log(shell.hint('dir p'))
+```
+
+_Output:_
+
+```sh
+{
+ commands: ['perm', 'payload'],
+ flags: []
+}
+```
+
+The hint matches "**dir p**ermission" and "**dir p**ayload", but does not match any flags.
+
+If no options/hints are available, `null` is returned.
+
+While this library provides input hints that could be used for suggestions/completions, it does **not** generate autocompletion files for shells like bash, zsh, fish, powershell, etc.
+
+> There are many variations of autocompletion for different shells, which are not available in browsers (see our Devtools extension for browser completion).
+
+If you wish to generate your own autocompletion capabilities, use the `shell.data` attribute to retrieve data for the shell (see prior section). For terminals, consider using the shell metadata with a module like [omlette](https://github.com/f/omelette) to produce autocompletion for your favorite terminal app. For browser-based CLI apps, consider using our devtools extension for an autocompletion experience.
+
## Installation
### Node.js
From 024b4d6610acb4eb56dac5013173a1f0e07c4b90 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 13 May 2020 01:15:51 -0500
Subject: [PATCH 072/152] Version bump
---
package-lock.json | 2 +-
package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index ae1305a..9e795ed 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.14",
+ "version": "1.5.15",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 55384ff..1bc6871 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.14",
+ "version": "1.5.15",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
From a3cbc03bbd6cbc3cc1ef95008db82dffeb18d986 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 13 May 2020 01:47:59 -0500
Subject: [PATCH 073/152] Applied sorting to hinting (now prioritized in most
relevant order).
---
package-lock.json | 2 +-
package.json | 2 +-
src/shell.js | 20 +++++++++++++++-----
test/unit/01-sanity/07-hints.js | 2 +-
4 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 9e795ed..0d5663a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.15",
+ "version": "1.5.16",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 1bc6871..ce4857c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.15",
+ "version": "1.5.16",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/shell.js b/src/shell.js
index 1ec2330..b0884b1 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -65,13 +65,11 @@ export default class Shell extends Base {
hint (cmd) {
cmd = cmd.toLowerCase()
let args = cmd.match(COMMAND_PATTERN)
- let commands = []
-
+ let commands = Array.from(this.__commands.keys()).filter(name => name.toLowerCase().indexOf((args === null ? cmd : args[1]).toLowerCase()) >= 0)
+
if (args) {
args = args.slice(1)
- commands = Array.from(this.__commands.keys()).filter(name => name.toLowerCase().indexOf(args[0]) >= 0)
-
switch (args.length) {
case 1:
break
@@ -95,6 +93,10 @@ export default class Shell extends Base {
commands: Array.from(subcmd.__commands.keys()).filter(name => {
return name.toLowerCase().indexOf(command.arguments.toLowerCase()) >= 0
|| subcmd.__processors.get(subcmd.__commands.get(name)).aliases.filter(a => a.toLowerCAse().indexOf(command.arguments) >= 0).length > 0
+ }).sort((a, b) => {
+ const ai = a.toLowerCase().indexOf(command.arguments.toLowerCase())
+ const bi = b.toLowerCase().indexOf(command.arguments.toLowerCase())
+ return ai < bi ? -1 : (ai > bi ? 1 : 0)
}),
flags: Array.from(flags.entries()).filter(keypair => {
const name = keypair[0]
@@ -103,6 +105,10 @@ export default class Shell extends Base {
return name.toLowerCase().indexOf(command.arguments.toLowerCase()) >= 0
|| (flag.aliases || []).filter(a => a.toLowerCase().indexOf(command.arguments) >= 0).length > 0
|| (flag.alias || '').toLowerCase().indexOf(command.arguments) >= 0
+ }).sort((a, b) => {
+ const ai = a.toLowerCase().indexOf(command.arguments.toLowerCase())
+ const bi = b.toLowerCase().indexOf(command.arguments.toLowerCase())
+ return ai < bi ? -1 : (ai > bi ? 1 : 0)
})
}
}
@@ -110,7 +116,11 @@ export default class Shell extends Base {
if (commands.length > 0) {
return {
- commands,
+ commands: commands.sort((a, b) => {
+ const ai = a.toLowerCase().indexOf(args[0])
+ const bi = b.toLowerCase().indexOf(args[0])
+ return ai < bi ? -1 : (ai > bi ? 1 : 0)
+ }),
flags: []
}
}
diff --git a/test/unit/01-sanity/07-hints.js b/test/unit/01-sanity/07-hints.js
index 090d68c..057e78f 100644
--- a/test/unit/01-sanity/07-hints.js
+++ b/test/unit/01-sanity/07-hints.js
@@ -56,6 +56,6 @@ test('Basic History', t => {
t.ok(typeof sh.hint('cmd ext') === 'object', 'Received a hint object for a valid partial command.')
t.ok(sh.hint('xcmd ext') === null, 'Received a null value for an invalid partial command.')
t.ok(typeof sh.hint('cmd') === 'object', 'Received a hint object for a valid full command.')
- t.ok(typeof sh.hint('c') === 'object', 'Received a hint object for a valid partial root command.')
+ t.ok(typeof sh.hint('c') === 'object' && sh.hint('c').commands.indexOf('cmd') >= 0, 'Received a hint object for a valid partial root command.')
t.end()
})
From 24527791438d24397db8f28ad0c56ad1bda409d8 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Thu, 14 May 2020 14:31:06 -0500
Subject: [PATCH 074/152] Minor fix: repaired hinting.
---
src/shell.js | 96 +++++++++++++++++++++------------
test/unit/01-sanity/07-hints.js | 26 ++++++++-
2 files changed, 86 insertions(+), 36 deletions(-)
diff --git a/src/shell.js b/src/shell.js
index b0884b1..07284c1 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -19,6 +19,12 @@ export default class Shell extends Base {
? globalThis.process.release.name
: 'unknown'
)
+ // Sort hints by string match
+ #hintsort = (matchString, a, b) => {
+ const ai = a.toLowerCase().indexOf(matchString.toLowerCase())
+ const bi = b.toLowerCase().indexOf(matchString.toLowerCase())
+ return ai < bi ? -1 : (ai > bi ? 1 : 0)
+ }
constructor (cfg = { maxhistory: 100 }) {
super(cfg)
@@ -64,68 +70,90 @@ export default class Shell extends Base {
hint (cmd) {
cmd = cmd.toLowerCase()
+ let response = null
let args = cmd.match(COMMAND_PATTERN)
- let commands = Array.from(this.__commands.keys()).filter(name => name.toLowerCase().indexOf((args === null ? cmd : args[1]).toLowerCase()) >= 0)
+ let match = args === null ? cmd : args[1].toLowerCase()
+ let commands = Array.from(this.__commands.keys()).filter(name => name.toLowerCase().indexOf(match) >= 0)
if (args) {
args = args.slice(1)
+ match = args[0]
switch (args.length) {
case 1:
break
default:
- if ((['version', 'help']).indexOf(args[0]) >= 0) {
- return null
+ if ((['version', 'help']).indexOf(match) >= 0) {
+ break
}
- let command = this.__commands.get(args[0])
+ let command = this.__commands.get(match)
if (!command) {
- return null
+ break
}
- command = this.__processors.get(command)
- command = command.getTerminalCommand(cmd.replace(new RegExp(`^${args[0]}\\s+`, 'i'), ''))
+ command = this.__processors.get(command).getTerminalCommand(cmd.replace(new RegExp(`^${match}\\s+`, 'i'), ''))
const subcmd = command.command
const flags = subcmd.__flagConfig
- return {
- commands: Array.from(subcmd.__commands.keys()).filter(name => {
- return name.toLowerCase().indexOf(command.arguments.toLowerCase()) >= 0
- || subcmd.__processors.get(subcmd.__commands.get(name)).aliases.filter(a => a.toLowerCAse().indexOf(command.arguments) >= 0).length > 0
- }).sort((a, b) => {
- const ai = a.toLowerCase().indexOf(command.arguments.toLowerCase())
- const bi = b.toLowerCase().indexOf(command.arguments.toLowerCase())
- return ai < bi ? -1 : (ai > bi ? 1 : 0)
- }),
+ match = command.arguments.toLowerCase()
+
+ response = {
+ commands: Array.from(subcmd.__commands.keys())
+ .filter(name => name.toLowerCase().indexOf(match) >= 0
+ || subcmd.__processors.get(subcmd.__commands.get(name)).aliases
+ .filter(a => a.toLowerCase().indexOf(match) >= 0).length > 0).sort((a, b) => this.#hintsort(match, a, b)
+ ),
flags: Array.from(flags.entries()).filter(keypair => {
- const name = keypair[0]
const flag = keypair.pop()
-
- return name.toLowerCase().indexOf(command.arguments.toLowerCase()) >= 0
- || (flag.aliases || []).filter(a => a.toLowerCase().indexOf(command.arguments) >= 0).length > 0
- || (flag.alias || '').toLowerCase().indexOf(command.arguments) >= 0
- }).sort((a, b) => {
- const ai = a.toLowerCase().indexOf(command.arguments.toLowerCase())
- const bi = b.toLowerCase().indexOf(command.arguments.toLowerCase())
- return ai < bi ? -1 : (ai > bi ? 1 : 0)
- })
+ const name = keypair.pop()
+
+ return name.toLowerCase().indexOf(match) >= 0
+ || (flag.aliases || []).filter(a => a.toLowerCase().indexOf(match) >= 0).length > 0
+ || (flag.alias || '').toLowerCase().indexOf(match) >= 0
+ }).sort((a, b) => this.#hintsort(match, a, b))
}
+
+ break
}
}
- if (commands.length > 0) {
- return {
- commands: commands.sort((a, b) => {
- const ai = a.toLowerCase().indexOf(args[0])
- const bi = b.toLowerCase().indexOf(args[0])
- return ai < bi ? -1 : (ai > bi ? 1 : 0)
- }),
+ if (response === null && commands.length > 0) {
+ response = {
+ commands: commands.sort((a, b) => this.#hintsort(match, a, b)),
flags: []
}
}
- return null
+ if (response !== null) {
+ response.input = cmd
+ response.commands = response.commands.filter(c => c.toLowerCase() !== match).map(c => {
+ return {
+ name: c,
+ match: [
+ c.indexOf(match),
+ c.indexOf(match) + (match.length - 1)
+ ]
+ }
+ })
+
+ response.flags = response.flags.filter(f => f.toLowerCase() !== match).map(f => {
+ return {
+ name: f,
+ match: [
+ f.indexOf(match),
+ f.indexOf(match) + (match.length - 1)
+ ]
+ }
+ })
+
+ if (response.commands.length === 0 && response.flags.length === 0) {
+ return null
+ }
+ }
+
+ return response
}
get version () {
diff --git a/test/unit/01-sanity/07-hints.js b/test/unit/01-sanity/07-hints.js
index 057e78f..9f89f9b 100644
--- a/test/unit/01-sanity/07-hints.js
+++ b/test/unit/01-sanity/07-hints.js
@@ -2,7 +2,7 @@ import 'source-map-support/register.js'
import test from 'tape'
import { Shell } from '../../.node/index.js'
-test('Basic History', t => {
+test('Basic Hinting', t => {
const sh = new Shell({
name: 'test',
maxhistory: 3,
@@ -56,6 +56,28 @@ test('Basic History', t => {
t.ok(typeof sh.hint('cmd ext') === 'object', 'Received a hint object for a valid partial command.')
t.ok(sh.hint('xcmd ext') === null, 'Received a null value for an invalid partial command.')
t.ok(typeof sh.hint('cmd') === 'object', 'Received a hint object for a valid full command.')
- t.ok(typeof sh.hint('c') === 'object' && sh.hint('c').commands.indexOf('cmd') >= 0, 'Received a hint object for a valid partial root command.')
+ t.ok(
+ typeof sh.hint('cm') === 'object' &&
+ sh.hint('cm').commands[0].name === 'cmd' &&
+ sh.hint('cm').commands[0].match[0] === 0 &&
+ sh.hint('cm').commands[0].match[1] === 1,
+ 'Received a hint object for a valid partial root command.')
+ t.end()
+})
+
+test('Single Command Hints', t => {
+ const clib = new Shell({
+ name: 'admin',
+ version: '1.0.1',
+
+ commands: [{
+ name: 'info',
+ description: 'info',
+ handler () { }
+ }]
+ })
+
+ console.log(clib.hint('i'))
+ t.pass('ok')
t.end()
})
From 8a1b1b751fc0242981d09d55ab9248006c698d9b Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Thu, 14 May 2020 22:49:34 -0500
Subject: [PATCH 075/152] Supply subcommands and flags as hints when full valid
commands are input
---
src/shell.js | 57 ++++++++++++++++++---------------
test/unit/01-sanity/07-hints.js | 3 +-
2 files changed, 34 insertions(+), 26 deletions(-)
diff --git a/src/shell.js b/src/shell.js
index 07284c1..3b5677a 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -99,24 +99,34 @@ export default class Shell extends Base {
match = command.arguments.toLowerCase()
- response = {
- commands: Array.from(subcmd.__commands.keys())
- .filter(name => name.toLowerCase().indexOf(match) >= 0
- || subcmd.__processors.get(subcmd.__commands.get(name)).aliases
- .filter(a => a.toLowerCase().indexOf(match) >= 0).length > 0).sort((a, b) => this.#hintsort(match, a, b)
- ),
- flags: Array.from(flags.entries()).filter(keypair => {
- const flag = keypair.pop()
- const name = keypair.pop()
-
- return name.toLowerCase().indexOf(match) >= 0
- || (flag.aliases || []).filter(a => a.toLowerCase().indexOf(match) >= 0).length > 0
- || (flag.alias || '').toLowerCase().indexOf(match) >= 0
- }).sort((a, b) => this.#hintsort(match, a, b))
+ if (match.length !== 0) {
+ response = {
+ commands: Array.from(subcmd.__commands.keys())
+ .filter(name => name.toLowerCase().indexOf(match) >= 0
+ || subcmd.__processors.get(subcmd.__commands.get(name)).aliases
+ .filter(a => a.toLowerCase().indexOf(match) >= 0).length > 0).sort((a, b) => this.#hintsort(match, a, b)
+ ),
+ flags: Array.from(flags.entries()).filter(keypair => {
+ const flag = keypair.pop()
+ const name = keypair.pop()
+
+ return name.toLowerCase().indexOf(match) >= 0
+ || (flag.aliases || []).filter(a => a.toLowerCase().indexOf(match) >= 0).length > 0
+ || (flag.alias || '').toLowerCase().indexOf(match) >= 0
+ }).sort((a, b) => this.#hintsort(match, a, b))
+ }
}
break
}
+ } else {
+ if (this.__commands.get(cmd)) {
+ let command = this.__processors.get(this.__commands.get(cmd))
+ response = {
+ commands: Array.from(command.__commands.keys()).sort(),
+ flags: Array.from(command.__flagConfig.keys()).sort()
+ }
+ }
}
if (response === null && commands.length > 0) {
@@ -127,30 +137,27 @@ export default class Shell extends Base {
}
if (response !== null) {
- response.input = cmd
response.commands = response.commands.filter(c => c.toLowerCase() !== match).map(c => {
+ let i = c.indexOf(match)
return {
- name: c,
- match: [
- c.indexOf(match),
- c.indexOf(match) + (match.length - 1)
- ]
- }
+ name: c,
+ match: [i, i < 0 ? -1 : i + (match.length - 1)]
+ }
})
response.flags = response.flags.filter(f => f.toLowerCase() !== match).map(f => {
+ let i = f.indexOf(match)
return {
name: f,
- match: [
- f.indexOf(match),
- f.indexOf(match) + (match.length - 1)
- ]
+ match: [i, i < 0 ? -1 : i + (match.length - 1)]
}
})
if (response.commands.length === 0 && response.flags.length === 0) {
return null
}
+
+ response.input = cmd
}
return response
diff --git a/test/unit/01-sanity/07-hints.js b/test/unit/01-sanity/07-hints.js
index 9f89f9b..b502228 100644
--- a/test/unit/01-sanity/07-hints.js
+++ b/test/unit/01-sanity/07-hints.js
@@ -55,7 +55,8 @@ test('Basic Hinting', t => {
t.ok(typeof sh.hint('cmd ext') === 'object', 'Received a hint object for a valid partial command.')
t.ok(sh.hint('xcmd ext') === null, 'Received a null value for an invalid partial command.')
- t.ok(typeof sh.hint('cmd') === 'object', 'Received a hint object for a valid full command.')
+ t.ok(typeof sh.hint('cmd') === 'object' && sh.hint('cmd') !== null, 'Received a hint object for a valid full command.')
+ t.ok(sh.hint('cmd').commands.length === 2, 'Specify a complete valid command returns subcommands as hints.')
t.ok(
typeof sh.hint('cm') === 'object' &&
sh.hint('cm').commands[0].name === 'cmd' &&
From f27f5658c6be1c77db56fb8bbcf009732ab137dc Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Thu, 14 May 2020 22:51:29 -0500
Subject: [PATCH 076/152] Removed unnecessary test
---
test/unit/01-sanity/07-hints.js | 17 -----------------
1 file changed, 17 deletions(-)
diff --git a/test/unit/01-sanity/07-hints.js b/test/unit/01-sanity/07-hints.js
index b502228..6670ce6 100644
--- a/test/unit/01-sanity/07-hints.js
+++ b/test/unit/01-sanity/07-hints.js
@@ -65,20 +65,3 @@ test('Basic Hinting', t => {
'Received a hint object for a valid partial root command.')
t.end()
})
-
-test('Single Command Hints', t => {
- const clib = new Shell({
- name: 'admin',
- version: '1.0.1',
-
- commands: [{
- name: 'info',
- description: 'info',
- handler () { }
- }]
- })
-
- console.log(clib.hint('i'))
- t.pass('ok')
- t.end()
-})
From b66c47302b8871f72d066633c375738cbc30dd87 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sat, 16 May 2020 18:20:14 -0500
Subject: [PATCH 077/152] Updated default flag formatting to use two dashes
instead of one. Abstracted command hinting into a separate add-on library.
---
src/format.js | 2 +-
src/shell.js | 103 +------------------------------
test/unit/01-sanity/01-sanity.js | 6 +-
test/unit/01-sanity/07-hints.js | 67 --------------------
4 files changed, 5 insertions(+), 173 deletions(-)
delete mode 100644 test/unit/01-sanity/07-hints.js
diff --git a/src/format.js b/src/format.js
index 0b8e1ca..e9406c9 100644
--- a/src/format.js
+++ b/src/format.js
@@ -96,7 +96,7 @@ class Formatter {
dsc = dsc.join(' ').trim()
- rows.push(['-' + flag, aliases || '', dsc || ''])
+ rows.push(['--' + flag, aliases || '', dsc || ''])
})
}
diff --git a/src/shell.js b/src/shell.js
index 3b5677a..3b80ca6 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -19,12 +19,6 @@ export default class Shell extends Base {
? globalThis.process.release.name
: 'unknown'
)
- // Sort hints by string match
- #hintsort = (matchString, a, b) => {
- const ai = a.toLowerCase().indexOf(matchString.toLowerCase())
- const bi = b.toLowerCase().indexOf(matchString.toLowerCase())
- return ai < bi ? -1 : (ai > bi ? 1 : 0)
- }
constructor (cfg = { maxhistory: 100 }) {
super(cfg)
@@ -44,7 +38,7 @@ export default class Shell extends Base {
this.#version = cfg.version || '1.0.0'
this.#maxHistoryItems = cfg.maxhistory || cfg.maxHistoryItems || 100
this.#tabWidth = cfg.hasOwnProperty('tabWidth') ? cfg.tabWidth : 4
-
+
// This sets a global symbol that dev tools can find.
globalThis[Symbol('SHELL_INTEGRATIONS')] = this
}
@@ -68,101 +62,6 @@ export default class Shell extends Base {
}
}
- hint (cmd) {
- cmd = cmd.toLowerCase()
- let response = null
- let args = cmd.match(COMMAND_PATTERN)
- let match = args === null ? cmd : args[1].toLowerCase()
- let commands = Array.from(this.__commands.keys()).filter(name => name.toLowerCase().indexOf(match) >= 0)
-
- if (args) {
- args = args.slice(1)
- match = args[0]
-
- switch (args.length) {
- case 1:
- break
-
- default:
- if ((['version', 'help']).indexOf(match) >= 0) {
- break
- }
-
- let command = this.__commands.get(match)
- if (!command) {
- break
- }
-
- command = this.__processors.get(command).getTerminalCommand(cmd.replace(new RegExp(`^${match}\\s+`, 'i'), ''))
- const subcmd = command.command
- const flags = subcmd.__flagConfig
-
- match = command.arguments.toLowerCase()
-
- if (match.length !== 0) {
- response = {
- commands: Array.from(subcmd.__commands.keys())
- .filter(name => name.toLowerCase().indexOf(match) >= 0
- || subcmd.__processors.get(subcmd.__commands.get(name)).aliases
- .filter(a => a.toLowerCase().indexOf(match) >= 0).length > 0).sort((a, b) => this.#hintsort(match, a, b)
- ),
- flags: Array.from(flags.entries()).filter(keypair => {
- const flag = keypair.pop()
- const name = keypair.pop()
-
- return name.toLowerCase().indexOf(match) >= 0
- || (flag.aliases || []).filter(a => a.toLowerCase().indexOf(match) >= 0).length > 0
- || (flag.alias || '').toLowerCase().indexOf(match) >= 0
- }).sort((a, b) => this.#hintsort(match, a, b))
- }
- }
-
- break
- }
- } else {
- if (this.__commands.get(cmd)) {
- let command = this.__processors.get(this.__commands.get(cmd))
- response = {
- commands: Array.from(command.__commands.keys()).sort(),
- flags: Array.from(command.__flagConfig.keys()).sort()
- }
- }
- }
-
- if (response === null && commands.length > 0) {
- response = {
- commands: commands.sort((a, b) => this.#hintsort(match, a, b)),
- flags: []
- }
- }
-
- if (response !== null) {
- response.commands = response.commands.filter(c => c.toLowerCase() !== match).map(c => {
- let i = c.indexOf(match)
- return {
- name: c,
- match: [i, i < 0 ? -1 : i + (match.length - 1)]
- }
- })
-
- response.flags = response.flags.filter(f => f.toLowerCase() !== match).map(f => {
- let i = f.indexOf(match)
- return {
- name: f,
- match: [i, i < 0 ? -1 : i + (match.length - 1)]
- }
- })
-
- if (response.commands.length === 0 && response.flags.length === 0) {
- return null
- }
-
- response.input = cmd
- }
-
- return response
- }
-
get version () {
return this.#version || 'Unknown'
}
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index af0cbb7..a422628 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -86,12 +86,12 @@ test('Output Formatting', t => {
Flags:
- -test [-t] test description
- -more [-m, -mr] This is a longer description that should break onto
+ --test [-t] test description
+ --more [-m, -mr] This is a longer description that should break onto
more than one line, or perhaps even more than one
extra line with especially poor grammar and
spellling.
- -none Ignore me. I do not exist. `, 'Correctly generated default help message.')
+ --none Ignore me. I do not exist. `, 'Correctly generated default help message.')
t.end()
})
diff --git a/test/unit/01-sanity/07-hints.js b/test/unit/01-sanity/07-hints.js
deleted file mode 100644
index 6670ce6..0000000
--- a/test/unit/01-sanity/07-hints.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import 'source-map-support/register.js'
-import test from 'tape'
-import { Shell } from '../../.node/index.js'
-
-test('Basic Hinting', t => {
- const sh = new Shell({
- name: 'test',
- maxhistory: 3,
- commonflags: {
- universal: {
- alias: 'u',
- description: 'Grand master flash, err, flag.'
- }
- },
- commands: [{
- name: 'cmd',
- flags: {
- main: {
- alias: 'm',
- description: 'Main flag.'
- }
- },
- handler () { console.log('test') },
- commands: [{
- name: 'subcommand',
- description: 'This is a subcommand',
- flags: {
- flaga: {
- alias: 'a',
- description: 'The A team.'
- },
- flagb: {
- alias: 'b',
- description: 'The B team.',
- type: String
- },
- flagc: {
- alias: 'c',
- description: 'The C club.'
- }
- },
- handler () {}
- }, {
- name: 'extra',
- description: 'another cmd',
- handler () {},
- commands: [{
- name: 'more',
- description: 'nested commands',
- handler () {}
- }]
- }]
- }]
- })
-
- t.ok(typeof sh.hint('cmd ext') === 'object', 'Received a hint object for a valid partial command.')
- t.ok(sh.hint('xcmd ext') === null, 'Received a null value for an invalid partial command.')
- t.ok(typeof sh.hint('cmd') === 'object' && sh.hint('cmd') !== null, 'Received a hint object for a valid full command.')
- t.ok(sh.hint('cmd').commands.length === 2, 'Specify a complete valid command returns subcommands as hints.')
- t.ok(
- typeof sh.hint('cm') === 'object' &&
- sh.hint('cm').commands[0].name === 'cmd' &&
- sh.hint('cm').commands[0].match[0] === 0 &&
- sh.hint('cm').commands[0].match[1] === 1,
- 'Received a hint object for a valid partial root command.')
- t.end()
-})
From 8512edc077aebb9afedf93e930691ac70ee50c90 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sat, 16 May 2020 18:31:03 -0500
Subject: [PATCH 078/152] Version bump.
---
package-lock.json | 2 +-
package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 0d5663a..f38fc9e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.16",
+ "version": "1.6.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index ce4857c..f8ae715 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.5.16",
+ "version": "1.6.0",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
From ce684834530fde5662103becd98ae44d3f97467f Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sun, 17 May 2020 01:25:18 -0500
Subject: [PATCH 079/152] Removed hints section and pointed to the new hints
library.
---
README.md | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index f9ba0e5..f0b49e2 100644
--- a/README.md
+++ b/README.md
@@ -698,11 +698,13 @@ Simple CLI utilities can also be loaded entirely from a JSON file by passing the
### Autocompletion/Input Hints
-This library provides a _command hinting_ feature using the shell `hint()` method.
+This library can use a _command hinting_ feature, i.e. a shell `hint()` method to return suggestions/hints about a partial command. This feature was part of the library through the `v1.5.x` release lifecycle. In `v.1.6.0+`, this feature is no longer a part of the core library. It is now available as the [author/shell-hints plugin](https://github.com/author/shell-hints).
Consider the following shell:
```javascript
+import HintPlugin from 'https://cdn.pika.dev/@author.io/browser-shell-hints'
+
const shell = new Shell({
name: 'mycli',
command: [{
@@ -727,6 +729,8 @@ const shell = new Shell({
}]
})
+HintPlugin.apply(shell) // <-- Adds the hint method.
+
// Help us figure out what we can do!
console.log(shell.hint('dir p'))
```
@@ -744,7 +748,7 @@ The hint matches "**dir p**ermission" and "**dir p**ayload", but does not match
If no options/hints are available, `null` is returned.
-While this library provides input hints that could be used for suggestions/completions, it does **not** generate autocompletion files for shells like bash, zsh, fish, powershell, etc.
+While this add-on provides input hints that could be used for suggestions/completions, it does **not** generate autocompletion files for shells like bash, zsh, fish, powershell, etc.
> There are many variations of autocompletion for different shells, which are not available in browsers (see our Devtools extension for browser completion).
From 2b491a51c99a07e228f690a04aa8971a11c7e32f Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 18 May 2020 11:07:19 -0500
Subject: [PATCH 080/152] Added a helper command for retrieving flag
configuration metadata. Also added checks to assure a standalone command can
still operate independently of a shell.
---
package-lock.json | 2 +-
package.json | 2 +-
src/base.js | 4 +--
src/command.js | 34 +++++++++++++++++++++++---
test/unit/01-sanity/01-sanity.js | 42 ++++++++++++++++++++++++++++++++
5 files changed, 76 insertions(+), 8 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index f38fc9e..6a33575 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.6.0",
+ "version": "1.6.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index f8ae715..c77c548 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.6.0",
+ "version": "1.6.1",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/base.js b/src/base.js
index 45bccbb..50b8153 100644
--- a/src/base.js
+++ b/src/base.js
@@ -28,7 +28,7 @@ export default class Base {
#defaultHandler = function (meta) {
if (this.parent !== null && this.parent.hasCustomDefaultHandler) {
return this.parent.defaultHandler(...arguments)
- } else if (this.shell.hasCustomDefaultHandler) {
+ } else if (this.shell && this.shell !== null && this.shell.hasCustomDefaultHandler) {
return this.shell.defaultHandler(...arguments)
}
@@ -239,7 +239,7 @@ export default class Base {
}
if (this instanceof Command) {
- if (this.shell[attr] !== null) {
+ if (this.shell && this.shell !== null && this.shell[attr] !== null) {
return this.shell[attr]
}
diff --git a/src/command.js b/src/command.js
index 62ec81f..66dd283 100644
--- a/src/command.js
+++ b/src/command.js
@@ -125,7 +125,7 @@ export default class Command extends Base {
flags = Object.assign(flags, this.parent.__commonFlags)
}
- return Object.assign({}, this.shell.__commonflags, flags)
+ return Object.assign({}, this.shell !== null ? this.shell.__commonflags : {}, flags)
}
},
__flagConfig: {
@@ -315,6 +315,30 @@ export default class Command extends Base {
delete this.#flagConfig[name]
}
+ getFlagConfiguration (name) {
+ let flag = this.__flagConfig.get(name)
+ if (!flag) {
+ for (let [f, cfg] of this.__flagConfig) {
+ if ((cfg.aliases && cfg.aliases.indexOf(name) >= 0) || (cfg.alias && cfg.alias === flag)) {
+ flag = cfg
+ break
+ }
+ }
+
+ if (!flag) {
+ return null
+ }
+ }
+
+ return {
+ description: flag.description,
+ required: flag.hasOwnProperty('required') ? flag.required : false,
+ aliases: flag.aliases || [flag.alias].filter(i => i !== null),
+ type: flag.type === undefined ? 'string' : (typeof flag.type === 'string' ? flag.type : flag.type.name.toLowerCase()),
+ options: flag.hasOwnProperty('options') ? flag.options : null
+ }
+ }
+
supportsFlag (name) {
return this.#flagConfig.hasOwnProperty(name)
}
@@ -473,10 +497,12 @@ export default class Command extends Base {
arguments[0] = this.deepParse(input)
- const parentMiddleware = this.shell.getCommandMiddleware(this.commandroot.replace(new RegExp(`^${this.shell.name}`, 'i'), '').trim())
+ if (this.shell !== null) {
+ const parentMiddleware = this.shell.getCommandMiddleware(this.commandroot.replace(new RegExp(`^${this.shell.name}`, 'i'), '').trim())
- if (parentMiddleware.length > 0) {
- this.middleware.use(...parentMiddleware)
+ if (parentMiddleware.length > 0) {
+ this.middleware.use(...parentMiddleware)
+ }
}
let trailers = this.trailers
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index a422628..3e60091 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -192,3 +192,45 @@ test('Basic Introspection', t => {
t.ok(typeof shell.data === 'object', 'Generates a data object representing the shell.')
t.end()
})
+
+test('Flag Default Configuration', t => {
+ const cmd = new Command({
+ name: 'cmd',
+ alias: 'c',
+ flags: {
+ test: {
+ alias: 't',
+ description: 'test description'
+ },
+ more: {
+ aliases: ['m', 'mr'],
+ description: 'This is a longer description that should break onto more than one line, or perhaps even more than one extra line with especially poor grammar and spellling.'
+ },
+ none: {
+ description: 'Ignore me. I do not exist.'
+ }
+ }
+ })
+
+ let f = cmd.getFlagConfiguration('test')
+ t.ok(
+ f.aliases[0] === 't' &&
+ f.description === 'test description' &&
+ f.required === false &&
+ f.type === 'string' &&
+ f.options === null,
+ 'Returned default configuration items for a named flag.'
+ )
+
+ f = cmd.getFlagConfiguration('t')
+ t.ok(
+ f.aliases[0] === 't' &&
+ f.description === 'test description' &&
+ f.required === false &&
+ f.type === 'string' &&
+ f.options === null,
+ 'Returned default configuration items for an alias of a flag.'
+ )
+
+ t.end()
+})
From 7c6bf0423ce49de941b2d61e6d115b558b6c85c6 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 19 May 2020 15:41:44 -0500
Subject: [PATCH 081/152] Updated dependencies and provide a default flag
configuration attribute (metadata) for conveying when multiple instances of a
flag are allowed to exist simultneously.
---
package-lock.json | 6 +++---
package.json | 2 +-
src/command.js | 10 +++++++---
3 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 6a33575..223f9a3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,9 +5,9 @@
"requires": true,
"dependencies": {
"@author.io/arg": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.3.tgz",
- "integrity": "sha512-TpBNJ0r6YbTwXeLci36GHZLHZx/9gWu9bBFNAinTgEY7H+oTt7OexYKce5UVrYG440Hc60jWZ4pelKCqlgAcIA=="
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.6.tgz",
+ "integrity": "sha512-mWY/p0JzTv8qEcIWL0PvZLv28+H23Pkp0qR/M6agJpPl7TDWiA10CB2AABJAionN517fNK7fAdYazVrO2axlLA=="
},
"@author.io/table": {
"version": "1.0.3",
diff --git a/package.json b/package.json
index c77c548..fb2ff7e 100644
--- a/package.json
+++ b/package.json
@@ -52,7 +52,7 @@
]
},
"dependencies": {
- "@author.io/arg": "^1.3.3",
+ "@author.io/arg": "^1.3.6",
"@author.io/table": "^1.0.3"
}
}
diff --git a/src/command.js b/src/command.js
index 66dd283..b6c115f 100644
--- a/src/command.js
+++ b/src/command.js
@@ -192,6 +192,9 @@ export default class Command extends Base {
delete value.alias
}
+ // Apply any missing default values to flags.
+ Object.keys(flags).forEach(name => flags[name] = Object.assign(this.getFlagConfiguration(name), flags[name]))
+
const data = {
name: this.name,
description: this.description,
@@ -335,7 +338,8 @@ export default class Command extends Base {
required: flag.hasOwnProperty('required') ? flag.required : false,
aliases: flag.aliases || [flag.alias].filter(i => i !== null),
type: flag.type === undefined ? 'string' : (typeof flag.type === 'string' ? flag.type : flag.type.name.toLowerCase()),
- options: flag.hasOwnProperty('options') ? flag.options : null
+ options: flag.hasOwnProperty('options') ? flag.options : null,
+ allowMultipleValues: flag.hasOwnProperty('allowMultipleValues') ? flag.allowMultipleValues : false
}
}
@@ -383,10 +387,10 @@ export default class Command extends Base {
const parser = new Parser(flags, flagConfig)
const pdata = parser.data
const recognized = {}
-
+
parser.recognizedFlags.forEach(flag => recognized[flag] = pdata[flag])
parser.unrecognizedFlags.forEach(arg => delete recognized[arg])
-
+
data.flags = { recognized, unrecognized: parser.unrecognizedFlags }
data.valid = parser.valid
data.violations = parser.violations
From aa108aad300c014d00ce2793449d868cef329e82 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 19 May 2020 15:43:09 -0500
Subject: [PATCH 082/152] Version bump
---
package-lock.json | 2 +-
package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 223f9a3..17ad2d5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.6.1",
+ "version": "1.6.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index fb2ff7e..5035571 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.6.1",
+ "version": "1.6.2",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
From 87ed3e17361e86c748a81e3d31f90978b3793859 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Fri, 22 May 2020 11:45:14 -0500
Subject: [PATCH 083/152] Added and configuration options/getters for
commands and the entire shell. These read-only properties are designed to
provide data for identifying documentation/author details and support (such
as a Github issues link).
---
package-lock.json | 2 +-
package.json | 2 +-
src/base.js | 47 +++++++++++++++++++++++++++++++++++++++++++++++
src/command.js | 4 +++-
4 files changed, 52 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 17ad2d5..074e34e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.6.2",
+ "version": "1.6.3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 5035571..f22e164 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.6.2",
+ "version": "1.6.3",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/base.js b/src/base.js
index 50b8153..58b6362 100644
--- a/src/base.js
+++ b/src/base.js
@@ -4,6 +4,8 @@ import Shell from './shell.js'
import Command from './command.js'
export default class Base {
+ #url = null
+ #support = null
#formattedDefaultHelp
#description
#customUsage
@@ -82,6 +84,14 @@ export default class Base {
this.#arguments = new Set(cfg.arguments)
}
+ if (typeof cfg.url === 'string') {
+ this.#url = cfg.url
+ }
+
+ if (typeof cfg.support === 'string') {
+ this.#support = cfg.support
+ }
+
this.#name = (cfg.name || 'unknown').trim().split(/\s+/)[0]
this.#description = cfg.description || null
@@ -208,14 +218,51 @@ export default class Base {
this.updateHelp()
}
+ // @readonly
get name () {
return this.#name || 'Unknown'
}
+ // @readonly
get description () {
return this.#description || this.usage || ''
}
+ // @readonly
+ get url () {
+ return this.URL
+ }
+
+ // @readonly
+ get URL () {
+ let uri = (this.#url || '').trim()
+
+ if (uri.length === 0) {
+ if (this.hasOwnProperty('parent')) {
+ return this.parent.URL
+ } else if (this instanceof Command) {
+ return this.shell.URL
+ }
+ }
+
+ return uri
+ }
+
+ // @readonly
+ get support () {
+ let support = (this.#support || '').trim()
+
+ if (support.length === 0) {
+ if (this.hasOwnProperty('parent')) {
+ return this.parent.support
+ } else if (this instanceof Command) {
+ return this.shell.support
+ }
+ }
+
+ return support
+ }
+
get autohelp() {
return this.#autohelp
}
diff --git a/src/command.js b/src/command.js
index b6c115f..6108a56 100644
--- a/src/command.js
+++ b/src/command.js
@@ -106,7 +106,9 @@ export default class Command extends Base {
'arguments',
'commonflag',
'commonflags',
- 'trailer'
+ 'trailer',
+ 'url',
+ 'support'
])
const unrecognized = Object.keys(cfg).filter(attribute => !attributes.has(attribute))
From cb92d3f57493211e115b47d6e8bf78fbef2f9262 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Thu, 18 Jun 2020 19:23:13 -0500
Subject: [PATCH 084/152] Added a plugin capability.
---
README.md | 87 +++++++++++++++++++++++
build/lib/build.js | 1 +
package-lock.json | 2 +-
package.json | 2 +-
src/base.js | 9 +++
src/command.js | 8 +++
src/shell.js | 5 ++
test/unit/01-sanity/07-plugins.js | 113 ++++++++++++++++++++++++++++++
8 files changed, 225 insertions(+), 2 deletions(-)
create mode 100644 test/unit/01-sanity/07-plugins.js
diff --git a/README.md b/README.md
index f0b49e2..8fa62b6 100644
--- a/README.md
+++ b/README.md
@@ -331,6 +331,93 @@ _Output:_
> Notice the values from the known flags are _first_.
+## Plugins
+
+Plugins expose functions, objects, and primitives to shell handlers.
+
+_Example:_
+
+Consider an example where information is retrieved from a remote API. To do this, an HTTP request library may be necessary to make the request and parse the results. In this example, the axios library is defined as a plugin. The plugin is accessible in the metadata passed to each handler, as shown below.
+
+
+ Why would you do this?
+
+ Remember, the shell library can produce JSON (See the Introspection/Metadata Generation section). JSON is a string format for storing data. The output will contain a stringified version of all the handler functions. This can be used as the configuration for another instance of a shell. In other words, you can maintain a runtime-agnostic configuration. You could use _mostly_ the same configuration for the browser, Node, Deno, Vert.x, or another JavaScript runtime. However; the modules/packages like the HTTP request module may or may not work in each runtime.
+
+
+ Plugins allow developers to write handlers that are completely "self contained". It is then possible to modify the plugin configuration for each runtime without modifying every handler in the shell.
+
+
+
+```javascript
+import axios from 'axios'
+
+const sh = new Shell({
+ name: 'info',
+ plugins: {
+ httprequest: axios // replace this with any compatible library
+ },
+ commands: [{
+ name: 'person',
+ flags: {
+ name: {
+ description: 'Name of the person you want info about.',
+ required: true
+ }
+ },
+ handler (meta) {
+ meta.plugins.httprequest({
+ method: 'get',
+ url: `http://api.com/person/${meta.flag('name')}`
+ }).then(console.log).catch(console.error)
+ }
+ }, {
+ name: 'group',
+ flags: {
+ name: {
+ description: 'Name of the group you want info about.',
+ required: true
+ }
+ },
+ handler (meta) {
+ meta.plugins.httprequest({
+ method: 'get',
+ url: `http://api.com/group/${meta.flag('name')}`
+ }).then(console.log).catch(console.error)
+ }
+ }]
+})
+```
+
+Commands will inherit plugins from the shell and any parent commands. It is possible to "override" a plugin in any specific command.
+
+
+Override Example
+
+```javascript
+const sh = new Shell({
+ name: 'test',
+ plugins: {
+ test: value => {
+ return value + 1
+ }
+ },
+ commands: [{
+ name: 'cmd',
+ plugins: {
+ test: value => {
+ return value + 10
+ }
+ },
+ handler(meta) {
+ console.log(meta.test(1)) // Outputs 11
+ }
+ }]
+})
+```
+
+
+
## Universal Flags
_Common flags are automatically applied to multiple commands._
diff --git a/build/lib/build.js b/build/lib/build.js
index 9e9d0f8..eea4a26 100644
--- a/build/lib/build.js
+++ b/build/lib/build.js
@@ -160,6 +160,7 @@ export default class build {
const refs = new Set([...arguments])
return warning => {
+ console.log(chalk.red(warning.importer))
if (
warning.code === 'CIRCULAR_DEPENDENCY' &&
refs.size > 0 &&
diff --git a/package-lock.json b/package-lock.json
index 074e34e..7097b1a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.6.3",
+ "version": "1.7.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index f22e164..a13aa39 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.6.3",
+ "version": "1.7.0",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/base.js b/src/base.js
index 58b6362..e64a09a 100644
--- a/src/base.js
+++ b/src/base.js
@@ -4,6 +4,7 @@ import Shell from './shell.js'
import Command from './command.js'
export default class Base {
+ #plugins = {}
#url = null
#support = null
#formattedDefaultHelp
@@ -129,6 +130,10 @@ export default class Base {
}
}
+ if (typeof cfg.plugins === 'object') {
+ this.#plugins = cfg.plugins
+ }
+
Object.defineProperties(this, {
__processors: {
enumerable: false,
@@ -218,6 +223,10 @@ export default class Base {
this.updateHelp()
}
+ get plugins () {
+ return this.#plugins
+ }
+
// @readonly
get name () {
return this.#name || 'Unknown'
diff --git a/src/command.js b/src/command.js
index 6108a56..b5218ea 100644
--- a/src/command.js
+++ b/src/command.js
@@ -86,6 +86,7 @@ export default class Command extends Base {
const attributes = new Set([
'commands',
'subcommands',
+ 'plugins',
'defaultHandler',
'disableHelp',
'describeDefault',
@@ -254,6 +255,10 @@ export default class Command extends Base {
return this.#shell
}
+ get plugins () {
+ return Object.assign({}, this.shell.plugins, this.parent ? this.parent.plugins : {}, super.plugins)
+ }
+
get commandroot () {
if (this.#parent) {
return `${this.#parent.commandroot} ${this.name}`.trim()
@@ -502,6 +507,7 @@ export default class Command extends Base {
const data = typeof input === 'string' ? this.parse(input) : input
arguments[0] = this.deepParse(input)
+ arguments[0].plugins = this.plugins
if (this.shell !== null) {
const parentMiddleware = this.shell.getCommandMiddleware(this.commandroot.replace(new RegExp(`^${this.shell.name}`, 'i'), '').trim())
@@ -534,6 +540,8 @@ export default class Command extends Base {
return
}
+ // Command.reply(fn(arguments[0], callback))
+ data.plugins = this.plugins
Command.reply(fn(data, callback))
if (trailers.size > 0) {
diff --git a/src/shell.js b/src/shell.js
index 3b80ca6..e8a23e5 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -193,8 +193,13 @@ export default class Shell extends Base {
return results.flat(Infinity)
}
+ clearHistory () {
+ this.#history = []
+ }
+
// Clear the terminal
clear () {
+ this.#history = []
console.clear()
// .write('\x1b[0f') // regular clear
// .write('\x1b[2J') // full clear
diff --git a/test/unit/01-sanity/07-plugins.js b/test/unit/01-sanity/07-plugins.js
new file mode 100644
index 0000000..627b560
--- /dev/null
+++ b/test/unit/01-sanity/07-plugins.js
@@ -0,0 +1,113 @@
+import 'source-map-support/register.js'
+import test from 'tape'
+import { Shell } from '../../.node/index.js'
+
+test('Basic Plugins', t => {
+ const sh = new Shell({
+ name: 'test',
+ plugins: {
+ test: (value) => {
+ return value += 1
+ }
+ },
+ commands: [{
+ name: 'cmd',
+ handler (meta) {
+ t.ok(typeof meta.plugins === 'object', `meta.plugins should be an object. Recognized as ${typeof meta.plugins}.`)
+ t.ok(typeof meta.plugins.test === 'function', `Expected test plugin to be a function, recognized ${typeof meta.plugins.test}.`)
+ t.ok(meta.plugins.test(1) === 2, 'Plugin executes properly.')
+
+ t.end()
+ }
+ }]
+ })
+
+ sh.exec('cmd').catch(t.fail)
+})
+
+test('Inherited Plugins', t => {
+ const sh = new Shell({
+ name: 'test',
+ plugins: {
+ test: (value) => {
+ return value += 1
+ }
+ },
+ commands: [{
+ name: 'cmd',
+ plugins: {
+ ten: 10
+ },
+ handler(meta) {
+ t.ok(typeof meta.plugins === 'object', `meta.plugins should be an object. Recognized as ${typeof meta.plugins}.`)
+ t.ok(typeof meta.plugins.ten === 'number', `Expected test plugin to be a number, recognized ${typeof meta.plugins.ten}.`)
+ t.ok(meta.plugins.test(1) === 2, 'Shell plugin (global) executes properly.')
+
+ t.end()
+ }
+ }]
+ })
+
+ sh.exec('cmd').catch(t.fail)
+})
+
+test('Overriding Plugins', t => {
+ const sh = new Shell({
+ name: 'test',
+ plugins: {
+ test: (value) => {
+ return value += 1
+ }
+ },
+ commands: [{
+ name: 'cmd',
+ plugins: {
+ test: (value) => {
+ return value += 10
+ }
+ },
+ handler(meta) {
+ t.ok(meta.plugins.test(1) === 11, 'Overridden shell plugin (global) executes properly.')
+ t.ok(meta.shell.plugins.test(1) === 2, 'Original shell plugin (overridden) executes properly when executed from shell.')
+ t.end()
+ }
+ }]
+ })
+
+ sh.exec('cmd').catch(t.fail)
+})
+
+test('Overriding Plugins', t => {
+ const sh = new Shell({
+ name: 'test',
+ plugins: {
+ test: (value) => {
+ return value += 1
+ }
+ },
+ commands: [{
+ name: 'cmd',
+ plugins: {
+ test: (value) => {
+ return value += 10
+ }
+ },
+ commands: [{
+ name: 'sub',
+ plugins: {
+ test: (value) => {
+ return value += 100
+ }
+ },
+ handler(meta) {
+ t.ok(meta.plugins.test(1) === 101, 'Overridden command plugin executes properly.')
+ t.ok(meta.command.parent.plugins.test(1) === 11, 'Original parent command plugin executes properly.')
+ t.ok(meta.shell.plugins.test(1) === 2, 'Original shell plugin (overridden) executes properly when executed from shell.')
+ t.end()
+ }
+ }]
+ }]
+ })
+
+ sh.exec('cmd sub').catch(t.fail)
+})
From 6174546c8702352e7d9e64e5687261c95011bb33 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 24 Jun 2020 18:34:19 -0500
Subject: [PATCH 085/152] Update README.md
---
README.md | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/README.md b/README.md
index 8fa62b6..8fa4f33 100644
--- a/README.md
+++ b/README.md
@@ -4,14 +4,11 @@
This is a super-lightweight framework for building text-based programs, like [CLI](https://en.wikipedia.org/wiki/Command-line_interface) applications.
-**Sponsors (as of 2020)**
+This library is now supported by the [Chrome CLI Devtools Extension](https://chrome.google.com/webstore/detail/cli/okpglddgmnblhbdpdcmodmacgcibgfkf):
-
-
-
-
-
-
+
+
+You can see it in use in this [OpenJS World 2020 talk](https://youtu.be/dw7ABwvFtdM) (The Benefits of a "CLI First" Development Strategy)
## Uses
@@ -892,4 +889,13 @@ Each distribution has a corresponding `-debug` version that should be installed
### Related Modules
-1. [@author.io/table](https://github.com/author/table) - Used to generate the default usage/help messages for the shell and subcommands.
\ No newline at end of file
+1. [@author.io/table](https://github.com/author/table) - Used to generate the default usage/help messages for the shell and subcommands.
+
+**Sponsors (as of 2020)**
+
+
+
+
+
+
+
From ed329b88107e154311a8d55dbfecd9fcef15fa33 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 24 Jun 2020 18:35:33 -0500
Subject: [PATCH 086/152] Update README.md
---
README.md | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 8fa4f33..fb171c4 100644
--- a/README.md
+++ b/README.md
@@ -4,11 +4,14 @@
This is a super-lightweight framework for building text-based programs, like [CLI](https://en.wikipedia.org/wiki/Command-line_interface) applications.
-This library is now supported by the [Chrome CLI Devtools Extension](https://chrome.google.com/webstore/detail/cli/okpglddgmnblhbdpdcmodmacgcibgfkf):
+---
+This library is now supported by this [Chrome CLI Devtools Extension](https://chrome.google.com/webstore/detail/cli/okpglddgmnblhbdpdcmodmacgcibgfkf):

-You can see it in use in this [OpenJS World 2020 talk](https://youtu.be/dw7ABwvFtdM) (The Benefits of a "CLI First" Development Strategy)
+You can see the library in use (in browsers and Node.js) in this [OpenJS World 2020 talk](https://youtu.be/dw7ABwvFtdM) (The Benefits of a "CLI First" Development Strategy).
+
+---
## Uses
From b6063cde71a780753867462aa698fdce7b8d5c6b Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 24 Jun 2020 18:39:18 -0500
Subject: [PATCH 087/152] Add note about plugins
---
README.md | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index 8fa62b6..01d5991 100644
--- a/README.md
+++ b/README.md
@@ -48,13 +48,14 @@ Sometimes single purpose tools grow into multipurpose tools over time. Tools whi
## Differentiating Features
-1. Supports **middleware** (express-style)
-1. Supports **postware** (middleware that runs after a command)
-1. **Customizable** help/usage screens
-1. **Introspectable**: Produces/consumes JSON (load a compatible JSON file and have a working CLI)
+1. Supports **middleware** (express-style).
+1. Supports **postware** (middleware that runs after a command).
+1. **Customizable **help/usage** screens.
+1. Produces **introspectable** JSON. Load a JSON config, have a working CLI.
+1. Reusable **plugin** system.
1. Dynamically add/remove commands.
-1. Command/execution **history** tracking
-1. **Universal flags**: define a flag once, reuse everywhere.
+1. Track command execution **history**.
+1. Define **universal flags** flag once, reuse in all commands.
Also has better source & distribution code
From d25a0285f372694a1abdfbc0eab6d5527f3d3e6b Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 24 Jun 2020 18:40:15 -0500
Subject: [PATCH 088/152] Update README.md
---
README.md | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 875a2c8..b148438 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,5 @@
-# @author.io/shell 
-
- using the [cross-runtime template](https://github.com/author/template-cross-runtime).
+# @author.io/shell
+
This is a super-lightweight framework for building text-based programs, like [CLI](https://en.wikipedia.org/wiki/Command-line_interface) applications.
From f54439d66b4f1d8e5ee22b0837b1169e32a48b39 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 24 Jun 2020 18:52:08 -0500
Subject: [PATCH 089/152] Update .travis.yml
Removed 13.x.x since ES modules are now natively supported in Node 14.0.0+
---
.travis.yml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index f027827..580b705 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,5 @@
language: node_js
node_js:
-- '13.5.0'
- '14.0.0'
install:
@@ -12,4 +11,4 @@ script:
# Only run node tests since sauce labs fails all the time
- npm run test:node
# - ls -l
- # - cd ./test && ls -l && npm run node
\ No newline at end of file
+ # - cd ./test && ls -l && npm run node
From 5c8c060bbf1ba0b0c108c519d3275501a283e354 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 29 Jun 2020 19:16:12 -0500
Subject: [PATCH 090/152] Added support for passing an array of input arguments
to the exec method. This helps prevent problems when Node users pass
process.argv.slice(2) in as the input instead of process.argv.slice(2).join('
').
---
src/shell.js | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/shell.js b/src/shell.js
index e8a23e5..d7a010b 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -139,6 +139,12 @@ export default class Shell extends Base {
}
async exec (input, callback) {
+ // The array check exists because people are passing process.argv.slice(2) into this
+ // method, often forgetting to join the values into a string.
+ if (Array.isArray(input)) {
+ input = input.join(' ')
+ }
+
this.#history.unshift({ input, time: new Date().toLocaleString()})
if (this.#history.length > this.#maxHistoryItems) {
@@ -180,6 +186,7 @@ export default class Shell extends Base {
}
const term = processor.getTerminalCommand(args)
+ console.log(term)
return await Command.reply(await term.command.run(term.arguments, callback))
}
From af7be56b450d5c5637316ed304f03096d3cfb32a Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 29 Jun 2020 19:23:03 -0500
Subject: [PATCH 091/152] Bump version
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index a13aa39..60e5b58 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.7.0",
+ "version": "1.7.1",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
From ff53fce7d837181727eda82418bf5ce2048a6277 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 29 Jun 2020 19:25:55 -0500
Subject: [PATCH 092/152] Removed extraneous artifact from output.
---
package-lock.json | 2 +-
package.json | 2 +-
src/shell.js | 1 -
3 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 7097b1a..6b618a7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.7.0",
+ "version": "1.7.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 60e5b58..837dac4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.7.1",
+ "version": "1.7.2",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/shell.js b/src/shell.js
index d7a010b..6a081b5 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -186,7 +186,6 @@ export default class Shell extends Base {
}
const term = processor.getTerminalCommand(args)
- console.log(term)
return await Command.reply(await term.command.run(term.arguments, callback))
}
From ce54c87c2db449073aaaab7479850a5e51cb972c Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 29 Jun 2020 19:34:38 -0500
Subject: [PATCH 093/152] Fixed version bump
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 837dac4..60e5b58 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.7.2",
+ "version": "1.7.1",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
From ae911e141d57f84a353c1b60d91b332bf75ab705 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sat, 4 Jul 2020 22:50:15 -0500
Subject: [PATCH 094/152] Updated dependencies to resolve metadata duplication
regression.
---
package-lock.json | 8 ++++----
package.json | 4 ++--
src/command.js | 3 ++-
test/unit/01-sanity/100-regression.js | 28 +++++++++++++++++++++++++++
4 files changed, 36 insertions(+), 7 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 6b618a7..6cce510 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,13 +1,13 @@
{
"name": "@author.io/shell",
- "version": "1.7.1",
+ "version": "1.7.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@author.io/arg": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.6.tgz",
- "integrity": "sha512-mWY/p0JzTv8qEcIWL0PvZLv28+H23Pkp0qR/M6agJpPl7TDWiA10CB2AABJAionN517fNK7fAdYazVrO2axlLA=="
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.8.tgz",
+ "integrity": "sha512-JXeBApJ9hCrlDPHoieX5d3BBqP6l1O0x95TkDSYfZgIa9OitQHwJuaBM7eyv8bkxL4pQnAORvftifVW/DdGinA=="
},
"@author.io/table": {
"version": "1.0.3",
diff --git a/package.json b/package.json
index 60e5b58..f992d95 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.7.1",
+ "version": "1.7.2",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
@@ -52,7 +52,7 @@
]
},
"dependencies": {
- "@author.io/arg": "^1.3.6",
+ "@author.io/arg": "^1.3.8",
"@author.io/table": "^1.0.3"
}
}
diff --git a/src/command.js b/src/command.js
index b5218ea..c066038 100644
--- a/src/command.js
+++ b/src/command.js
@@ -391,10 +391,11 @@ export default class Command extends Base {
}
const flags = Array.from(FLAG_PATTERN[Symbol.matchAll](input), x => x[0])
+// console.log(flags, flagConfig)
const parser = new Parser(flags, flagConfig)
const pdata = parser.data
const recognized = {}
-
+
parser.recognizedFlags.forEach(flag => recognized[flag] = pdata[flag])
parser.unrecognizedFlags.forEach(arg => delete recognized[arg])
diff --git a/test/unit/01-sanity/100-regression.js b/test/unit/01-sanity/100-regression.js
index 14f1384..917aa1f 100644
--- a/test/unit/01-sanity/100-regression.js
+++ b/test/unit/01-sanity/100-regression.js
@@ -25,3 +25,31 @@ test('Extending shell creates RangeError for data attribute', t => {
t.ok(sh.data.name === 'test', 'Extended shell still provides underlying data.')
t.end()
})
+
+test('Metadata duplication of flag values when multiple values are allowed', t => {
+ const sh = new Shell({
+ name: 'dev',
+ version: '1.0.0',
+ description: 'Control the manual test suite.',
+
+ commands: [{
+ name: 'run',
+ description: 'Run a specific test. Runs all known test files if no file is specified with a flag.',
+ flags: {
+ file: {
+ alias: 'f',
+ description: 'The file to load/execute.',
+ allowMultipleValues: true
+ }
+ },
+ handler (meta) {
+ t.ok(meta.data.file[0] === 'a.js', 'First value is correct')
+ t.ok(meta.data.file[1] === 'b.js', 'Second value is correct')
+ t.ok(meta.data.file.length === 2, 'Only two unique flag values provided.')
+ t.end()
+ }
+ }]
+ })
+
+ sh.exec('run -f a.js -f b.js').catch(t.fail)
+})
From 3bc6fb2ec38cdea28032b57541c15cca2b60395c Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Thu, 16 Jul 2020 15:44:03 -0500
Subject: [PATCH 095/152] Added middleware capable of being applied to all
commands _except_ a given list of commands (cherry picking). Also added a
special _ignore_ parameter to the commonflag (universal flags) configuration,
allowing applications to be applied to a filtered set of
commands/subcommands. This closes #3 and it closes #4.
---
README.md | 78 +++++++++++++++++++++++++++
examples/cli/index.js | 2 +-
examples/json/index.js | 2 +-
package.json | 2 +-
src/base.js | 10 ++++
src/command.js | 16 +++++-
src/shell.js | 26 +++++++++
test/unit/01-sanity/02-middleware.js | 45 ++++++++++++++++
test/unit/01-sanity/05-commonflags.js | 49 +++++++++++++++++
9 files changed, 226 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index b148438..b8e863b 100644
--- a/README.md
+++ b/README.md
@@ -524,6 +524,47 @@ mycli read
```
+#### Filtering Universal Flags
+
+Universal/common flags accept a special attribute named `ignore`, which will prevent the flags from being applied to specific commands. This should be used sparingly.
+
+
+Cherry-picking example
+
+
+```javascript
+const shell = new Shell({
+ name: 'mycli',
+ commmonflags: {
+ ignore: 'info', // This can also be an array of string. Fully qualified subcommands will also be respected.
+ note: {
+ alias: 'n',
+ description: 'Save a note about the operation.'
+ }
+ },
+ commands: [{
+ name: 'create',
+ handler () {}
+ }, {
+ name: 'read',
+ handler () {}
+ }, {
+ name: 'update',
+ handler () {}
+ }, {
+ name: 'delete',
+ handler () {}
+ }, {
+ name: 'info',
+ handler () {}
+ }]
+})
+```
+
+Any command, except `info`, will accepts/parse the `note` flag.
+
+
+
## Middleware
When a command is called, it's handler function is executed. Sometimes it is desirable to pre-process one or more commands. The shell middleware feature supports "global" middleware and "assigned" middleware.
@@ -562,6 +603,8 @@ shell.useWith('demo', function (metadata, next) {
The code above would only run when the user inputs the `demo` command (or any `demo` subcommand).
+#### Command-Specific Assignments
+
It is possible to assign middleware to more than one command at a time, and it is possible to target subcommands. For example:
```javascript
@@ -596,6 +639,41 @@ cmd.use(function (metadata, next) {
})
```
+#### Command-Exclusion Assignments
+
+Sometimes middleware needs to be applied to all but a few commands. The `useExcept` method supports these needs. It is basically the opposite of `useWith`. Middleware is applied to all commands/subcommands _except_ those specified.
+
+For example:
+
+```javascript
+const shell = new Shell({
+ ...,
+ commands: [{
+ name: 'add',
+ handler (meta) {
+ ...
+ }
+ }, {
+ name: 'subtract',
+ handler (meta) {
+ ...
+ }
+ }, {
+ name: 'info',
+ handler (meta) {
+ ...
+ }
+ }]
+})
+
+shell.useExcept(['info], function (meta, next) {
+ console.log(`this middleware is only applied to some math commands`)
+ next()
+})
+```
+
+In this example, the console statement would be displayed for all commands except the `info` command (and any info subcommands).
+
### Built-in "Middleware"
Displaying help and version information is built-in (overridable).
diff --git a/examples/cli/index.js b/examples/cli/index.js
index ce6abf8..6e6b282 100755
--- a/examples/cli/index.js
+++ b/examples/cli/index.js
@@ -1,4 +1,4 @@
-#!/usr/bin/env node --experimental-modules -r source-map-support/register
+#!/usr/bin/env node -r source-map-support/register
import fs from 'fs'
import path from 'path'
diff --git a/examples/json/index.js b/examples/json/index.js
index f4a074d..c5d973c 100755
--- a/examples/json/index.js
+++ b/examples/json/index.js
@@ -1,4 +1,4 @@
-#!/usr/bin/env node --experimental-modules
+#!/usr/bin/env node
import fs from 'fs'
import path from 'path'
import { Command, Shell } from '../../src/index.js'
diff --git a/package.json b/package.json
index f992d95..4a34501 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.7.2",
+ "version": "1.8.0",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/base.js b/src/base.js
index e64a09a..4448f3f 100644
--- a/src/base.js
+++ b/src/base.js
@@ -408,6 +408,16 @@ export default class Base {
return this.#processors
}
+ get commandlist () {
+ const list = new Set()
+ this.commands.forEach(cmd => {
+ list.add(cmd.name)
+ cmd.commandlist.forEach(subcmd => list.add(`${cmd.name} ${subcmd}`))
+ })
+
+ return Array.from(list).sort()
+ }
+
getCommand(name = null) {
if (!name) {
return null
diff --git a/src/command.js b/src/command.js
index c066038..5ddc214 100644
--- a/src/command.js
+++ b/src/command.js
@@ -379,7 +379,21 @@ export default class Command extends Base {
// Parse the command input for flags
const data = { command: this.name, input: input.trim() }
- let flagConfig = Object.assign(this.__commonFlags, this.#flagConfig || {})
+ let commonFlags = this.__commonFlags
+ if (commonFlags.ignore && (Array.isArray(commonFlags.ignore) || typeof commonFlags.ignore === 'string')) {
+ const ignore = new Set(Array.isArray(commonFlags.ignore) ? commonFlags.ignore : [commonFlags.ignore])
+ delete commonFlags.ignore
+ const root = this.commandroot.replace(new RegExp(`^${this.shell.name}\\s+`, 'i'), '')
+
+ for (const cmd of ignore) {
+ if (root.startsWith(cmd)) {
+ commonFlags = {}
+ break
+ }
+ }
+ }
+
+ let flagConfig = Object.assign(commonFlags, this.#flagConfig || {})
if (!flagConfig.hasOwnProperty('help')) {
flagConfig.help = {
diff --git a/src/shell.js b/src/shell.js
index 6a081b5..3bbbb5b 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -138,6 +138,32 @@ export default class Shell extends Base {
commands.forEach(cmd => this.#middlewareGroups.set(cmd.trim(), (this.#middlewareGroups.get(cmd.trim()) || []).concat(fns)))
}
+ useExcept (commands) {
+ if (arguments.length < 2) {
+ throw new Error('useExcept([\'command\', \'command\'], fn) requires two or more arguments.')
+ }
+
+ commands = typeof commands === 'string' ? commands.split(/\s+/) : commands
+
+ if (!Array.isArray(commands) || commands.filter(c => typeof c !== 'string').length > 0) {
+ throw new Error(`The first argument of useExcept must be a string or array of strings. Received ${typeof commands}`)
+ }
+
+ const fns = Array.from(arguments).slice(1)
+ const all = new Set(this.commandlist.map(i => i.toLowerCase()))
+
+ commands.forEach(cmd => {
+ all.delete(cmd)
+ for (const c of all) {
+ if (c.indexOf(cmd) === 0) {
+ all.delete(c)
+ }
+ }
+ })
+
+ this.useWith(Array.from(all), ...fns)
+ }
+
async exec (input, callback) {
// The array check exists because people are passing process.argv.slice(2) into this
// method, often forgetting to join the values into a string.
diff --git a/test/unit/01-sanity/02-middleware.js b/test/unit/01-sanity/02-middleware.js
index 32b2dc4..79e1e3f 100644
--- a/test/unit/01-sanity/02-middleware.js
+++ b/test/unit/01-sanity/02-middleware.js
@@ -113,6 +113,51 @@ test('Command Specific Middleware', t => {
})
})
+test('Command Specific Middleware Exceptions', async t => {
+ let ok = false
+
+ const shell = new Shell({
+ name: 'test',
+ commands: [{
+ name: 'a',
+ handler () { },
+ commands: [{
+ name: 'f',
+ handler () { }
+ }]
+ }, {
+ name: 'b',
+ handler () { },
+ commands: [{
+ name: 'e',
+ handler () {}
+ }]
+ }, {
+ name: 'c',
+ handler () { }
+ }, {
+ name: 'd',
+ handler () {
+ ok = true
+ }
+ }]
+ })
+
+ shell.useExcept(['b', 'c'], (meta, next) => { count++; next() })
+
+ let count = 0
+ await shell.exec('a').catch(t.fail)
+ await shell.exec('b').catch(t.fail)
+ await shell.exec('c').catch(t.fail)
+ await shell.exec('d').catch(t.fail)
+ await shell.exec('b e').catch(t.fail)
+ await shell.exec('a f').catch(t.fail)
+
+ t.ok(count === 3, `Expected 3 middleware operations to run. Recognized ${count}.`)
+ t.ok(ok, 'Handler executes at the end.')
+ t.end()
+})
+
test('Basic Trailers', t => {
let ok = false
let after = 0
diff --git a/test/unit/01-sanity/05-commonflags.js b/test/unit/01-sanity/05-commonflags.js
index 0145bd3..772156b 100644
--- a/test/unit/01-sanity/05-commonflags.js
+++ b/test/unit/01-sanity/05-commonflags.js
@@ -88,3 +88,52 @@ test('Common flags (command-specific)', t => {
})
.catch(e => console.log(e.stack) && t.fail(e.message) && t.end())
})
+
+test('Common flags (exclusions)', async t => {
+ const shell = new Shell({
+ name: 'account',
+ commonflags: {
+ ignore: ['other'],
+ typical: {
+ alias: 't',
+ description: 'A typical flag on all commands.',
+ default: true
+ }
+ },
+ commands: [{
+ name: 'create',
+ handler (meta) {
+ t.ok(meta.flag('typical'), `Retrieved common flag value. Expected true, received ${meta.flag('typical')}`)
+ }
+ }, {
+ name: 'delete',
+ handler (meta) {
+ t.ok(meta.flag('typical'), `Retrieved common flag value. Expected true, received ${meta.flag('typical')}`)
+ }
+ }, {
+ name: 'other',
+ handler (meta) {
+ t.ok(!meta.flags.recognized.hasOwnProperty('typical'), 'The common flag "typical" was successfully excluded.')
+ },
+ commands: [{
+ name: 'sub',
+ handler (meta) {
+ t.ok(!meta.flags.recognized.hasOwnProperty('typical'), 'The common flag "typical" was successfully excluded from a sub command.')
+ },
+ commands: [{
+ name: 'cmd',
+ handler (meta) {
+ t.ok(!meta.flags.recognized.hasOwnProperty('typical'), 'The common flag "typical" was successfully excluded from a nested sub command.')
+ }
+ }]
+ }]
+ }]
+ })
+
+ await shell.exec('create').catch(t.fail)
+ await shell.exec('delete').catch(t.fail)
+ await shell.exec('other').catch(t.fail)
+ await shell.exec('other sub').catch(t.fail)
+ await shell.exec('other sub cmd').catch(t.fail)
+ t.end()
+})
From 33586e0cf809023b79d24e98ef0eada431a54b90 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Thu, 16 Jul 2020 17:43:21 -0500
Subject: [PATCH 096/152] Allow modification of flag metadata by middleware
functions
---
package-lock.json | 2 +-
package.json | 2 +-
src/command.js | 7 +++++--
3 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 6cce510..bee7941 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.7.2",
+ "version": "1.8.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 4a34501..0bb87bb 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.0",
+ "version": "1.8.1",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/command.js b/src/command.js
index 5ddc214..69dcf8d 100644
--- a/src/command.js
+++ b/src/command.js
@@ -405,7 +405,6 @@ export default class Command extends Base {
}
const flags = Array.from(FLAG_PATTERN[Symbol.matchAll](input), x => x[0])
-// console.log(flags, flagConfig)
const parser = new Parser(flags, flagConfig)
const pdata = parser.data
const recognized = {}
@@ -444,7 +443,11 @@ export default class Command extends Base {
if (typeof name === 'number') {
return Array.from(parser.unrecognizedFlags)[name]
} else {
- return pdata.flagSource[name].value
+ if (data.flags.recognized.hasOwnProperty(pdata.flagSource[name].name)) {
+ return data.flags.recognized[pdata.flagSource[name].name]
+ } else {
+ return pdata.flagSource[name].value
+ }
}
} catch (e) {
if (this.arguments.has(name)) {
From a8717eaaa4b56e46b0b1ad435e7add387b24f152 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Thu, 16 Jul 2020 18:46:52 -0500
Subject: [PATCH 097/152] Applied universal flag filter globally (help and data
object now respect the filter as a result).
---
package-lock.json | 2 +-
package.json | 2 +-
src/command.js | 43 +++++++++++++++++++-------------
src/format.js | 2 +-
test/unit/01-sanity/01-sanity.js | 4 +--
5 files changed, 31 insertions(+), 22 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index bee7941..7b06e68 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.1",
+ "version": "1.8.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 0bb87bb..3309b84 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.1",
+ "version": "1.8.2",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/command.js b/src/command.js
index 69dcf8d..b2639e9 100644
--- a/src/command.js
+++ b/src/command.js
@@ -118,17 +118,40 @@ export default class Command extends Base {
throw new Error(`Unrecognized configuration attribute(s): ${unrecognized.join(', ')}`)
}
+ const ignoreFlags = commonFlags => {
+ if (commonFlags.ignore && (Array.isArray(commonFlags.ignore) || typeof commonFlags.ignore === 'string')) {
+ const ignore = new Set(Array.isArray(commonFlags.ignore) ? commonFlags.ignore : [commonFlags.ignore])
+ // delete commonFlags.ignore
+ const root = this.commandroot.replace(new RegExp(`^${this.shell.name}\\s+`, 'i'), '')
+
+ for (const cmd of ignore) {
+ if (root.startsWith(cmd)) {
+ commonFlags = {}
+ break
+ }
+ }
+ }
+
+ return commonFlags
+ }
+
Object.defineProperties(this, {
__commonFlags: {
enumerable: false,
get () {
- let flags = this.__commonflags //Object.assign({}, this.__commonflags, this.#flagConfig)
+ let flags = ignoreFlags(this.__commonflags) //Object.assign({}, this.__commonflags, this.#flagConfig)
if (this.parent !== null) {
flags = Object.assign(flags, this.parent.__commonFlags)
}
- return Object.assign({}, this.shell !== null ? this.shell.__commonflags : {}, flags)
+ const result = Object.assign({}, this.shell !== null ? ignoreFlags(this.shell.__commonflags) : {}, flags)
+
+ if (Array.isArray(result.ignore) || typeof result.ignore === 'string') {
+ delete result.ignore
+ }
+
+ return result
}
},
__flagConfig: {
@@ -379,21 +402,7 @@ export default class Command extends Base {
// Parse the command input for flags
const data = { command: this.name, input: input.trim() }
- let commonFlags = this.__commonFlags
- if (commonFlags.ignore && (Array.isArray(commonFlags.ignore) || typeof commonFlags.ignore === 'string')) {
- const ignore = new Set(Array.isArray(commonFlags.ignore) ? commonFlags.ignore : [commonFlags.ignore])
- delete commonFlags.ignore
- const root = this.commandroot.replace(new RegExp(`^${this.shell.name}\\s+`, 'i'), '')
-
- for (const cmd of ignore) {
- if (root.startsWith(cmd)) {
- commonFlags = {}
- break
- }
- }
- }
-
- let flagConfig = Object.assign(commonFlags, this.#flagConfig || {})
+ let flagConfig = Object.assign(this.__commonFlags, this.#flagConfig || {})
if (!flagConfig.hasOwnProperty('help')) {
flagConfig.help = {
diff --git a/src/format.js b/src/format.js
index e9406c9..51fb417 100644
--- a/src/format.js
+++ b/src/format.js
@@ -6,7 +6,7 @@ class Formatter {
#data = null
#tableWidth = 80
#colAlign = [] // Defaults to ['l', 'l', 'l']
- #colWidth = ['15%', '20%', '65%']
+ #colWidth = ['20%', '15%', '65%']
constructor (data) {
this.#data = data
diff --git a/test/unit/01-sanity/01-sanity.js b/test/unit/01-sanity/01-sanity.js
index 3e60091..2627581 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/test/unit/01-sanity/01-sanity.js
@@ -86,8 +86,8 @@ test('Output Formatting', t => {
Flags:
- --test [-t] test description
- --more [-m, -mr] This is a longer description that should break onto
+ --test [-t] test description
+ --more [-m, -mr] This is a longer description that should break onto
more than one line, or perhaps even more than one
extra line with especially poor grammar and
spellling.
From 0e5f217fa0dbeaae3899148db4def61e711b4534 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sun, 27 Dec 2020 15:52:21 -0600
Subject: [PATCH 098/152] Cleaned up syntax, updated build to use author/dev
and include args/table libs by defualt.
---
.github/workflows/deploy.yml | 239 +++++++--
.github/workflows/pr.yml | 91 ++++
.gitignore | 1 +
LICENSE => LICENSE.md | 0
package-lock.json | 477 +++++++++++++++++-
package.json | 57 ++-
src/base.js | 82 +--
src/command.js | 114 ++---
src/format.js | 34 +-
src/middleware.js | 2 +-
src/shell.js | 51 +-
src/utility.js | 10 +-
test/.eslintrc | 13 -
test/assets/index.html | 358 -------------
test/package.json | 86 ----
test/syntax/validator.js | 94 ----
test/unit/karma.conf.cjs | 189 -------
test/unit/prepareKarmaBrowserSuite.js | 89 ----
test/unit/prepareManualTestEnvironment.js | 73 ---
{test/unit/01-sanity => tests}/01-sanity.js | 40 +-
.../unit/01-sanity => tests}/02-middleware.js | 7 +-
.../01-sanity => tests}/03-help-defaults.js | 6 +-
{test/unit/01-sanity => tests}/04-metadata.js | 5 +-
.../01-sanity => tests}/05-commonflags.js | 7 +-
{test/unit/01-sanity => tests}/06-history.js | 5 +-
{test/unit/01-sanity => tests}/07-plugins.js | 6 +-
.../01-sanity => tests}/100-regression.js | 5 +-
27 files changed, 997 insertions(+), 1144 deletions(-)
create mode 100644 .github/workflows/pr.yml
rename LICENSE => LICENSE.md (100%)
delete mode 100644 test/.eslintrc
delete mode 100644 test/assets/index.html
delete mode 100644 test/package.json
delete mode 100755 test/syntax/validator.js
delete mode 100644 test/unit/karma.conf.cjs
delete mode 100644 test/unit/prepareKarmaBrowserSuite.js
delete mode 100644 test/unit/prepareManualTestEnvironment.js
rename {test/unit/01-sanity => tests}/01-sanity.js (83%)
rename {test/unit/01-sanity => tests}/02-middleware.js (97%)
rename {test/unit/01-sanity => tests}/03-help-defaults.js (95%)
rename {test/unit/01-sanity => tests}/04-metadata.js (98%)
rename {test/unit/01-sanity => tests}/05-commonflags.js (96%)
rename {test/unit/01-sanity => tests}/06-history.js (90%)
rename {test/unit/01-sanity => tests}/07-plugins.js (96%)
rename {test/unit/01-sanity => tests}/100-regression.js (93%)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 609c374..6c5d912 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -7,22 +7,77 @@ on:
jobs:
build:
- name: 'Build & Release'
+ name: 'Release'
runs-on: ubuntu-latest
steps:
# Checkout updated source code
- uses: actions/checkout@v2
-
- # If the version has changed, create a new git tag for it.
- - name: Tag
- id: autotagger
- uses: butlerlogic/action-autotag@master
+ name: Checkout Code
+
+ - uses: actions/setup-node@v1
+ name: Setup Node.js
+ with:
+ node-version: '15'
+
+ - uses: actions/cache@v2
+ name: Establish Docker Cache
+ id: cache
+ with:
+ path: docker-cache
+ key: ${{ runner.os }}-docker-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.os }}-docker-
+
+ - name: Load cached Docker layers
+ run: |
+ if [ -d "docker-cache" ]; then
+ cat docker-cache/x* > my-image.tar
+ docker load < my-image.tar
+ rm -rf docker-cache
+ fi
+
+ - name: Setup Build Tooling
+ id: setup
+ run: |
+ base=$(curl -L -s 'https://registry.hub.docker.com/v2/repositories/author/dev-base/tags?page_size=1'|jq '."results"[]["name"]')
+ base=$(sed -e 's/^"//' -e 's/"$//' <<<"$base")
+ echo Retrieving author/dev/dev-base:$base
+ docker pull author/dev-base:$base
+
+ deno=$(curl -L -s 'https://registry.hub.docker.com/v2/repositories/author/dev-deno/tags?page_size=1'|jq '."results"[]["name"]')
+ deno=$(sed -e 's/^"//' -e 's/"$//' <<<"$deno")
+ echo Retrieving author/dev/dev-deno:$deno
+ docker pull author/dev-deno:$deno
+
+ browser=$(curl -L -s 'https://registry.hub.docker.com/v2/repositories/author/dev-browser/tags?page_size=1'|jq '."results"[]["name"]')
+ browser=$(sed -e 's/^"//' -e 's/"$//' <<<"$browser")
+ echo Retrieving author/dev/dev-browser:$browser
+ docker pull author/dev-browser:$browser
+
+ node=$(curl -L -s 'https://registry.hub.docker.com/v2/repositories/author/dev-node/tags?page_size=1'|jq '."results"[]["name"]')
+ node=$(sed -e 's/^"//' -e 's/"$//' <<<"$node")
+ echo Retrieving author/dev/dev-node:$node
+ docker pull author/dev-node:$node
+
+ # node -e "const p=new Set(Object.keys(require('./package.json').peerDependencies));p.delete('@author.io/dev');console.log('npm i ' + Array.from(p).join(' '))"
+ version=$(npm show @author.io/dev version)
+ echo $version
+ npm i -g @author.io/dev@$version
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- # The remaining steps all depend on whether or not
- # a new tag was created. There is no need to release/publish
- # updates until the code base is in a releaseable state.
+
+ - name: Test
+ if: success()
+ run: |
+ dev -v
+ npm run ci
+
+ - name: Tag
+ id: autotagger
+ if: success()
+ uses: butlerlogic/action-autotag@stable
+ with:
+ GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
# If the new version/tag is a pre-release (i.e. 1.0.0-beta.1), create
# an environment variable indicating it is a prerelease.
@@ -30,10 +85,7 @@ jobs:
if: steps.autotagger.outputs.tagname != ''
run: |
if [[ "${{ steps.autotagger.output.version }}" == *"-"* ]]; then echo "::set-env IS_PRERELEASE=true";else echo "::set-env IS_PRERELEASE=''";fi
-
- # Create a github release
- # This will create a snapshot of the module,
- # available in the "Releases" section on Github.
+
- name: Release
id: create_release
if: steps.autotagger.outputs.tagname != ''
@@ -47,47 +99,31 @@ jobs:
draft: false
prerelease: env.IS_PRERELEASE != ''
- - uses: actions/setup-node@v1
- if: steps.create_release.outputs.id != ''
- with:
- node-version: '13'
-
# Build tarballs of the module code.
- name: Build Release Artifacts
id: build_release
if: steps.create_release.outputs.id != ''
run: |
- npm install
- cd ./build && npm install && cd ../
- npm run build --if-present
- for d in .dist/*/*/ ; do tar -cvzf ${d%%/}-${{ steps.autotagger.outputs.version }}.tar.gz ${d%%}*; done;
- if [[ ${{ github.ref }} == *"-"* ]]; then echo ::set-output isprerelease=true;else echo ::set-output isprerelease=false;fi
+ dev build --pack --mode ci --peer
+ cp -rf .dist ./dist
+
# Upload tarballs to the release.
- name: Upload Release Artifacts
uses: AButler/upload-release-assets@v2.0
if: steps.create_release.outputs.id != ''
with:
- files: './.dist/**/*.tar.gz'
+ files: '.dist/*.tar.gz'
repo-token: ${{ secrets.GITHUB_TOKEN }}
release-tag: ${{ steps.autotagger.outputs.tagname }}
- # Build npm packages
- - name: Build Module Artifacts
- id: build_npm
- if: steps.create_release.outputs.id != ''
- run: |
- npm install
- cd ./build && npm install && cd ../
- npm run build --if-present
- # Use this action to publish a single module to npm.
- - name: Publish
+ - name: Publish to npm
id: publish_npm
if: steps.autotagger.outputs.tagname != ''
- uses: author/action-publish@master
+ uses: author/action-publish@stable
with:
- scan: .dist
- env:
- REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
+ scan: ./dist
+ env:
+ REGISTRY_TOKEN: ${{ secrets.NPM_REGISTRY_TOKEN }}
- name: Rollback Release
if: failure() && steps.create_release.outputs.id != ''
@@ -118,7 +154,7 @@ jobs:
uses: Ilshidur/action-slack@master
with:
args: '@author.io/shell ${{ steps.autotagger.outputs.tagname }} published to npm.' # Optional
-
+
- name: Inaction Notification
if: steps.autotagger.outputs.tagname == ''
env:
@@ -128,4 +164,125 @@ jobs:
SLACK_AVATAR: "https://cdn.freebiesupply.com/logos/large/2x/nodejs-icon-logo-png-transparent.png" # Optional. can be (repository, sender, an URL) (defaults to webhook app avatar)
uses: Ilshidur/action-slack@master
with:
- args: "New code was added to author/shell master branch." # Optional
\ No newline at end of file
+ args: "New code was added to author/shell master branch." # Optional
+
+
+
+
+
+ # # If the version has changed, create a new git tag for it.
+ # - name: Tag
+ # id: autotagger
+ # uses: butlerlogic/action-autotag@master
+ # env:
+ # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ # # The remaining steps all depend on whether or not
+ # # a new tag was created. There is no need to release/publish
+ # # updates until the code base is in a releaseable state.
+
+ # # If the new version/tag is a pre-release (i.e. 1.0.0-beta.1), create
+ # # an environment variable indicating it is a prerelease.
+ # - name: Pre-release
+ # if: steps.autotagger.outputs.tagname != ''
+ # run: |
+ # if [[ "${{ steps.autotagger.output.version }}" == *"-"* ]]; then echo "::set-env IS_PRERELEASE=true";else echo "::set-env IS_PRERELEASE=''";fi
+
+ # # Create a github release
+ # # This will create a snapshot of the module,
+ # # available in the "Releases" section on Github.
+ # - name: Release
+ # id: create_release
+ # if: steps.autotagger.outputs.tagname != ''
+ # uses: actions/create-release@v1.0.0
+ # env:
+ # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ # with:
+ # tag_name: ${{ steps.autotagger.outputs.tagname }}
+ # release_name: ${{ steps.autotagger.outputs.tagname }}
+ # body: ${{ steps.autotagger.outputs.tagmessage }}
+ # draft: false
+ # prerelease: env.IS_PRERELEASE != ''
+
+ # - uses: actions/setup-node@v1
+ # if: steps.create_release.outputs.id != ''
+ # with:
+ # node-version: '13'
+
+ # # Build tarballs of the module code.
+ # - name: Build Release Artifacts
+ # id: build_release
+ # if: steps.create_release.outputs.id != ''
+ # run: |
+ # npm install
+ # cd ./build && npm install && cd ../
+ # npm run build --if-present
+ # for d in .dist/*/*/ ; do tar -cvzf ${d%%/}-${{ steps.autotagger.outputs.version }}.tar.gz ${d%%}*; done;
+ # if [[ ${{ github.ref }} == *"-"* ]]; then echo ::set-output isprerelease=true;else echo ::set-output isprerelease=false;fi
+ # # Upload tarballs to the release.
+ # - name: Upload Release Artifacts
+ # uses: AButler/upload-release-assets@v2.0
+ # if: steps.create_release.outputs.id != ''
+ # with:
+ # files: './.dist/**/*.tar.gz'
+ # repo-token: ${{ secrets.GITHUB_TOKEN }}
+ # release-tag: ${{ steps.autotagger.outputs.tagname }}
+
+ # # Build npm packages
+ # - name: Build Module Artifacts
+ # id: build_npm
+ # if: steps.create_release.outputs.id != ''
+ # run: |
+ # npm install
+ # cd ./build && npm install && cd ../
+ # npm run build --if-present
+ # # Use this action to publish a single module to npm.
+ # - name: Publish
+ # id: publish_npm
+ # if: steps.autotagger.outputs.tagname != ''
+ # uses: author/action-publish@master
+ # with:
+ # scan: .dist
+ # env:
+ # REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
+
+ # - name: Rollback Release
+ # if: failure() && steps.create_release.outputs.id != ''
+ # uses: author/action-rollback@stable
+ # with:
+ # tag: ${{ steps.autotagger.outputs.tagname }}
+ # env:
+ # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ # - name: Failure Notification
+ # if: failure() && steps.create_release.outputs.id != ''
+ # env:
+ # SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
+ # SLACK_USERNAME: Github # Optional. (defaults to webhook app)
+ # SLACK_CHANNEL: author # Optional. (defaults to webhook)
+ # SLACK_AVATAR: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/320px-Npm-logo.svg.png"
+ # uses: Ilshidur/action-slack@master
+ # with:
+ # args: '@author.io/shell ${{ steps.autotagger.outputs.tagname }} failed to publish and was rolled back.' # Optional
+
+ # - name: Success Notification
+ # if: success() && steps.autotagger.outputs.tagname != ''
+ # env:
+ # SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
+ # SLACK_USERNAME: Github # Optional. (defaults to webhook app)
+ # SLACK_CHANNEL: author # Optional. (defaults to webhook)
+ # SLACK_AVATAR: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/320px-Npm-logo.svg.png"
+ # uses: Ilshidur/action-slack@master
+ # with:
+ # args: '@author.io/shell ${{ steps.autotagger.outputs.tagname }} published to npm.' # Optional
+
+ # - name: Inaction Notification
+ # if: steps.autotagger.outputs.tagname == ''
+ # env:
+ # SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
+ # SLACK_USERNAME: Github # Optional. (defaults to webhook app)
+ # SLACK_CHANNEL: author # Optional. (defaults to webhook)
+ # SLACK_AVATAR: "https://cdn.freebiesupply.com/logos/large/2x/nodejs-icon-logo-png-transparent.png" # Optional. can be (repository, sender, an URL) (defaults to webhook app avatar)
+ # uses: Ilshidur/action-slack@master
+ # with:
+ # args: "New code was added to author/shell master branch." # Optional
\ No newline at end of file
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
new file mode 100644
index 0000000..2c23e4d
--- /dev/null
+++ b/.github/workflows/pr.yml
@@ -0,0 +1,91 @@
+name: Test Suite
+
+on:
+ pull_request:
+ branches:
+ - master
+
+jobs:
+ build:
+ name: 'Run Tests'
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ name: Checkout Code
+
+ - name: List Directory Contents (for Troubleshooting)
+ run: |
+ pwd
+ ls -l
+
+ - uses: actions/setup-node@v1
+ name: Setup Node.js
+ with:
+ node-version: '15'
+
+ - uses: actions/cache@v2
+ name: Establish npm Cache
+ with:
+ path: ~/.npm
+ key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-node-
+
+ - uses: actions/cache@v2
+ name: Establish Docker Cache
+ id: cache
+ with:
+ path: docker-cache
+ key: ${{ runner.os }}-docker-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.os }}-docker-
+
+ - name: Load cached Docker layers
+ run: |
+ if [ -d "docker-cache" ]; then
+ cat docker-cache/x* > my-image.tar
+ docker load < my-image.tar
+ rm -rf docker-cache
+ fi
+
+ - name: Download Dev Tooling
+ id: setup
+ run: |
+ echo ${{ secrets.GH_DOCKER_TOKEN }} | docker login https://docker.pkg.github.com -u ${{ secrets.GH_DOCKER_USER }} --password-stdin
+ base=$(curl -L -s 'https://registry.hub.docker.com/v2/repositories/author/dev-base/tags?page_size=1'|jq '."results"[]["name"]')
+ base=$(sed -e 's/^"//' -e 's/"$//' <<<"$base")
+ echo Retrieving author/dev/dev-base:$base
+ docker pull author/dev-base:$base
+ # docker pull docker.pkg.github.com/author/dev/dev-base:$base
+
+ deno=$(curl -L -s 'https://registry.hub.docker.com/v2/repositories/author/dev-deno/tags?page_size=1'|jq '."results"[]["name"]')
+ deno=$(sed -e 's/^"//' -e 's/"$//' <<<"$deno")
+ echo Retrieving author/dev/dev-deno:$deno
+ # docker pull docker.pkg.github.com/author/dev/dev-deno:$deno
+ docker pull author/dev-deno:$deno
+
+ browser=$(curl -L -s 'https://registry.hub.docker.com/v2/repositories/author/dev-browser/tags?page_size=1'|jq '."results"[]["name"]')
+ browser=$(sed -e 's/^"//' -e 's/"$//' <<<"$browser")
+ echo Retrieving author/dev/dev-browser:$browser
+ # docker pull docker.pkg.github.com/author/dev/dev-browser:$browser
+ docker pull author/dev-browser:$browser
+
+ node=$(curl -L -s 'https://registry.hub.docker.com/v2/repositories/author/dev-node/tags?page_size=1'|jq '."results"[]["name"]')
+ node=$(sed -e 's/^"//' -e 's/"$//' <<<"$node")
+ echo Retrieving author/dev/dev-node:$node
+ # docker pull docker.pkg.github.com/author/dev/dev-node:$node
+ docker pull author/dev-node:$node
+
+ # node -e "const p=new Set(Object.keys(require('./package.json').peerDependencies));p.delete('@author.io/dev');console.log('npm i ' + Array.from(p).join(' '))"
+ version=$(npm show @author.io/dev version)
+ echo $version
+ npm i -g @author.io/dev@$version
+ dev -v
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Test
+ if: success()
+ run: |
+ dev -v
+ npm run ci
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 2190ef9..5a478a5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
*.log
.*
+_*
!.github
!.gitignore
!.npmignore
diff --git a/LICENSE b/LICENSE.md
similarity index 100%
rename from LICENSE
rename to LICENSE.md
diff --git a/package-lock.json b/package-lock.json
index 7b06e68..e049ba7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,18 +1,489 @@
{
"name": "@author.io/shell",
"version": "1.8.2",
- "lockfileVersion": 1,
+ "lockfileVersion": 2,
"requires": true,
+ "packages": {
+ "": {
+ "version": "1.8.2",
+ "license": "MIT",
+ "devDependencies": {
+ "@author.io/arg": "^1.3.8",
+ "@author.io/dev": "^1.1.5",
+ "@author.io/table": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=13.5.0"
+ }
+ },
+ "node_modules/@author.io/arg": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.8.tgz",
+ "integrity": "sha512-JXeBApJ9hCrlDPHoieX5d3BBqP6l1O0x95TkDSYfZgIa9OitQHwJuaBM7eyv8bkxL4pQnAORvftifVW/DdGinA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/@author.io/dev": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@author.io/dev/-/dev-1.1.5.tgz",
+ "integrity": "sha512-bid83f8hmaU86MVerAggVmkc5gE3kfkoHw54tJypYTqlwo7NViW7CppuzrH9cndCAIIBhThK6GgMYCgD4L9o/A==",
+ "dev": true,
+ "dependencies": {
+ "@author.io/node-shell": "^1.8.2",
+ "@author.io/shell": "^1.3.8",
+ "chalk": "^4.1.0",
+ "glob": "^7.1.6",
+ "semver": "^7.3.2"
+ },
+ "bin": {
+ "dev": "index.js",
+ "space": "index.js"
+ }
+ },
+ "node_modules/@author.io/node-shell": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/@author.io/node-shell/-/node-shell-1.8.2.tgz",
+ "integrity": "sha512-mnOwUASxLYV3NcSlUvjHwnLkbwhxSUcq/dwUPkawWmu5TJ6txYcU+Eub4QMyCXqpiThyiFrRc6Za89Nh+dKo0w==",
+ "dev": true,
+ "dependencies": {
+ "@author.io/arg": "^1.3.8",
+ "@author.io/table": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=13.5.0"
+ }
+ },
+ "node_modules/@author.io/shell": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/@author.io/shell/-/shell-1.3.8.tgz",
+ "integrity": "sha512-/ybwBCffBeFp4QS5tnC0bd/XxgTNXP9r6FVBJiFWolTjALVfL0tEUtOrNF+JdVxBf7vLvmnSiz5EUvrdj9Cm0A==",
+ "dev": true,
+ "dependencies": {
+ "@author.io/arg": "^1.2.6",
+ "@author.io/table": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=13.5.0"
+ }
+ },
+ "node_modules/@author.io/table": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.0.3.tgz",
+ "integrity": "sha512-JnsndB8kzcyLwYp42teOpdICCP4KZHmzOlFnL/uxfQCxGrQKEIH8Occq8LFQXO7OKri/tOYG5mOhrWxxuoRyzw==",
+ "dev": true
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "dev": true
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "node_modules/glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/semver": {
+ "version": "7.3.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
+ "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ }
+ },
"dependencies": {
"@author.io/arg": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.8.tgz",
- "integrity": "sha512-JXeBApJ9hCrlDPHoieX5d3BBqP6l1O0x95TkDSYfZgIa9OitQHwJuaBM7eyv8bkxL4pQnAORvftifVW/DdGinA=="
+ "integrity": "sha512-JXeBApJ9hCrlDPHoieX5d3BBqP6l1O0x95TkDSYfZgIa9OitQHwJuaBM7eyv8bkxL4pQnAORvftifVW/DdGinA==",
+ "dev": true
+ },
+ "@author.io/dev": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@author.io/dev/-/dev-1.1.5.tgz",
+ "integrity": "sha512-bid83f8hmaU86MVerAggVmkc5gE3kfkoHw54tJypYTqlwo7NViW7CppuzrH9cndCAIIBhThK6GgMYCgD4L9o/A==",
+ "dev": true,
+ "requires": {
+ "@author.io/node-shell": "^1.8.2",
+ "@author.io/shell": "^1.3.8",
+ "chalk": "^4.1.0",
+ "glob": "^7.1.6",
+ "semver": "^7.3.2"
+ }
+ },
+ "@author.io/node-shell": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/@author.io/node-shell/-/node-shell-1.8.2.tgz",
+ "integrity": "sha512-mnOwUASxLYV3NcSlUvjHwnLkbwhxSUcq/dwUPkawWmu5TJ6txYcU+Eub4QMyCXqpiThyiFrRc6Za89Nh+dKo0w==",
+ "dev": true,
+ "requires": {
+ "@author.io/arg": "^1.3.8",
+ "@author.io/table": "^1.0.3"
+ }
+ },
+ "@author.io/shell": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/@author.io/shell/-/shell-1.3.8.tgz",
+ "integrity": "sha512-/ybwBCffBeFp4QS5tnC0bd/XxgTNXP9r6FVBJiFWolTjALVfL0tEUtOrNF+JdVxBf7vLvmnSiz5EUvrdj9Cm0A==",
+ "dev": true,
+ "requires": {
+ "@author.io/arg": "^1.2.6",
+ "@author.io/table": "^1.0.1"
+ }
},
"@author.io/table": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.0.3.tgz",
- "integrity": "sha512-JnsndB8kzcyLwYp42teOpdICCP4KZHmzOlFnL/uxfQCxGrQKEIH8Occq8LFQXO7OKri/tOYG5mOhrWxxuoRyzw=="
+ "integrity": "sha512-JnsndB8kzcyLwYp42teOpdICCP4KZHmzOlFnL/uxfQCxGrQKEIH8Occq8LFQXO7OKri/tOYG5mOhrWxxuoRyzw==",
+ "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"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "dev": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "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
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "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
+ },
+ "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
+ },
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
+ "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"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "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
+ },
+ "semver": {
+ "version": "7.3.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
+ "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
}
}
}
diff --git a/package.json b/package.json
index 3309b84..e83befb 100644
--- a/package.json
+++ b/package.json
@@ -1,22 +1,25 @@
{
"name": "@author.io/shell",
- "version": "1.8.2",
+ "version": "1.8.3",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
- "test": "cd ./test && npm test",
- "build": "cd ./build && npm run all",
- "build:node": "cd ./build && npm run node",
- "build:browser": "cd ./build && npm run browser",
- "test:node": "cd ./test && npm run node",
- "test:browser": "cd ./test && npm run browser",
- "reset": "echo Resetting test environments && cd ./test && npm run clean && cd ../build && npm run clean",
- "manually": "cd ./test && npm run browser:manual:open",
- "again": "cd ./test && npm run browser:manual",
- "setup": "echo \"Installing build and test dependencies...\" && cd ./build && npm i --no-package-lock && cd ../test && npm i --no-package-lock && echo Template Setup Complete.",
- "resetup": "node -e \"let fs=require('fs'),path=require('path');fs.rmdirSync(path.resolve('./build/node_modules'), { recursive: true });fs.rmdirSync(path.resolve('./test/node_modules'), { recursive: true });\" && npm run setup",
- "report:compat": "cd ./test && npm run compat",
- "report:syntax": "cd ./test && npm run syntax",
+ "start": "dev workspace",
+ "test": "npm run test:node && npm run test:deno && npm run test:browser && npm run report:syntax && npm run report:size",
+ "test:node": "dev test -rt node tests/*.js",
+ "test:node:sanity": "dev test -rt node tests/01-sanity.js",
+ "test:node:base": "dev test -rt node tests/02-base.js",
+ "test:node:relationships": "dev test -rt node tests/06-relationships.js",
+ "test:browser": "dev test -rt browser tests/*.js",
+ "test:browser:sanity": "dev test -rt browser tests/01-sanity.js",
+ "test:browser:base": "dev test -rt browser tests/02-base.js",
+ "test:deno": "dev test -rt deno tests/*.js",
+ "test:deno:sanity": "dev test -rt deno tests/01-sanity.js",
+ "manually": "dev test -rt manual tests/*.js",
+ "build": "dev build",
+ "report:syntax": "dev report syntax --pretty",
+ "report:size": "dev report size ./.dist/**/*.js ./.dist/**/*.js.map",
+ "report:compat": "dev report compatibility ./src/**/*.js",
"report:preview": "npm pack --dry-run && echo \"==============================\" && echo \"This report shows what will be published to the module registry. Pay attention to the tarball contents and assure no sensitive files will be published.\""
},
"keywords": [
@@ -25,7 +28,28 @@
"arg",
"shell"
],
- "author": "Corey Butler",
+ "dev": {
+ "ignorecircular": [
+ "src/command.js",
+ "src/shell.js"
+ ],
+ "replace": {
+ "<#REPLACE_VERSION#>": "package.version"
+ },
+ "alias": {
+ "@author.io/shell": "/app/.dist/shell/index.js",
+ "@author.io/arg": "/node_modules/@author.io/arg/index.js",
+ "@author.io/table": "/node_modules/@author.io/table/src/index.js"
+ },
+ "volume": [
+ "./node_modules/@author.io/arg:/node_modules/@author.io/arg",
+ "./node_modules/@author.io/table:/node_modules/@author.io/table"
+ ]
+ },
+ "author": {
+ "name": "Corey Butler",
+ "url": "http://coreybutler.com"
+ },
"license": "MIT",
"type": "module",
"files": [
@@ -51,8 +75,9 @@
"globalThis"
]
},
- "dependencies": {
+ "devDependencies": {
"@author.io/arg": "^1.3.8",
+ "@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
}
}
diff --git a/src/base.js b/src/base.js
index 4448f3f..460ef62 100644
--- a/src/base.js
+++ b/src/base.js
@@ -27,7 +27,9 @@ export default class Base {
MultipleValues: null,
Required: null
}
+
#hasCustomDefaultHandler = false
+
#defaultHandler = function (meta) {
if (this.parent !== null && this.parent.hasCustomDefaultHandler) {
return this.parent.defaultHandler(...arguments)
@@ -40,28 +42,28 @@ export default class Base {
}
}
- constructor(cfg = {}) {
+ constructor (cfg = {}) {
if (typeof cfg !== 'object') {
throw new Error('Invalid command configuration. Expected an object.')
}
- if (!cfg.hasOwnProperty('name')) {
+ if (!cfg.hasOwnProperty('name')) { // eslint-disable-line no-prototype-builtins
throw new Error('Invalid command configuration. A "name" attribute is required.')
}
- if (cfg.hasOwnProperty('help')) {
+ if (cfg.hasOwnProperty('help')) { // eslint-disable-line no-prototype-builtins
this.#customHelp = cfg.help
}
- if (cfg.hasOwnProperty('usage')) {
+ if (cfg.hasOwnProperty('usage')) { // eslint-disable-line no-prototype-builtins
this.#customUsage = cfg.usage
}
- if (cfg.hasOwnProperty('disablehelp') && !cfg.hasOwnProperty('disableHelp')) {
+ if (cfg.hasOwnProperty('disablehelp') && !cfg.hasOwnProperty('disableHelp')) { // eslint-disable-line no-prototype-builtins
cfg.disableHelp = cfg.disablehelp
}
- if (cfg.hasOwnProperty('disableHelp') && cfg.disableHelp === true) {
+ if (cfg.hasOwnProperty('disableHelp') && cfg.disableHelp === true) { // eslint-disable-line no-prototype-builtins
this.#autohelp = false
}
@@ -73,12 +75,12 @@ export default class Base {
this.usage = cfg.usage
}
- if (cfg.hasOwnProperty('defaultHandler') && cfg.defaultHandler.toString() !== this.#defaultHandler.toString()) {
+ if (cfg.hasOwnProperty('defaultHandler') && cfg.defaultHandler.toString() !== this.#defaultHandler.toString()) { // eslint-disable-line no-prototype-builtins
this.defaultHandler = cfg.defaultHandler
}
if (typeof cfg.arguments === 'string') {
- cfg.arguments = cfg.arguments.split(/\s+|\t+|\,+|\;+/).map(arg => arg.trim())
+ cfg.arguments = cfg.arguments.split(/\s+|\t+|\,+|\;+/).map(arg => arg.trim()) // eslint-disable-line no-useless-escape
}
if (Array.isArray(cfg.arguments)) {
@@ -100,31 +102,31 @@ export default class Base {
cfg.commands.forEach(cmd => this.add(cmd))
} else if (typeof cfg.commands === 'object') {
for (const key in cfg.commands) {
- let data = cfg.commands[key]
+ const data = cfg.commands[key]
data.name = key
this.add(data)
}
}
- if (cfg.hasOwnProperty('middleware')) {
+ if (cfg.hasOwnProperty('middleware')) { // eslint-disable-line no-prototype-builtins
console.warn('The "middleware" attribute has been replaced with the "use" attribute.')
cfg.use = cfg.middleware
delete cfg.middleware
}
- if (!cfg.hasOwnProperty('commonflag')) {
- if (cfg.hasOwnProperty('commonFlag')) {
+ if (!cfg.hasOwnProperty('commonflag')) { // eslint-disable-line no-prototype-builtins
+ if (cfg.hasOwnProperty('commonFlag')) { // eslint-disable-line no-prototype-builtins
cfg.commonflag = cfg.commonFlag
- } else if (cfg.hasOwnProperty('commonflags')) {
+ } else if (cfg.hasOwnProperty('commonflags')) { // eslint-disable-line no-prototype-builtins
cfg.commonflag = cfg.commonflags
- } else if (cfg.hasOwnProperty('commonFlag')) {
+ } else if (cfg.hasOwnProperty('commonFlag')) { // eslint-disable-line no-prototype-builtins
cfg.commonflag = cfg.commonFlag
- } else if (cfg.hasOwnProperty('commonFlags')) {
+ } else if (cfg.hasOwnProperty('commonFlags')) { // eslint-disable-line no-prototype-builtins
cfg.commonflag = cfg.commonFlags
}
}
- if (cfg.hasOwnProperty('commonflag')) {
+ if (cfg.hasOwnProperty('commonflag')) { // eslint-disable-line no-prototype-builtins
if (typeof cfg.commonflag !== 'object') {
throw new Error('The "commonflag" configuration attribute must be an object.')
}
@@ -137,19 +139,19 @@ export default class Base {
Object.defineProperties(this, {
__processors: {
enumerable: false,
- get() {
+ get () {
return this.#processors
}
},
__commands: {
enumerable: false,
- get() {
+ get () {
return this.#commands
}
},
__width: {
enumerable: false,
- get() {
+ get () {
return this.#width
},
set (v) {
@@ -177,7 +179,7 @@ export default class Base {
writable: false,
value: code => {
if (typeof code === 'string') {
- this.use(Function('return ' + code)())
+ this.use(Function('return ' + code)()) // eslint-disable-line no-new-func
} else if (typeof code === 'function') {
this.use(code)
} else {
@@ -191,7 +193,7 @@ export default class Base {
writable: false,
value: code => {
if (typeof code === 'string') {
- this.trailer(Function('return ' + code)())
+ this.trailer(Function('return ' + code)()) // eslint-disable-line no-new-func
} else if (typeof code === 'function') {
this.trailer(code)
} else {
@@ -204,16 +206,16 @@ export default class Base {
configurable: false,
writable: false,
value: cfg => {
- if (cfg.hasOwnProperty('describeDefault') && typeof cfg.describeDefault === 'boolean') {
+ if (cfg.hasOwnProperty('describeDefault') && typeof cfg.describeDefault === 'boolean') { // eslint-disable-line no-prototype-builtins
this.#display.Default = cfg.describeDefault
}
- if (cfg.hasOwnProperty('describeOptions') && typeof cfg.describeOptions === 'boolean') {
+ if (cfg.hasOwnProperty('describeOptions') && typeof cfg.describeOptions === 'boolean') { // eslint-disable-line no-prototype-builtins
this.#display.Options = cfg.describeOptions
}
- if (cfg.hasOwnProperty('describeMultipleValues') && typeof cfg.describeMultipleValues === 'boolean') {
+ if (cfg.hasOwnProperty('describeMultipleValues') && typeof cfg.describeMultipleValues === 'boolean') { // eslint-disable-line no-prototype-builtins
this.#display.MultipleValues = cfg.describeMultipleValues
}
- if (cfg.hasOwnProperty('describeRequired') && typeof cfg.describeRequired === 'boolean') {
+ if (cfg.hasOwnProperty('describeRequired') && typeof cfg.describeRequired === 'boolean') { // eslint-disable-line no-prototype-builtins
this.#display.Required = cfg.describeRequired
}
}
@@ -244,10 +246,10 @@ export default class Base {
// @readonly
get URL () {
- let uri = (this.#url || '').trim()
+ const uri = (this.#url || '').trim()
if (uri.length === 0) {
- if (this.hasOwnProperty('parent')) {
+ if (this.hasOwnProperty('parent')) { // eslint-disable-line no-prototype-builtins
return this.parent.URL
} else if (this instanceof Command) {
return this.shell.URL
@@ -259,10 +261,10 @@ export default class Base {
// @readonly
get support () {
- let support = (this.#support || '').trim()
+ const support = (this.#support || '').trim()
if (support.length === 0) {
- if (this.hasOwnProperty('parent')) {
+ if (this.hasOwnProperty('parent')) { // eslint-disable-line no-prototype-builtins
return this.parent.support
} else if (this instanceof Command) {
return this.shell.support
@@ -272,7 +274,7 @@ export default class Base {
return support
}
- get autohelp() {
+ get autohelp () {
return this.#autohelp
}
@@ -281,7 +283,7 @@ export default class Base {
return
}
this.#autohelp = value
- this.#processors.forEach(cmd => cmd.autohelp = value)
+ this.#processors.forEach(cmd => { cmd.autohelp = value })
}
updateHelp () {
@@ -298,7 +300,7 @@ export default class Base {
if (this.shell && this.shell !== null && this.shell[attr] !== null) {
return this.shell[attr]
}
-
+
if (this.parent !== null) {
return this.parent[attr]
}
@@ -323,7 +325,7 @@ export default class Base {
return this.describeHelp('describeRequired', 'Required')
}
- get usage() {
+ get usage () {
if (this.#customUsage !== null) {
return typeof this.#customUsage === 'function' ? this.#customUsage() : this.#customUsage
}
@@ -368,7 +370,7 @@ export default class Base {
if (typeof value === 'function') {
this.#defaultHandler = value
this.#hasCustomDefaultHandler = true
- this.#processors.forEach(cmd => cmd.defaultProcessor = value)
+ this.#processors.forEach(cmd => { cmd.defaultProcessor = value })
} else {
throw new Error(`Invalid default method (must be a function, not "${typeof value}").`)
}
@@ -387,7 +389,7 @@ export default class Base {
const commands = {}
Array.from(this.#processors.values()).forEach(cmd => {
- let data = cmd.data
+ const data = cmd.data
const name = data.name
delete data.name
commands[name] = data
@@ -396,7 +398,7 @@ export default class Base {
return commands
}
- get middleware() {
+ get middleware () {
return this.#middleware
}
@@ -404,7 +406,7 @@ export default class Base {
return this.#trailer
}
- get commands() {
+ get commands () {
return this.#processors
}
@@ -418,12 +420,12 @@ export default class Base {
return Array.from(list).sort()
}
- getCommand(name = null) {
+ getCommand (name = null) {
if (!name) {
return null
}
- let names = name.split(/\s+/i)
+ const names = name.split(/\s+/i)
let cmd = this.#commands.get(names.shift())
if (cmd) {
cmd = this.#processors.get(cmd)
@@ -435,7 +437,7 @@ export default class Base {
return cmd instanceof Command ? cmd : null
}
- remove() {
+ remove () {
for (const cmd of arguments) {
if (typeof cmd === 'symbol') {
this.#processors.delete(cmd)
diff --git a/src/command.js b/src/command.js
index b2639e9..66af246 100644
--- a/src/command.js
+++ b/src/command.js
@@ -1,4 +1,5 @@
-import { Parser } from '../node_modules/@author.io/arg/index.js'
+// import { Parser } from '../../../@author.io/arg/index.js'
+import { Parser } from '@author.io/arg'
import Shell from './shell.js'
import Base from './base.js'
import { METHOD_PATTERN, FLAG_PATTERN, STRIP_QUOTE_PATTERN } from './utility.js'
@@ -11,11 +12,11 @@ export default class Command extends Base {
#flagConfig = {}
#parent = null
#shell = null
-
+
constructor (cfg = {}) {
- if (cfg.hasOwnProperty('handler')) {
+ if (cfg.hasOwnProperty('handler')) { // eslint-disable-line no-prototype-builtins
if (typeof cfg.handler === 'string') {
- cfg.handler = Function('return (' + cfg.handler.replace('function anonymous', 'function') + ').call(this)').call(globalThis)
+ cfg.handler = Function('return (' + cfg.handler.replace('function anonymous', 'function') + ').call(this)').call(globalThis) // eslint-disable-line no-new-func
}
if (typeof cfg.handler !== 'function') {
@@ -25,11 +26,11 @@ export default class Command extends Base {
super(cfg)
- if (cfg.hasOwnProperty('use') && Array.isArray(cfg.use)) {
+ if (cfg.hasOwnProperty('use') && Array.isArray(cfg.use)) { // eslint-disable-line no-prototype-builtins
cfg.use.forEach(code => this.initializeMiddleware(code))
}
- if (cfg.hasOwnProperty('trailer') && Array.isArray(cfg.trailer)) {
+ if (cfg.hasOwnProperty('trailer') && Array.isArray(cfg.trailer)) { // eslint-disable-line no-prototype-builtins
cfg.trailer.forEach(code => this.initializeTrailer(code))
}
@@ -38,7 +39,7 @@ export default class Command extends Base {
this.#fn = cfg.handler
this.#oid = Symbol(((cfg.name || cfg.usage) || cfg.pattern) || 'command')
this.#pattern = cfg.pattern || /[\s\S]+/i
-
+
if (cfg.alias && !cfg.aliases) {
cfg.aliases = typeof cfg.alias === 'string' ? [cfg.alias] : (Array.isArray(cfg.alias) ? cfg.alias : Array.from(cfg.alias))
delete cfg.alias
@@ -48,7 +49,7 @@ export default class Command extends Base {
if (!Array.isArray(cfg.aliases)) {
throw new Error('The alias property only accepts an array.')
}
-
+
this.#aliases = new Set(cfg.aliases)
}
@@ -58,11 +59,11 @@ export default class Command extends Base {
}
for (const [key, value] of Object.entries(cfg.flags)) {
- if (value.hasOwnProperty('alias')) {
+ if (value.hasOwnProperty('alias')) { // eslint-disable-line no-prototype-builtins
value.aliases = value.aliases || []
-
+
if (Array.isArray(value.alias)) {
- value.aliases = Array.from(new Set(...value.aliases, ... value.alias))
+ value.aliases = Array.from(new Set(...value.aliases, ...value.alias))
if (value.aliases.filter(a => typeof a !== 'string') > 0) {
throw new Error(`${key} flag aliases must be strings. Type failure on: ${value.aliases.filter(a => typeof a !== 'string').join(', ')}.`)
}
@@ -123,7 +124,7 @@ export default class Command extends Base {
const ignore = new Set(Array.isArray(commonFlags.ignore) ? commonFlags.ignore : [commonFlags.ignore])
// delete commonFlags.ignore
const root = this.commandroot.replace(new RegExp(`^${this.shell.name}\\s+`, 'i'), '')
-
+
for (const cmd of ignore) {
if (root.startsWith(cmd)) {
commonFlags = {}
@@ -131,7 +132,7 @@ export default class Command extends Base {
}
}
}
-
+
return commonFlags
}
@@ -139,8 +140,8 @@ export default class Command extends Base {
__commonFlags: {
enumerable: false,
get () {
- let flags = ignoreFlags(this.__commonflags) //Object.assign({}, this.__commonflags, this.#flagConfig)
-
+ let flags = ignoreFlags(this.__commonflags) // Object.assign({}, this.__commonflags, this.#flagConfig)
+
if (this.parent !== null) {
flags = Object.assign(flags, this.parent.__commonFlags)
}
@@ -157,7 +158,7 @@ export default class Command extends Base {
__flagConfig: {
enumerable: false,
get () {
- let flags = new Map(Object.entries(Object.assign(this.__commonFlags, this.#flagConfig || {})))
+ const flags = new Map(Object.entries(Object.assign(this.__commonFlags, this.#flagConfig || {})))
flags.delete('help')
return flags
}
@@ -167,7 +168,7 @@ export default class Command extends Base {
configurable: false,
writable: false,
value: input => {
- let args = input.trim().split(/\t+|\s+/)
+ const args = input.trim().split(/\t+|\s+/)
let cmd = this
while (args.length > 0) {
@@ -204,12 +205,12 @@ export default class Command extends Base {
handler = handler.replace(METHOD_PATTERN.exec(handler)[1], 'function ')
}
- let flags = Object.assign(this.__commonFlags, this.#flagConfig || {})
-
- for (let [key, value] of Object.entries(flags)) {
+ const flags = Object.assign(this.__commonFlags, this.#flagConfig || {})
+
+ for (const [key, value] of Object.entries(flags)) { // eslint-disable-line no-unused-vars
value.aliases = value.aliases || []
- if (value.hasOwnProperty('alias')) {
+ if (value.hasOwnProperty('alias')) { // eslint-disable-line no-prototype-builtins
if (value.aliases.indexOf(value.alias) < 0) {
value.aliases.push(value.alias)
}
@@ -219,7 +220,7 @@ export default class Command extends Base {
}
// Apply any missing default values to flags.
- Object.keys(flags).forEach(name => flags[name] = Object.assign(this.getFlagConfiguration(name), flags[name]))
+ Object.keys(flags).forEach(name => { flags[name] = Object.assign(this.getFlagConfiguration(name), flags[name]) })
const data = {
name: this.name,
@@ -235,7 +236,7 @@ export default class Command extends Base {
trailer: this.trailers.data
}
- for (let [key, value] of Object.entries(data.flags)) {
+ for (const [key, value] of Object.entries(data.flags)) { // eslint-disable-line no-unused-vars
delete value.alias
}
@@ -334,7 +335,7 @@ export default class Command extends Base {
addFlag (name, cfg) {
if (typeof name !== 'string') {
- if (!cfg.hasOwnProperty('name')) {
+ if (!cfg.hasOwnProperty('name')) { // eslint-disable-line no-prototype-builtins
throw new Error('Invalid flag name (should be a string).')
} else {
name = cfg.name
@@ -351,13 +352,13 @@ export default class Command extends Base {
getFlagConfiguration (name) {
let flag = this.__flagConfig.get(name)
if (!flag) {
- for (let [f, cfg] of this.__flagConfig) {
+ for (const [f, cfg] of this.__flagConfig) { // eslint-disable-line no-unused-vars
if ((cfg.aliases && cfg.aliases.indexOf(name) >= 0) || (cfg.alias && cfg.alias === flag)) {
flag = cfg
break
}
}
-
+
if (!flag) {
return null
}
@@ -365,20 +366,20 @@ export default class Command extends Base {
return {
description: flag.description,
- required: flag.hasOwnProperty('required') ? flag.required : false,
+ required: flag.hasOwnProperty('required') ? flag.required : false, // eslint-disable-line no-prototype-builtins
aliases: flag.aliases || [flag.alias].filter(i => i !== null),
type: flag.type === undefined ? 'string' : (typeof flag.type === 'string' ? flag.type : flag.type.name.toLowerCase()),
- options: flag.hasOwnProperty('options') ? flag.options : null,
- allowMultipleValues: flag.hasOwnProperty('allowMultipleValues') ? flag.allowMultipleValues : false
+ options: flag.hasOwnProperty('options') ? flag.options : null, // eslint-disable-line no-prototype-builtins
+ allowMultipleValues: flag.hasOwnProperty('allowMultipleValues') ? flag.allowMultipleValues : false // eslint-disable-line no-prototype-builtins
}
}
supportsFlag (name) {
- return this.#flagConfig.hasOwnProperty(name)
+ return this.#flagConfig.hasOwnProperty(name) // eslint-disable-line no-prototype-builtins
}
deepParse (input) {
- let meta = this.parse(input)
+ const meta = this.parse(input)
if (this.__commands.size === 0) {
return meta
@@ -388,8 +389,8 @@ export default class Command extends Base {
return meta
}
- let args = meta.input.split(/\s+/)
- let subcmd = this.__commands.get(args.shift())
+ const args = meta.input.split(/\s+/)
+ const subcmd = this.__commands.get(args.shift())
if (!subcmd) {
return meta
@@ -401,12 +402,11 @@ export default class Command extends Base {
parse (input) {
// Parse the command input for flags
const data = { command: this.name, input: input.trim() }
+ const flagConfig = Object.assign(this.__commonFlags, this.#flagConfig || {})
- let flagConfig = Object.assign(this.__commonFlags, this.#flagConfig || {})
-
- if (!flagConfig.hasOwnProperty('help')) {
+ if (!flagConfig.hasOwnProperty('help')) { // eslint-disable-line no-prototype-builtins
flagConfig.help = {
- description: `Display ${ this.name } help.`,
+ description: `Display ${this.name} help.`,
// aliases: ['h'],
default: false,
type: 'boolean'
@@ -418,16 +418,16 @@ export default class Command extends Base {
const pdata = parser.data
const recognized = {}
- parser.recognizedFlags.forEach(flag => recognized[flag] = pdata[flag])
+ parser.recognizedFlags.forEach(flag => { recognized[flag] = pdata[flag] })
parser.unrecognizedFlags.forEach(arg => delete recognized[arg])
-
+
data.flags = { recognized, unrecognized: parser.unrecognizedFlags }
data.valid = parser.valid
data.violations = parser.violations
-
+
data.parsed = {}
if (Object.keys(pdata.flagSource).length > 0) {
- for (const [key, src] of Object.entries(pdata.flagSource)) {
+ for (const [key, src] of Object.entries(pdata.flagSource)) { // eslint-disable-line no-unused-vars
data.parsed[src.name] = src.inputName
}
}
@@ -441,7 +441,7 @@ export default class Command extends Base {
}
const args = Array.from(this.arguments)
-
+
Object.defineProperties(data, {
flag: {
enumerable: true,
@@ -452,7 +452,7 @@ export default class Command extends Base {
if (typeof name === 'number') {
return Array.from(parser.unrecognizedFlags)[name]
} else {
- if (data.flags.recognized.hasOwnProperty(pdata.flagSource[name].name)) {
+ if (data.flags.recognized.hasOwnProperty(pdata.flagSource[name].name)) { // eslint-disable-line no-prototype-builtins
return data.flags.recognized[pdata.flagSource[name].name]
} else {
return pdata.flagSource[name].value
@@ -478,12 +478,12 @@ export default class Command extends Base {
data: {
enumerable: true,
get () {
- let uf = parser.unrecognizedFlags
- let result = Object.assign({}, recognized)
+ const uf = parser.unrecognizedFlags
+ const result = Object.assign({}, recognized)
delete result.help
-
+
args.forEach((name, i) => {
- let value = uf[i]
+ const value = uf[i]
let normalizedValue = Object.keys(pdata).filter(key => key.toLowerCase() === value)
normalizedValue = (normalizedValue.length > 0 ? normalizedValue.pop() : value)
@@ -495,8 +495,8 @@ export default class Command extends Base {
}
}
- if (result.hasOwnProperty(name)) {
- result[name] = Array.isArray(result[name]) ? result[name]: [result[name]]
+ if (result.hasOwnProperty(name)) { // eslint-disable-line no-prototype-builtins
+ result[name] = Array.isArray(result[name]) ? result[name] : [result[name]]
result[name].push(normalizedValue)
} else {
result[name] = normalizedValue
@@ -507,8 +507,8 @@ export default class Command extends Base {
uf.slice(args.length)
.forEach((flag, i) => {
let name = `unknown${i + 1}`
- while (result.hasOwnProperty(name)) {
- let number = name.substring(7)
+ while (result.hasOwnProperty(name)) { // eslint-disable-line no-prototype-builtins
+ const number = name.substring(7)
name = 'unknown' + (parseInt(number) + 1)
}
@@ -530,7 +530,7 @@ export default class Command extends Base {
}
async run (input, callback) {
- let fn = (this.#fn || this.defaultHandler).bind(this)
+ const fn = (this.#fn || this.defaultHandler).bind(this)
const data = typeof input === 'string' ? this.parse(input) : input
arguments[0] = this.deepParse(input)
@@ -538,17 +538,17 @@ export default class Command extends Base {
if (this.shell !== null) {
const parentMiddleware = this.shell.getCommandMiddleware(this.commandroot.replace(new RegExp(`^${this.shell.name}`, 'i'), '').trim())
-
+
if (parentMiddleware.length > 0) {
this.middleware.use(...parentMiddleware)
}
}
- let trailers = this.trailers
+ const trailers = this.trailers
if (arguments[0].help && arguments[0].help.requested) {
console.log(this.help)
-
+
if (trailers.size > 0) {
trailers.run(arguments[0])
}
@@ -559,7 +559,7 @@ export default class Command extends Base {
// No subcommand was recognized
if (this.middleware.size > 0) {
this.middleware.run(arguments[0], async meta => await Command.reply(fn(meta, callback)))
-
+
if (trailers.size > 0) {
trailers.run(arguments[0])
}
@@ -590,7 +590,7 @@ export default class Command extends Base {
if (typeof callback === 'function') {
callback()
}
-
+
resolve()
} catch (e) {
reject(e)
diff --git a/src/format.js b/src/format.js
index 51fb417..8a1a486 100644
--- a/src/format.js
+++ b/src/format.js
@@ -1,4 +1,4 @@
-import Table from '../node_modules/@author.io/table/src/index.js'
+import Table from '@author.io/table'
import Command from './command.js'
import Shell from './shell.js'
@@ -26,11 +26,11 @@ class Formatter {
get usage () {
const desc = this.#data.description.trim()
-
+
if (this.#data instanceof Command) {
const aliases = this.#data.aliases
const out = [`${this.#data.commandroot}${aliases.length > 0 ? '|' + aliases.join('|') : ''}${this.#data.__flagConfig.size > 0 ? ' [FLAGS]' : ''}${this.#data.arguments.size > 0 ? ' ' + Array.from(this.#data.arguments).map(i => '<' + i + '>').join(' ') : ''}`]
-
+
if (this.#data.__processors.size > 0) {
out[out.length - 1] += (this.#data.arguments.size > 0 || this.#data.__flagConfig.size > 0 ? ' |' : '') + ' [COMMAND]'
}
@@ -49,15 +49,15 @@ class Formatter {
get subcommands () {
const rows = Array.from(this.#data.__processors.values()).map(cmd => {
- let nm = [cmd.name].concat(cmd.aliases)
+ const nm = [cmd.name].concat(cmd.aliases)
return [nm.join('|'), cmd.description]
})
- let result = []
+ const result = []
if (rows.length > 0) {
const table = new Table(rows, this.#colAlign, ['25%', '75%'], this.#tableWidth, [2])
- result.push(`\nCommands:\n`)
+ result.push('\nCommands:\n')
result.push(table.output)
}
@@ -66,42 +66,42 @@ class Formatter {
get help () {
const usage = this.usage.trim()
-
+
if (this.#data instanceof Command) {
const flags = this.#data.__flagConfig
const rows = []
if (flags.size > 0) {
flags.forEach((cfg, flag) => {
- let aliases = Array.from(cfg.aliases||cfg.alias||[])
+ let aliases = Array.from(cfg.aliases || cfg.alias || [])
aliases = aliases.length === 0 ? '' : '[' + aliases.map(a => `-${a}`).join(', ') + ']'
-
+
let dsc = [cfg.description || '']
- if (cfg.hasOwnProperty('options') && this.#data.describeOptions) {
+ if (cfg.hasOwnProperty('options') && this.#data.describeOptions) { // eslint-disable-line no-prototype-builtins
dsc.push(`Options: ${cfg.options.join(', ')}.`)
}
-
- if (cfg.hasOwnProperty('allowMultipleValues') && cfg.allowMultipleValues === true && this.#data.describeMultipleValues) {
+
+ if (cfg.hasOwnProperty('allowMultipleValues') && cfg.allowMultipleValues === true && this.#data.describeMultipleValues) { // eslint-disable-line no-prototype-builtins
dsc.push('Can be used multiple times.')
}
- if (cfg.hasOwnProperty('default') && this.#data.describeDefault) {
+ if (cfg.hasOwnProperty('default') && this.#data.describeDefault) { // eslint-disable-line no-prototype-builtins
dsc.push(`(Default: ${cfg.default.toString()})`)
}
- if (cfg.hasOwnProperty('required') && cfg.required === true && this.#data.describeRequired) {
+ if (cfg.hasOwnProperty('required') && cfg.required === true && this.#data.describeRequired) { // eslint-disable-line no-prototype-builtins
dsc.unshift('Required.')
}
dsc = dsc.join(' ').trim()
-
+
rows.push(['--' + flag, aliases || '', dsc || ''])
})
}
const table = new Table(rows, this.#colAlign, this.#colWidth, this.#tableWidth, [2, 0, usage.length > 0 ? 1 : 0, 0])
-
+
let subcommands = '\n' + this.subcommands
if (subcommands.trim().length === 0) {
subcommands = ''
@@ -115,4 +115,4 @@ class Formatter {
}
}
-export { Formatter as default, Formatter, Table }
\ No newline at end of file
+export { Formatter as default, Formatter, Table }
diff --git a/src/middleware.js b/src/middleware.js
index 6519ecf..934eaf1 100644
--- a/src/middleware.js
+++ b/src/middleware.js
@@ -17,7 +17,7 @@ export default class Middleware {
}
this.go = (stack => (...args) => {
- let next = args.pop()
+ const next = args.pop()
stack(...args, () => {
method.apply(this, [...args, next.bind(null, ...args)])
})
diff --git a/src/shell.js b/src/shell.js
index 3bbbb5b..edca10a 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -1,6 +1,5 @@
import Command from './command.js'
import Base from './base.js'
-import { Parser } from '../node_modules/@author.io/arg/index.js'
import { COMMAND_PATTERN } from './utility.js'
export default class Shell extends Base {
@@ -10,16 +9,16 @@ export default class Shell extends Base {
#version
#cursor = 0
#tabWidth
- #runtime = globalThis.hasOwnProperty('window')
+ #runtime = globalThis.hasOwnProperty('window') // eslint-disable-line no-prototype-builtins
? 'browser'
: (
- globalThis.hasOwnProperty('process')
- && globalThis.process.release
- && globalThis.process.release.name
- ? globalThis.process.release.name
- : 'unknown'
- )
-
+ globalThis.hasOwnProperty('process') && // eslint-disable-line no-prototype-builtins
+ globalThis.process.release &&
+ globalThis.process.release.name
+ ? globalThis.process.release.name
+ : 'unknown'
+ )
+
constructor (cfg = { maxhistory: 100 }) {
super(cfg)
@@ -27,17 +26,17 @@ export default class Shell extends Base {
this.__commonflags = cfg.commonflags || {}
- if (cfg.hasOwnProperty('use') && Array.isArray(cfg.use)) {
+ if (cfg.hasOwnProperty('use') && Array.isArray(cfg.use)) { // eslint-disable-line no-prototype-builtins
cfg.use.forEach(code => this.initializeMiddleware(code))
}
- if (cfg.hasOwnProperty('trailer') && Array.isArray(cfg.trailer)) {
+ if (cfg.hasOwnProperty('trailer') && Array.isArray(cfg.trailer)) { // eslint-disable-line no-prototype-builtins
cfg.trailer.forEach(code => this.initializeTrailer(code))
}
this.#version = cfg.version || '1.0.0'
this.#maxHistoryItems = cfg.maxhistory || cfg.maxHistoryItems || 100
- this.#tabWidth = cfg.hasOwnProperty('tabWidth') ? cfg.tabWidth : 4
+ this.#tabWidth = cfg.hasOwnProperty('tabWidth') ? cfg.tabWidth : 4 // eslint-disable-line no-prototype-builtins
// This sets a global symbol that dev tools can find.
globalThis[Symbol('SHELL_INTEGRATIONS')] = this
@@ -66,7 +65,7 @@ export default class Shell extends Base {
return this.#version || 'Unknown'
}
- set tableWidth(value) {
+ set tableWidth (value) {
this.__width = value
}
@@ -86,9 +85,9 @@ export default class Shell extends Base {
if (this.#history.length === 0) {
return null
}
-
+
if (count < 0) {
- return this.nextCommand(abs(count))
+ return this.nextCommand(Math.abs(count))
}
count = count % this.#history.length
@@ -106,9 +105,9 @@ export default class Shell extends Base {
if (this.#history.length === 0) {
return null
}
-
+
if (count < 0) {
- return this.priorCommand(abs(count))
+ return this.priorCommand(Math.abs(count))
}
count = count % this.#history.length
@@ -151,7 +150,7 @@ export default class Shell extends Base {
const fns = Array.from(arguments).slice(1)
const all = new Set(this.commandlist.map(i => i.toLowerCase()))
-
+
commands.forEach(cmd => {
all.delete(cmd)
for (const c of all) {
@@ -171,7 +170,7 @@ export default class Shell extends Base {
input = input.join(' ')
}
- this.#history.unshift({ input, time: new Date().toLocaleString()})
+ this.#history.unshift({ input, time: new Date().toLocaleString() })
if (this.#history.length > this.#maxHistoryItems) {
this.#history.pop()
@@ -185,15 +184,15 @@ export default class Shell extends Base {
} else if (input.indexOf('help') !== -1) {
return console.log(this.help)
}
-
+
return Command.stderr(this.help)
}
parsed = parsed.filter(item => item !== undefined)
- let cmd = parsed[1]
- let args = parsed.length > 2 ? parsed[2] : ''
- let command = null
+ const cmd = parsed[1]
+ const args = parsed.length > 2 ? parsed[2] : ''
+ // const command = null
const action = this.__commands.get(cmd)
@@ -205,7 +204,7 @@ export default class Shell extends Base {
return Command.stderr(this.help)
}
- let processor = this.__processors.get(action)
+ const processor = this.__processors.get(action)
if (!processor) {
return Command.stderr('Command not found.')
@@ -216,9 +215,9 @@ export default class Shell extends Base {
}
getCommandMiddleware (cmd) {
- let results = []
+ const results = []
cmd.split(/\s+/).forEach((c, i, a) => {
- let r = this.#middlewareGroups.get(a.slice(0, i + 1).join(' '))
+ const r = this.#middlewareGroups.get(a.slice(0, i + 1).join(' '))
r && results.push(r.flat(Infinity))
})
diff --git a/src/utility.js b/src/utility.js
index e84de40..83fea4e 100644
--- a/src/utility.js
+++ b/src/utility.js
@@ -1,10 +1,10 @@
// const STRIP_EQUAL_SIGNS = /(\=+)(?=([^'"\\]*(\\.|['"]([^'"\\]*\\.)*[^'"\\]*['"]))*[^'"]*$)/g
-const SUBCOMMAND_PATTERN = /^([^"'][\S\b]+)[\s+]?([^-].*)$/i
-const FLAG_PATTERN = /((?:"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|\/[^\/\\]*(?:\\[\S\s][^\/\\]*)*\/[gimy]*(?=\s|$)|(?:\\\s|\S))+)(?=\s|$)/g
-const METHOD_PATTERN = /^([\w]+\s?)\(.*\)\s?{/i
-const STRIP_QUOTE_PATTERN = /"([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'/ig
-const COMMAND_PATTERN = /^(\w+)\s+([\s\S]+)?/i
+const SUBCOMMAND_PATTERN = /^([^"'][\S\b]+)[\s+]?([^-].*)$/i // eslint-disable-line no-useless-escape
+const FLAG_PATTERN = /((?:"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|\/[^\/\\]*(?:\\[\S\s][^\/\\]*)*\/[gimy]*(?=\s|$)|(?:\\\s|\S))+)(?=\s|$)/g // eslint-disable-line no-useless-escape
+const METHOD_PATTERN = /^([\w]+\s?)\(.*\)\s?{/i // eslint-disable-line no-useless-escape
+const STRIP_QUOTE_PATTERN = /"([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'/ig // eslint-disable-line no-useless-escape
+const COMMAND_PATTERN = /^(\w+)\s+([\s\S]+)?/i // eslint-disable-line no-useless-escape
const CONSTANTS = Object.freeze({
SUBCOMMAND_PATTERN,
FLAG_PATTERN,
diff --git a/test/.eslintrc b/test/.eslintrc
deleted file mode 100644
index 0410f26..0000000
--- a/test/.eslintrc
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "extends": [
- "plugin:compat/recommended"
- ],
- "env": {
- "browser": true,
- "es6": true
- },
- "parserOptions": {
- "sourceType": "module",
- "ecmaVersion": 2019
- }
-}
diff --git a/test/assets/index.html b/test/assets/index.html
deleted file mode 100644
index 76a4be3..0000000
--- a/test/assets/index.html
+++ /dev/null
@@ -1,358 +0,0 @@
-
-
- {{NAMESPACE}} Manual Testing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/package.json b/test/package.json
deleted file mode 100644
index 0fbd273..0000000
--- a/test/package.json
+++ /dev/null
@@ -1,86 +0,0 @@
-{
- "name": "test",
- "version": "1.0.0",
- "description": "Test Suite",
- "main": "index.js",
- "scripts": {
- "start": "npm test",
- "test": "npm run node && npm run browser",
- "node": "npm run build:test:node && tap --no-esm --no-coverage -r source-map-support/register -R spec ./unit/*-*/**/*-*.js",
- "browser": "npm run build:test:browser && node ./unit/prepareKarmaBrowserSuite.js && karma start ./unit/karma.conf.cjs",
- "build:test:node": "cd ../build && npm run test:node && cd ../test",
- "build:test:browser": "cd ../build && npm run test:browser && cd ../test",
- "browser:manual": "npm run clean && npm run build:test:browser && node ./unit/prepareKarmaBrowserSuite.js && node ./unit/prepareManualTestEnvironment.js && cd .testsuite",
- "browser:manual:open": "npm run browser:manual && cd .testsuite && fenix open",
- "clean": "node ../build/lib/reset.js",
- "syntax": "./syntax/validator.js --source ../src/**/*.js --config ./package.json --parser babel-eslint --verbose | snazzy",
- "compat": "echo 'Building...' && cd ../build && npm run browser && echo 'Testing modern browser compatibility...' && cd ../test && BROWSERSLIST_ENV=current BROWSERSLIST_CONFIG=../build/.browserslistrc eslint -c ./.eslintrc ../.dist/browser/browser-*/*.min.js --no-ignore && echo Done."
- },
- "author": "",
- "type": "module",
- "engines": {
- "node": ">=13.5.0"
- },
- "dependencies": {
- "@author.io/arg": "^1.1.0",
- "@babel/core": "^7.7.5",
- "@babel/preset-env": "^7.7.7",
- "@rollup/plugin-multi-entry": "^3.0.0",
- "babel-eslint": "^10.0.3",
- "browserify": "^16.5.0",
- "diff": "^4.0.2",
- "eslint": "^6.8.0",
- "eslint-plugin-compat": "^3.3.0",
- "karma": "^4.4.1",
- "karma-babel-preprocessor": "^8.0.1",
- "karma-browserify": "^6.1.0",
- "karma-chrome-launcher": "^3.1.0",
- "karma-edgium-launcher": "^4.0.0-0",
- "karma-firefox-launcher": "^1.2.0",
- "karma-ie-launcher": "^1.0.0",
- "karma-safari-launcher": "^1.0.0",
- "karma-sauce-launcher": "^2.0.2",
- "karma-source-map-support": "^1.4.0",
- "karma-sourcemap-loader": "^0.3.7",
- "karma-spec-reporter": "0.0.32",
- "karma-tap": "^4.1.4",
- "karma-tap-pretty-reporter": "^4.1.0",
- "magic-string": "^0.25.6",
- "snazzy": "^8.0.0",
- "source-map-support": "^0.5.16",
- "standard": "14.3.1",
- "tap": "14.10.5",
- "tap-spec": "^5.0.0",
- "tape": "4.12.0"
- },
- "standard": {
- "parser": "babel-eslint",
- "ignore": [
- "_*",
- "_**/*",
- ".**/*",
- "node_modules",
- "karma.conf.js",
- "karma.conf.cjs",
- "build.js"
- ],
- "globals": [
- "window",
- "global",
- "MutationObserver",
- "DOMParser",
- "XMLHttpRequest",
- "FormData",
- "btoa",
- "localStorage",
- "Request",
- "Response",
- "Headers",
- "fetch",
- "Element",
- "HTMLElement",
- "NodeFilter"
- ]
- },
- "nyc": {}
-}
diff --git a/test/syntax/validator.js b/test/syntax/validator.js
deleted file mode 100755
index ee8d642..0000000
--- a/test/syntax/validator.js
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/usr/bin/env node --experimental-modules
-import fs from 'fs'
-import path from 'path'
-import Args from '@author.io/arg'
-import standard from 'standard'
-
-// Configure argument parser
-Args.configure({
- source: {
- default: path.join(process.cwd(), '../unit/**/*.js')
- },
- config: {
- default: path.join(process.cwd(), '../package.json')
- },
- parser: {
- default: ''
- },
- verbose: {
- default: false
- }
-})
-
-Args.enforceRules()
-
-// Normalize the source path and identify which linter to use
-let scanpath = Args.value('source')
-let scanFile = false
-
-if (scanpath.indexOf('*') === -1) {
- const stat = fs.statSync(scanpath)
- if (stat.isDirectory()) {
- scanpath = path.join(scanpath, '../unit/**/*.js')
- } else if (!stat.isFile) {
- throw new Error(`Cannot find or process "${scanpath}"`)
- } else {
- scanFile = true
- }
-}
-
-const pkg = JSON.parse(fs.readFileSync(Args.value('config')).toString())
-const opts = {
- cwd: path.resolve(Args.value('source')),
- ignore: (pkg.standard ? pkg.standard.ignore : []) || [], // file globs to ignore (has sane defaults)
- globals: (pkg.standard ? pkg.standard.globals : []) || [], // global variables to declare
- // plugins: (pkg.standard ? pkg.standard.plugins : []) || [], // eslint plugins
- parser: Args.value('parser')
-}
-
-// Custom standardjs output
-const output = (err, result) => {
- if (err) {
- process.stderr.write(err)
- }
-
- if (result) {
- if (!result.errorCount && !result.warningCount) {
- process.exitCode = 0
- return
- }
-
- // Are any fixable rules present?
- var isFixable = result.results.some(function (result) {
- return result.messages.some(function (message) {
- return !!message.fix
- })
- })
-
- if (isFixable) {
- console.error(
- '%s: %s',
- opts.cmd,
- 'Run `' + opts.cmd + ' --fix` to automatically fix some problems.'
- )
- }
-
- result.results.forEach(function (result) {
- result.messages.forEach(function (message) {
- console.log(
- ' %s:%d:%d: %s%s',
- result.filePath, message.line || 0, message.column || 0, message.message,
- Args.value('verbose') ? ' (' + message.ruleId + ')' : ''
- )
- })
- })
-
- process.exitCode = result.errorCount ? 1 : 0
- }
-}
-
-if (scanFile) {
- standard.lintText(fs.readFileSync(scanpath).toString(), opts, output)
-} else {
- standard.lintFiles(scanpath, opts, output)
-}
diff --git a/test/unit/karma.conf.cjs b/test/unit/karma.conf.cjs
deleted file mode 100644
index 1e884df..0000000
--- a/test/unit/karma.conf.cjs
+++ /dev/null
@@ -1,189 +0,0 @@
-// Karma configuration
-const fs = require('fs')
-const config = JSON.parse(fs.readFileSync('../build/config.json'))
-const pkg = JSON.parse(fs.readFileSync('../package.json'))
-const BrowsersList = require('../../build/node_modules/browserslist')
-// const babelify = require('babelify')
-
-let local = !process.env.hasOwnProperty('CI')
-if (process.env.hasOwnProperty('LOCAL')) {
- if (process.env.LOCAL.trim().toLowerCase() === 'false') {
- local = false
- }
-}
-
-if (process.env.hasOwnProperty('SAUCE_USERNAME') && process.env.hasOwnProperty('SAUCE_ACCESS_KEY')) {
- local = false
-}
-
-const browsers = {}
-if (!local) {
- const opts = {}
- if (process.env.BROWSERSLIST_CONFIG) {
- opts.path = process.env.BROWSERSLIST_CONFIG
- }
-
- if (process.env.BROWSERSLIST_ENV) {
- opts.env = process.env.BROWSERSLIST_ENV
- }
-
- BrowsersList(null, opts)
- .forEach(item => {
- if (item.indexOf('-')) {
- let browser = item.split('-').shift().split(' ')
- const version = /([0-9]+\.?([0-9]+)?)/.exec(browser[1])
-
- if (version && browser[0].trim().toLowerCase() !== 'samsung') {
- const label = `sl_${browser[0]}_${browser[1]}`.toLowerCase()
- browsers[label] = {
- base: 'SauceLabs',
- browserName: browser[0],
- version: version[1]
- }
-
- if (browser[0].indexOf('_') > 0) {
- browser = browser[0].split('_')
- switch (browser[0].trim().toLowerCase()) {
- case 'ios':
- browsers[label].platformName = 'iOS'
- break
-
- case 'and':
- case 'android':
- browsers[label].platformName = 'Android'
- break
- }
- browser[0] = browser[1]
- }
-
- switch (browser[0].toLowerCase()) {
- case 'edge':
- browsers[label].browserName = 'MicrosoftEdge'
- if (browser[1] === '17') {
- browsers[label].version = '17.17134'
- }
- break
- case 'saf':
- browsers[label].browserName = 'Safari'
- break
- case 'chr':
- browsers[label].browserName = 'Chrome'
- break
- case 'uc':
- // Unsupported in SauceLabs
- delete browsers[label]
- }
-
- if (browsers[label] && !browsers[label].platformName) {
- browsers[label].platformName = 'macOS 10.14'
- }
- }
- }
- })
-}
-
-// console.log(browsers)
-// process.exit(0)
-
-for (const browser in browsers) {
- console.log(`Queued tests for ${browsers[browser].browserName} ${browsers[browser].version} on ${browsers[browser].platformName || 'default OS'}.`)
-}
-
-if (!local) {
- console.log('Testing remotely.')
-}
-
-module.exports = function (config) {
- config.set({
- browserDisconnectTimeout: 30000,
- browserDisconnectTolerance: 3,
- browserNoActivityTimeout: 60000,
- processKillTimeout: 30000,
-
- // base path that will be used to resolve all patterns (eg. files, exclude)
- basePath: '',
-
- // frameworks to use
- // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
- frameworks: ['browserify', 'source-map-support', 'tap'],
-
- browserify: {
- debug: true
- // transform: babelify.configure({
- // presets: ['@babel/preset-env']
- // })
- },
-
- // list of files / patterns to load in the browser
- files: [
- { pattern: '../.browser/*.js', included: true, served: true, type: 'module' },
- { pattern: '../.browser/*.js.map', included: false, served: true, type: 'js' },
- '../.testsuite/browser-test.js'
- // { pattern: '.testsuite/*.js', included: true, nocache: true }
- ],
-
- // list of files to exclude
- exclude: [
- '../.browser/*-global.*',
- '../.browser/*-es*.*'
- ],
-
- // preprocess matching files before serving them to the browser
- // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
- preprocessors: {
- '../.browser/*.min.js': ['sourcemap'],
- '../.testsuite/browser-test.js': ['browserify']
- },
-
- // test results reporter to use
- // possible values: 'dots', 'progress'
- // available reporters: https://npmjs.org/browse/keyword/karma-reporter
- reporters: ['tap-pretty', 'saucelabs'],
-
- tapReporter: {
- prettify: require('tap-spec'), // default 'standard TAP' output
- separator: '****************************'
- },
- // specReporter: {
- // maxLogLines: 15, // limit number of lines logged per test
- // suppressErrorSummary: false, // do not print error summary
- // suppressFailed: false, // do not print information about failed tests
- // suppressPassed: false, // do not print information about passed tests
- // suppressSkipped: true, // do not print information about skipped tests
- // showSpecTiming: false, // print the time elapsed for each spec
- // failFast: true
- // },
-
- // web server port
- port: 9876,
-
- // enable / disable colors in the output (reporters and logs)
- colors: true,
-
- // level of logging
- // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
- logLevel: config.LOG_ERROR,
-
- // enable / disable watching file and executing tests whenever any file changes
- // autoWatch: true,
-
- // start these browsers
- // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
- browsers: local ? ['Chrome'] : Object.keys(browsers),
- customLaunchers: local ? null : browsers,
-
- sauceLabs: {
- testName: pkg.name
- },
-
- // Continuous Integration mode
- // if true, Karma captures browsers, runs the tests and exits
- singleRun: true,
- // autoWatch: true,
-
- // Concurrency level
- // how many browser should be started simultanous
- concurrency: 1
- // concurrency: Infinity
- })
-}
diff --git a/test/unit/prepareKarmaBrowserSuite.js b/test/unit/prepareKarmaBrowserSuite.js
deleted file mode 100644
index a245ed6..0000000
--- a/test/unit/prepareKarmaBrowserSuite.js
+++ /dev/null
@@ -1,89 +0,0 @@
-import fs from 'fs'
-import path from 'path'
-// Rollup is used from the build package instead of requiring 2 copies of rollup to be installed in node_modules.
-import multi from '../../build/node_modules/@rollup/plugin-multi-entry/dist/index.js'
-import rollup from '../../build/node_modules/rollup/dist/rollup.js'
-import MagicString from 'magic-string'
-import diff from 'diff'
-
-const config = JSON.parse(fs.readFileSync('../build/config.json'))
-const pkg = JSON.parse(fs.readFileSync('../package.json'))
-const testpkg = JSON.parse(fs.readFileSync('./package.json'))
-const file = path.resolve(path.join(config.testOutput, '.testsuite', 'browser-test.js'))
-
-fs.rmdirSync(path.dirname(file), { recursive: true })
-fs.mkdirSync(path.dirname(file))
-
-const outputOptions = {
- file,
- format: 'cjs'
-}
-
-const external = config.external
-external.push('.node/index.js')
-external.push('./.node/index.js')
-external.push('../.node/index.js')
-external.push('../../.node/index.js')
-external.push('tape')
-
-const matcher = /import\s+(?:.*as\s+)?(\{.*\}|[\S]+)\s.*from\s+['"].*\/\.node\/index\.js['"]/
-const tests = new Set(process.argv.filter((val, i, args) => i > 0 && /-+test/i.test(args[i - 1])).map(i => i.toLowerCase()))
-const input = tests.size === 0 ? ['./unit/0*-*/*-*.js'] : Array.from(tests)
-
-export default function importExtractor() {
- return {
- name: 'import-extractor', // this name will show up in warnings and errors
- load (id) {
- if (fs.existsSync(id)) {
- console.log(`Including ${id}`)
- const input = fs.readFileSync(id).toString()
- const ms = new MagicString(input)
- const output = input
- .replace(/(import\s+.*\s+['"].*\/)\.node\/index\.js(['"])/gi, `$1.browser/${pkg.name.split('/').pop()}-${pkg.version}.min.js$2`)
- .replace(/import\s+['"]source-map-support\/register.*/gi, '') // Not supported by browserify
-
- const changes = diff.diffChars(input, output)
- if (changes && changes.length > 0) {
- let idx = 0
-
- changes.forEach(part => {
- if (part.added) {
- ms.prependLeft(idx, part.value)
- idx -= part.count
- } else if (part.removed) {
- ms.remove(idx, idx + part.count)
- }
-
- idx += part.count
- })
- }
-
- return { code: output, map: ms.generateMap({ hires: true })}
- }
- return null
- }
- // , buildEnd () {}
- };
-}
-
-async function build () {
- const bundle = await rollup.rollup({
- input,
- external,
- plugins: [
- importExtractor(),
- multi(),
- ]
- })
-
- // const { output } = await bundle.generate(outputOptions)
-
- await bundle.write(outputOptions)
-
- // The setTimeout is used to force Karma to wait for the code to be loaded by the prep script.
- // const content = fs.readFileSync(file).toString()
- // fs.writeFileSync(file, `setTimeout(function () {\n${content}\n}, 600)`)
- // console.log(`Wrote "${file}" to disk.`)
-}
-
-build()
diff --git a/test/unit/prepareManualTestEnvironment.js b/test/unit/prepareManualTestEnvironment.js
deleted file mode 100644
index 46344aa..0000000
--- a/test/unit/prepareManualTestEnvironment.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import path from 'path'
-import fs from 'fs'
-import Build from '../../build/lib/build.js'
-import browserify from 'browserify'
-import { execSync } from 'child_process'
-
-const build = new Build()
-const pkg = JSON.parse(fs.readFileSync('../package.json').toString())
-const name = pkg.name.split('/').pop()
-const sources = fs.readdirSync(path.resolve('./.browser')).filter(i => path.extname(i).split('.').pop() === 'js')
-const options = sources.map(src => ``)
-options.sort((a, b) => {
- if (a.replace(/[^\S0-9]/gi, '') > b.replace(/[^\S0-9]/gi, '')) {
- return -1
- } else {
- return 1
- }
-})
-
-if (pkg.main) {
- options.push(``)
-}
-
-const content = fs.readFileSync('./assets/index.html')
- .toString()
- .replace(/\{\{script\}\}/g, `./${name}.min.js`)
- .replace(/\{\{NAMESPACE\}\}/g, name)
- .replace(/\{\{OPTIONS\}\}/gi, options.join('\n '))
-
-if (!fs.existsSync(path.resolve('./.testsuite'))) {
- fs.mkdirSync(path.resolve('./.testsuite'), { recursive: true })
-}
-
-fs.writeFileSync('./.testsuite/index.html', content)
-sources.forEach(jsfile => {
- fs.copyFileSync(`./.browser/${jsfile}`, `./.testsuite/${jsfile}`)
- fs.copyFileSync(`./.browser/${jsfile}.map`, `./.testsuite/${jsfile}.map`)
-})
-
-const cwd = process.cwd()
-const out = path.join(process.cwd(), '.testsuite')
-build.walk('../src').forEach(file => {
- const input = path.resolve(file)
- const output = path.dirname(input).replace(path.join(cwd, '..'), out)
- if (fs.statSync(input).isFile() && !fs.existsSync(output)) {
- fs.mkdirSync(output)
- }
-
- const content = fs.readFileSync(input)
- .toString()
- .replace(/([\t ]*\/\* ?node-only ?\*\/)[\s\S]*?(\/\* ?end-node-only ?\*\/[\t ]*\n?)/gim, '')
- // .replace(/<#(\s+)?REPLACE_VERSION(\s+)?#>/gi, pkg.version)
-
- fs.writeFileSync(input.replace(path.join(cwd, '..'), out), content)
-})
-
-// Add the libraries from the test suite
-if (fs.existsSync(path.resolve('./.testsuite/browser-test.js'))) {
- const content = fs.readFileSync('./.testsuite/browser-test.js').toString()
- const importStatements = content.match(/_interop[\S]+\(require\(['"]([\S]+)['"]/g)
- const names = new Set()
- importStatements.forEach(i => i.match(/_interop[\S]+\(require\(['"]([\S]+)['"]/).slice(1).forEach(name => names.add(name)))
-
- if (names.size > 0) {
- // TODO: Use the browserify API to bundle
- // const bundle = fs.createWriteStream(path.resolve('./.testsuite/bundle.js'))
- const cmd = `./node_modules/browserify/bin/cmd.js -r ${Array.from(names).join('-r ')} > "${path.resolve('./.testsuite/bundle.js')}"`
- execSync(cmd, { stdio: 'inherit' })
- // console.log(bundle)
- // browserify(Array.from(names)).bundle().on('data', chunk => bundle.write(chunk)).on('end', () => console.log('done'))
- console.log(`Generated browser references for: ${Array.from(names).join(', ')}.`)
- }
-}
diff --git a/test/unit/01-sanity/01-sanity.js b/tests/01-sanity.js
similarity index 83%
rename from test/unit/01-sanity/01-sanity.js
rename to tests/01-sanity.js
index 2627581..000506e 100644
--- a/test/unit/01-sanity/01-sanity.js
+++ b/tests/01-sanity.js
@@ -1,8 +1,6 @@
-import 'source-map-support/register.js'
-import test from 'tape'
-import { Command, Shell, Formatter } from '../../.node/index.js'
+import test from 'tappedout'
+import { Command, Shell, Formatter } from '@author.io/shell'
// import fs from 'fs'
-// import path from 'path'
test('Sanity Check - Shell', t => {
const shell = new Shell({
@@ -80,19 +78,35 @@ test('Output Formatting', t => {
formatter.width = 80
t.ok(formatter instanceof Formatter, 'Basic formatter instantiates correctly.')
- // fs.writeFileSync('./test.txt', Buffer.from(formatter.help))
- // console.log(formatter.help)
- t.ok(formatter.help === `test cmd|c [FLAGS]
+// fs.writeFileSync('./test.txt', Buffer.from(formatter.help))
+// console.log(formatter.help)
+// t.expect(`test cmd|c [FLAGS]
+
+// Flags:
+
+// --test [-t] test description
+// --more [-m, -mr] This is a longer description that should break onto
+// more than one line, or perhaps even more than one
+// extra line with especially poor grammar and
+// spellling.
+// --none Ignore me. I do not exist. `,
+// formatter.help,
+// 'Correctly generated default help message.')
+
+ t.expect(`test cmd|c [FLAGS]
Flags:
- --test [-t] test description
+ --test [-t] test description
--more [-m, -mr] This is a longer description that should break onto
- more than one line, or perhaps even more than one
- extra line with especially poor grammar and
- spellling.
- --none Ignore me. I do not exist. `, 'Correctly generated default help message.')
- t.end()
+ more than one line, or perhaps even more than one
+ extra line with especially poor grammar and
+ spellling.
+ --none Ignore me. I do not exist. `.replace(/\s+|\t+|\n+/gi, ''),
+ formatter.help.replace(/\s+|\t+|\n+/gi, ''),
+ 'Correctly generated default help message.')
+
+ t.end()
})
test('Subcommand Config', t => {
diff --git a/test/unit/01-sanity/02-middleware.js b/tests/02-middleware.js
similarity index 97%
rename from test/unit/01-sanity/02-middleware.js
rename to tests/02-middleware.js
index 79e1e3f..de92309 100644
--- a/test/unit/01-sanity/02-middleware.js
+++ b/tests/02-middleware.js
@@ -1,6 +1,5 @@
-import 'source-map-support/register.js'
-import test from 'tape'
-import { Shell, Middleware } from '../../.node/index.js'
+import test from 'tappedout'
+import { Shell, Middleware } from '@author.io/shell'
test('Sync Middleware', t => {
const mw = new Middleware()
@@ -137,7 +136,7 @@ test('Command Specific Middleware Exceptions', async t => {
handler () { }
}, {
name: 'd',
- handler () {
+ handler () {
ok = true
}
}]
diff --git a/test/unit/01-sanity/03-help-defaults.js b/tests/03-help-defaults.js
similarity index 95%
rename from test/unit/01-sanity/03-help-defaults.js
rename to tests/03-help-defaults.js
index 0480f11..e5ab4e9 100644
--- a/test/unit/01-sanity/03-help-defaults.js
+++ b/tests/03-help-defaults.js
@@ -1,6 +1,6 @@
-import 'source-map-support/register.js'
-import test from 'tape'
-import { Shell, Middleware } from '../../.node/index.js'
+import test from 'tappedout'
+import { Shell, Middleware } from '@author.io/shell'
+
// import fs from 'fs'
let msg = ''
diff --git a/test/unit/01-sanity/04-metadata.js b/tests/04-metadata.js
similarity index 98%
rename from test/unit/01-sanity/04-metadata.js
rename to tests/04-metadata.js
index 50daf2e..5a8f3c4 100644
--- a/test/unit/01-sanity/04-metadata.js
+++ b/tests/04-metadata.js
@@ -1,6 +1,5 @@
-import 'source-map-support/register.js'
-import test from 'tape'
-import { Shell } from '../../.node/index.js'
+import test from 'tappedout'
+import { Shell } from '@author.io/shell'
test('Map unnamed argument', t => {
const shell = new Shell({
diff --git a/test/unit/01-sanity/05-commonflags.js b/tests/05-commonflags.js
similarity index 96%
rename from test/unit/01-sanity/05-commonflags.js
rename to tests/05-commonflags.js
index 772156b..6d199bb 100644
--- a/test/unit/01-sanity/05-commonflags.js
+++ b/tests/05-commonflags.js
@@ -1,6 +1,5 @@
-import 'source-map-support/register.js'
-import test from 'tape'
-import { Shell } from '../../.node/index.js'
+import test from 'tappedout'
+import { Shell } from '@author.io/shell'
test('Common flags (entire shell)', t => {
const shell = new Shell({
@@ -117,7 +116,7 @@ test('Common flags (exclusions)', async t => {
},
commands: [{
name: 'sub',
- handler (meta) {
+ handler (meta) {
t.ok(!meta.flags.recognized.hasOwnProperty('typical'), 'The common flag "typical" was successfully excluded from a sub command.')
},
commands: [{
diff --git a/test/unit/01-sanity/06-history.js b/tests/06-history.js
similarity index 90%
rename from test/unit/01-sanity/06-history.js
rename to tests/06-history.js
index d83f965..0476e91 100644
--- a/test/unit/01-sanity/06-history.js
+++ b/tests/06-history.js
@@ -1,6 +1,5 @@
-import 'source-map-support/register.js'
-import test from 'tape'
-import { Shell } from '../../.node/index.js'
+import test from 'tappedout'
+import { Shell } from '@author.io/shell'
test('Basic History', t => {
const sh = new Shell({
diff --git a/test/unit/01-sanity/07-plugins.js b/tests/07-plugins.js
similarity index 96%
rename from test/unit/01-sanity/07-plugins.js
rename to tests/07-plugins.js
index 627b560..29ed309 100644
--- a/test/unit/01-sanity/07-plugins.js
+++ b/tests/07-plugins.js
@@ -1,6 +1,6 @@
-import 'source-map-support/register.js'
-import test from 'tape'
-import { Shell } from '../../.node/index.js'
+import test from 'tappedout'
+import { Shell } from '@author.io/shell'
+
test('Basic Plugins', t => {
const sh = new Shell({
diff --git a/test/unit/01-sanity/100-regression.js b/tests/100-regression.js
similarity index 93%
rename from test/unit/01-sanity/100-regression.js
rename to tests/100-regression.js
index 917aa1f..51cc1a7 100644
--- a/test/unit/01-sanity/100-regression.js
+++ b/tests/100-regression.js
@@ -1,6 +1,5 @@
-import 'source-map-support/register.js'
-import test from 'tape'
-import { Shell } from '../../.node/index.js'
+import test from 'tappedout'
+import { Shell } from '@author.io/shell'
// The range error was caused by the underlying table library.
// When a default help message was generated, a negative column
From cc499409a139a9eeb697754ee672468dce47294c Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sun, 27 Dec 2020 15:56:08 -0600
Subject: [PATCH 099/152] Update CI/CD command
---
.github/workflows/deploy.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 6c5d912..5dabda7 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -70,7 +70,7 @@ jobs:
if: success()
run: |
dev -v
- npm run ci
+ npm run test
- name: Tag
id: autotagger
From 4a66212cf7e3ea73f177ef8140195806e7852726 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sun, 27 Dec 2020 15:58:43 -0600
Subject: [PATCH 100/152] Update CI/CD command
---
.github/workflows/deploy.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 5dabda7..04ab398 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -123,7 +123,7 @@ jobs:
with:
scan: ./dist
env:
- REGISTRY_TOKEN: ${{ secrets.NPM_REGISTRY_TOKEN }}
+ REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
- name: Rollback Release
if: failure() && steps.create_release.outputs.id != ''
From fd167c908514c119d4c35cd25cdbcb0ec2a69968 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sun, 27 Dec 2020 16:52:02 -0600
Subject: [PATCH 101/152] Add CI build process, which embeds internal libraries
insted of dynamically linking them.
---
.github/workflows/deploy.yml | 2 +-
package.json | 19 ++++++++++++++-----
2 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 04ab398..184c83f 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -70,7 +70,7 @@ jobs:
if: success()
run: |
dev -v
- npm run test
+ npm run ci
- name: Tag
id: autotagger
diff --git a/package.json b/package.json
index e83befb..5cdd63a 100644
--- a/package.json
+++ b/package.json
@@ -20,7 +20,8 @@
"report:syntax": "dev report syntax --pretty",
"report:size": "dev report size ./.dist/**/*.js ./.dist/**/*.js.map",
"report:compat": "dev report compatibility ./src/**/*.js",
- "report:preview": "npm pack --dry-run && echo \"==============================\" && echo \"This report shows what will be published to the module registry. Pay attention to the tarball contents and assure no sensitive files will be published.\""
+ "report:preview": "npm pack --dry-run && echo \"==============================\" && echo \"This report shows what will be published to the module registry. Pay attention to the tarball contents and assure no sensitive files will be published.\"",
+ "ci": "dev test --verbose --mode ci --peer -rt node tests/*.js && dev test --mode ci -rt deno tests/*.js && dev test --mode ci -rt browser tests/*.js"
},
"keywords": [
"cli",
@@ -36,15 +37,23 @@
"replace": {
"<#REPLACE_VERSION#>": "package.version"
},
+ "volume": [
+ "./node_modules/@author.io/arg:/node_modules/@author.io/arg",
+ "./node_modules/@author.io/table:/node_modules/@author.io/table"
+ ],
"alias": {
"@author.io/shell": "/app/.dist/shell/index.js",
"@author.io/arg": "/node_modules/@author.io/arg/index.js",
"@author.io/table": "/node_modules/@author.io/table/src/index.js"
},
- "volume": [
- "./node_modules/@author.io/arg:/node_modules/@author.io/arg",
- "./node_modules/@author.io/table:/node_modules/@author.io/table"
- ]
+ "ci": {
+ "verbose": true,
+ "peer": true,
+ "embed": [
+ "@author.io/arg",
+ "@author.io/table"
+ ]
+ }
},
"author": {
"name": "Corey Butler",
From b691190c645cac72943781d2fd1583f5650af659 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sun, 27 Dec 2020 16:52:14 -0600
Subject: [PATCH 102/152] Version bump
---
package-lock.json | 4 ++--
package.json | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index e049ba7..74b828b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,11 +1,11 @@
{
"name": "@author.io/shell",
- "version": "1.8.2",
+ "version": "1.8.4",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
- "version": "1.8.2",
+ "version": "1.8.4",
"license": "MIT",
"devDependencies": {
"@author.io/arg": "^1.3.8",
diff --git a/package.json b/package.json
index 5cdd63a..7234f0c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.3",
+ "version": "1.8.4",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
From bf4be49f7eeb0cc4cfa48944a36173bfdd47deb4 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 5 Jan 2021 22:21:53 -0600
Subject: [PATCH 103/152] Update README.md
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index b8e863b..1ea673b 100644
--- a/README.md
+++ b/README.md
@@ -349,6 +349,7 @@ Consider an example where information is retrieved from a remote API. To do this
+
```javascript
import axios from 'axios'
From 3a9e3ddbb03d54d1ee2be9ead19f6b8b287eca41 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 8 Feb 2021 22:12:21 -0600
Subject: [PATCH 104/152] Update README.md
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 1ea673b..31290de 100644
--- a/README.md
+++ b/README.md
@@ -54,12 +54,12 @@ Sometimes single purpose tools grow into multipurpose tools over time. Tools whi
1. Reusable **plugin** system.
1. Dynamically add/remove commands.
1. Track command execution **history**.
-1. Define **universal flags** flag once, reuse in all commands.
+1. Define **universal flags** once, reuse in all commands.
Also has better source & distribution code
-1. Cross-runtime (browser & node)
+1. Cross-runtime (browser, node, deno)
1. Separation of Concerns: Arg parsing and text formatting are separate microlibs.
1. Modern ES Module syntax
1. 40+ unit tests
From 533fdd210abdcc2febbc0bd872a3a681832a156f Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Fri, 23 Jul 2021 14:26:21 -0500
Subject: [PATCH 105/152] Cleaned up references to old runtime-specific module.
---
README.md | 57 ++++++++++++++++++++++---------------------------------
1 file changed, 23 insertions(+), 34 deletions(-)
diff --git a/README.md b/README.md
index 31290de..74f99cb 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# @author.io/shell
+# @author.io/shell

This is a super-lightweight framework for building text-based programs, like [CLI](https://en.wikipedia.org/wiki/Command-line_interface) applications.
@@ -35,7 +35,7 @@ There are two types of text-based apps:
This framework was designed to support multipurpose CLI tools. At the core, it provides a clean, easily-understood, repeatable pattern for building maintainable multipurpose CLI applications.
-Multipurpose tools require a layer of organizational overhead to help isolate different commands and features. This overhead is unnecessary in single purpose tools. Single purpose tools just need argument parsing, which the [@author.io/arg](https://github.com/author/arg) does very well.
+Multipurpose tools require a layer of organizational overhead to help isolate different commands and features. This overhead is unnecessary in single purpose tools. Single purpose tools just need argument parsing, which the [@author.io/arg](https://github.com/author/arg) does very well.
`@author.io/arg` is embedded in this framework, making `@author.io/shell` _capable_ of creating single purpose tools, but it's merely unnecessary overhead for single purpose commands.
@@ -75,7 +75,7 @@ There is a complete working example of a CLI app (with a mini tutorial) in the e
_This example imports the library for Node. Simply swap the Node import for the appropriate browser import if you're building a web utility. Everything else is the same for both Node and browser environments._
```javascript
-import { Shell, Command } from '@author.io/node-shell'
+import { Shell, Command } from '@author.io/shell'
// Define a command
const ListCommand = new Command({
@@ -103,13 +103,13 @@ const ListCommand = new Command({
},
handler (metadata, callback) {
// ... this is where your command actually does something ...
-
+
// Data comes from @author.io/arg lib. It looks like:
// {
// command: ,
// input: 'whatever user typed after "command"',
// flags: {
- // recognized: {},
+ // recognized: {},
// unrecognized: [
// 'whatever',
// 'user',
@@ -129,9 +129,9 @@ const ListCommand = new Command({
// Any unrecognized flags can be retrieved by index number (0-based)
console.log(metadata.flag(0)) // The first unrecognized flag... returns null if it doesn't exist
- // Execution callbacks are optional. If a callback is passed from the
- // execution context to this handler, it will run after the command
- // has finished processing
+ // Execution callbacks are optional. If a callback is passed from the
+ // execution context to this handler, it will run after the command
+ // has finished processing
// (kind of like "next" in Express).
// Promises are also supported.
callback && callback()
@@ -205,7 +205,7 @@ Each command has a handler function, which is responsible for doing something. T
command: ,
input: 'Raw string of flags/arguments passed to the command',
flags: {
- recognized: {},
+ recognized: {},
unrecognized: [
'whatever',
'user',
@@ -519,7 +519,7 @@ Flags:
_`read` output:_
```sh
mycli read
-
+
Read a directory.
```
@@ -803,8 +803,8 @@ The help message for this flag would look like:
```sh
Flags:
- -name ['nm'] Required. Specify a name. Options: Mr
- Awesome, Mrs Awesome, Rad Dev. Can be
+ -name ['nm'] Required. Specify a name. Options: Mr
+ Awesome, Mrs Awesome, Rad Dev. Can be
used multiple times. (Default Rad Dev)
```
@@ -815,7 +815,7 @@ Flags:
This library uses a vanilla dependency (i.e. no-subdependencies) called [@author.io/table](https://github.com/author/table) to format the usage and help messages of the shell. The `Table` library can be used to create your own custom screens, though most users will likely want to stick with the defaults. If you want to customize messages, the following example can be used as a starting point. The configuration options for the table can be found in the README of its repository.
```javascript
-import { Shell, Command, Table } from '@author.io/node-shell'
+import { Shell, Command, Table } from '@author.io/shell'
const shell = new Shell(...)
shell.usage = '...'
@@ -834,7 +834,7 @@ shell.help = () => {
**The `usage` and/or `help` attributes of an individual `Command` can also be set:**
```javascript
-import { Shell, Command, Table } from '@author.io/node-shell'
+import { Shell, Command, Table } from '@author.io/shell'
const cmd = new Command(...)
cmd.usage = '...'
@@ -929,17 +929,19 @@ If you wish to generate your own autocompletion capabilities, use the `shell.dat
```sh
-npm install @author.io/node-shell
+npm install @author.io/shell --save
```
-Please note, you'll need a verison of Node that supports ES Modules. In Node 12, this feature is behind the `--experimental-modules` flag. It is available in Node 13+ without a flag, but your `package.json` file must have the `"type": "module"` attribute. This feature is generally available as of [Node 14.0.0](https://nodejs.org).
+Please note, you'll need a verison of Node that supports ES Modules. In Node 12, this feature is behind the `--experimental-modules` flag. It is available in Node 13+ without a flag, but the `package.json` file must have the `"type": "module"` attribute. This feature is generally available in [Node 14.0.0](https://nodejs.org) and above.
-Legacy (CommonJS/require)
+Legacy (CommonJS/require)
-If you need to use the older CommonJS format (i.e. `require`), run `npm install @author.io/node-shell-legacy` instead.
+DEPRECATED
+
+If you need to use the older CommonJS format (i.e. `require`), run `npm install @author.io/shell-legacy` instead.
### Browsers
@@ -947,27 +949,14 @@ If you need to use the older CommonJS format (i.e. `require`), run `npm install
**CDN**
```javascript
-import { Shell, Command } from 'https://cdn.pika.dev/@author.io/browser-shell'
+import { Shell, Command } from 'https://cdn.pika.dev/@author.io/shell'
```
-Also available from [jsdelivr](https://www.jsdelivr.com/package/npm/@author.io/browser-shell) and [unpkg](https://unpkg.com/@author.io/browser-shell).
-
-
-npm options
-
-
-If you wish to bundle this library in your build process, use the version most appropriate for your target runtimes:
-
-- `npm install @author.io/browser-shell` (Minified ES Module)
-- `npm install @author.io/browser-shell-es6` (IIFE Minified Module - globally accessible)
-- `npm install @author.io/shell` (source)
-
-**TAKE NOTICE: The source may not be what you think it is.** The source code may contain Node or browser code that is stripped out during the build process. We have a goal of making the _API_ runtime-agnostic, not the implementation. We do everything we can to avoid runtime-specific source code though, and it is rare to have node or browser-specific source code... we just can't guarantee the source will be easily embeddable. We recommend consuming the prebuilt editions.
-
+Also available from [jsdelivr](https://www.jsdelivr.com/package/npm/@author.io/shell/index.js) and [unpkg](https://unpkg.com/@author.io/shell/index.js).
### Debugging
-Each distribution has a corresponding `-debug` version that should be installed _alongside_ the main module (the debugging is an add-on module). For example, `npm install @author.io/node-shell-debug --save-dev` would install the debugging code for Node.
+Each distribution has a corresponding `-debug` version that should be installed _alongside_ the main module (the debugging is an add-on module). For example, `npm install @author.io/shell-debug --save-dev` would install the debugging code for Node. In the browser, appending the debug library adds sourcemaps.
### Related Modules
From af0fc5eb310b8cefe7780bdf14ffe58e5bc4e7fa Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Fri, 23 Jul 2021 14:32:12 -0500
Subject: [PATCH 106/152] Regenerate package-lock
---
package-lock.json | 141 +++++++++++-----------------------------------
1 file changed, 33 insertions(+), 108 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 74b828b..4a7e55d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,18 +18,16 @@
},
"node_modules/@author.io/arg": {
"version": "1.3.8",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.8.tgz",
- "integrity": "sha512-JXeBApJ9hCrlDPHoieX5d3BBqP6l1O0x95TkDSYfZgIa9OitQHwJuaBM7eyv8bkxL4pQnAORvftifVW/DdGinA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/@author.io/dev": {
"version": "1.1.5",
- "resolved": "https://registry.npmjs.org/@author.io/dev/-/dev-1.1.5.tgz",
- "integrity": "sha512-bid83f8hmaU86MVerAggVmkc5gE3kfkoHw54tJypYTqlwo7NViW7CppuzrH9cndCAIIBhThK6GgMYCgD4L9o/A==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"@author.io/node-shell": "^1.8.2",
"@author.io/shell": "^1.3.8",
@@ -44,9 +42,8 @@
},
"node_modules/@author.io/node-shell": {
"version": "1.8.2",
- "resolved": "https://registry.npmjs.org/@author.io/node-shell/-/node-shell-1.8.2.tgz",
- "integrity": "sha512-mnOwUASxLYV3NcSlUvjHwnLkbwhxSUcq/dwUPkawWmu5TJ6txYcU+Eub4QMyCXqpiThyiFrRc6Za89Nh+dKo0w==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@author.io/arg": "^1.3.8",
"@author.io/table": "^1.0.3"
@@ -57,9 +54,8 @@
},
"node_modules/@author.io/shell": {
"version": "1.3.8",
- "resolved": "https://registry.npmjs.org/@author.io/shell/-/shell-1.3.8.tgz",
- "integrity": "sha512-/ybwBCffBeFp4QS5tnC0bd/XxgTNXP9r6FVBJiFWolTjALVfL0tEUtOrNF+JdVxBf7vLvmnSiz5EUvrdj9Cm0A==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@author.io/arg": "^1.2.6",
"@author.io/table": "^1.0.1"
@@ -70,15 +66,13 @@
},
"node_modules/@author.io/table": {
"version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.0.3.tgz",
- "integrity": "sha512-JnsndB8kzcyLwYp42teOpdICCP4KZHmzOlFnL/uxfQCxGrQKEIH8Occq8LFQXO7OKri/tOYG5mOhrWxxuoRyzw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/ansi-styles": {
"version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -91,15 +85,13 @@
},
"node_modules/balanced-match": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/brace-expansion": {
"version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -107,9 +99,8 @@
},
"node_modules/chalk": {
"version": "4.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
- "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -123,9 +114,8 @@
},
"node_modules/color-convert": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
@@ -135,27 +125,23 @@
},
"node_modules/color-name": {
"version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/concat-map": {
"version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/fs.realpath": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/glob": {
"version": "7.1.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
- "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@@ -173,18 +159,16 @@
},
"node_modules/has-flag": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/inflight": {
"version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
+ "license": "ISC",
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
@@ -192,15 +176,13 @@
},
"node_modules/inherits": {
"version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/lru-cache": {
"version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
},
@@ -210,9 +192,8 @@
},
"node_modules/minimatch": {
"version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@@ -222,27 +203,24 @@
},
"node_modules/once": {
"version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
+ "license": "ISC",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/semver": {
"version": "7.3.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
- "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"lru-cache": "^6.0.0"
},
@@ -255,9 +233,8 @@
},
"node_modules/supports-color": {
"version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -267,28 +244,22 @@
},
"node_modules/wrappy": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/yallist": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
}
},
"dependencies": {
"@author.io/arg": {
"version": "1.3.8",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.8.tgz",
- "integrity": "sha512-JXeBApJ9hCrlDPHoieX5d3BBqP6l1O0x95TkDSYfZgIa9OitQHwJuaBM7eyv8bkxL4pQnAORvftifVW/DdGinA==",
"dev": true
},
"@author.io/dev": {
"version": "1.1.5",
- "resolved": "https://registry.npmjs.org/@author.io/dev/-/dev-1.1.5.tgz",
- "integrity": "sha512-bid83f8hmaU86MVerAggVmkc5gE3kfkoHw54tJypYTqlwo7NViW7CppuzrH9cndCAIIBhThK6GgMYCgD4L9o/A==",
"dev": true,
"requires": {
"@author.io/node-shell": "^1.8.2",
@@ -300,8 +271,6 @@
},
"@author.io/node-shell": {
"version": "1.8.2",
- "resolved": "https://registry.npmjs.org/@author.io/node-shell/-/node-shell-1.8.2.tgz",
- "integrity": "sha512-mnOwUASxLYV3NcSlUvjHwnLkbwhxSUcq/dwUPkawWmu5TJ6txYcU+Eub4QMyCXqpiThyiFrRc6Za89Nh+dKo0w==",
"dev": true,
"requires": {
"@author.io/arg": "^1.3.8",
@@ -310,8 +279,6 @@
},
"@author.io/shell": {
"version": "1.3.8",
- "resolved": "https://registry.npmjs.org/@author.io/shell/-/shell-1.3.8.tgz",
- "integrity": "sha512-/ybwBCffBeFp4QS5tnC0bd/XxgTNXP9r6FVBJiFWolTjALVfL0tEUtOrNF+JdVxBf7vLvmnSiz5EUvrdj9Cm0A==",
"dev": true,
"requires": {
"@author.io/arg": "^1.2.6",
@@ -320,14 +287,10 @@
},
"@author.io/table": {
"version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.0.3.tgz",
- "integrity": "sha512-JnsndB8kzcyLwYp42teOpdICCP4KZHmzOlFnL/uxfQCxGrQKEIH8Occq8LFQXO7OKri/tOYG5mOhrWxxuoRyzw==",
"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"
@@ -335,14 +298,10 @@
},
"balanced-match": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
@@ -351,8 +310,6 @@
},
"chalk": {
"version": "4.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
- "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
@@ -361,8 +318,6 @@
},
"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"
@@ -370,26 +325,18 @@
},
"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
},
"fs.realpath": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
},
"glob": {
"version": "7.1.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
- "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
@@ -402,14 +349,10 @@
},
"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
},
"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",
@@ -418,14 +361,10 @@
},
"inherits": {
"version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"lru-cache": {
"version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"requires": {
"yallist": "^4.0.0"
@@ -433,8 +372,6 @@
},
"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"
@@ -442,8 +379,6 @@
},
"once": {
"version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
"wrappy": "1"
@@ -451,14 +386,10 @@
},
"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
},
"semver": {
"version": "7.3.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
- "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
"dev": true,
"requires": {
"lru-cache": "^6.0.0"
@@ -466,8 +397,6 @@
},
"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"
@@ -475,14 +404,10 @@
},
"wrappy": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"yallist": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
}
}
From d608177fca2c1696639b708c47efcc0b67aa910e Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Fri, 23 Jul 2021 14:39:14 -0500
Subject: [PATCH 107/152] Add reference to install options at the top of the
README
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 74f99cb..e9e8d43 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# @author.io/shell

-This is a super-lightweight framework for building text-based programs, like [CLI](https://en.wikipedia.org/wiki/Command-line_interface) applications.
+This is a super-lightweight framework for building text-based programs, like [CLI](https://en.wikipedia.org/wiki/Command-line_interface) applications. See the [installation guide](#installation) to jumpstart your CLI.
---
This library is now supported by this [Chrome CLI Devtools Extension](https://chrome.google.com/webstore/detail/cli/okpglddgmnblhbdpdcmodmacgcibgfkf):
From 038dc3105947367ac57505317981fa615b71b9db Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Fri, 23 Jul 2021 15:44:05 -0500
Subject: [PATCH 108/152] Add exports to package for easier integration in
modular environments.
---
package.json | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 7234f0c..c681095 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.4",
+ "version": "1.8.5",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
@@ -29,6 +29,14 @@
"arg",
"shell"
],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/author/shell"
+ },
+ "exports": {
+ "import": "./index.js",
+ "default": "./index.js"
+ },
"dev": {
"ignorecircular": [
"src/command.js",
From be0dd18cc80e018d014e1d52edfe0bab9a52d0ef Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 2 Aug 2021 00:22:11 -0500
Subject: [PATCH 109/152] Added promise rejection handler to prevent Deno from
registering an uncaught promise.
---
package.json | 2 +-
src/command.js | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/package.json b/package.json
index c681095..941ee55 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.5",
+ "version": "1.8.6",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/command.js b/src/command.js
index 66af246..e4c711e 100644
--- a/src/command.js
+++ b/src/command.js
@@ -578,10 +578,10 @@ export default class Command extends Base {
static stderr (err) {
if (err instanceof Error) {
- return new Promise((resolve, reject) => reject(err))
+ return new Promise((resolve, reject) => reject(err)).catch(console.error)
}
- return new Promise((resolve, reject) => reject(err))
+ return new Promise((resolve, reject) => reject(err)).catch(console.error)
}
static reply (callback) {
From f651ae77e591b6d846fdd67a85bcf338e7b7ed15 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 3 Aug 2021 17:11:30 -0500
Subject: [PATCH 110/152] Dependency update, version bump.
---
package-lock.json | 15 +++++++++------
package.json | 6 +++---
2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 4a7e55d..cda9367 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,14 +1,14 @@
{
"name": "@author.io/shell",
- "version": "1.8.4",
+ "version": "1.8.7",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
- "version": "1.8.4",
+ "version": "1.8.7",
"license": "MIT",
"devDependencies": {
- "@author.io/arg": "^1.3.8",
+ "@author.io/arg": "^1.3.13",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
},
@@ -17,9 +17,10 @@
}
},
"node_modules/@author.io/arg": {
- "version": "1.3.8",
+ "version": "1.3.13",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.13.tgz",
+ "integrity": "sha512-115k2jRIC/GGYkP9qDryyvH8yDCHsrsYSjLfnNO/63yQKTuXYnGj30lihKkmxG12envHDStD6WxkeLrNl2zZ8Q==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=12.0.0"
}
@@ -255,7 +256,9 @@
},
"dependencies": {
"@author.io/arg": {
- "version": "1.3.8",
+ "version": "1.3.13",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.13.tgz",
+ "integrity": "sha512-115k2jRIC/GGYkP9qDryyvH8yDCHsrsYSjLfnNO/63yQKTuXYnGj30lihKkmxG12envHDStD6WxkeLrNl2zZ8Q==",
"dev": true
},
"@author.io/dev": {
diff --git a/package.json b/package.json
index 941ee55..dfb49f4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.6",
+ "version": "1.8.7",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
@@ -46,7 +46,7 @@
"<#REPLACE_VERSION#>": "package.version"
},
"volume": [
- "./node_modules/@author.io/arg:/node_modules/@author.io/arg",
+ "./node_modules/@author.io/arg:/node_modules/@author.io/arg/src",
"./node_modules/@author.io/table:/node_modules/@author.io/table"
],
"alias": {
@@ -93,7 +93,7 @@
]
},
"devDependencies": {
- "@author.io/arg": "^1.3.8",
+ "@author.io/arg": "^1.3.13",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
}
From b7302be860d71698e7198ebea432e59f88760814 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 3 Aug 2021 22:51:09 -0500
Subject: [PATCH 111/152] Updated arg dependency to fix multi-value arg
regression.
---
package-lock.json | 14 +++++++-------
package.json | 9 +++++----
tests/100-regression.js | 26 +++++++++++++++++++++++---
3 files changed, 35 insertions(+), 14 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index cda9367..e642d4f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,7 +8,7 @@
"version": "1.8.7",
"license": "MIT",
"devDependencies": {
- "@author.io/arg": "^1.3.13",
+ "@author.io/arg": "^1.3.14",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
},
@@ -17,9 +17,9 @@
}
},
"node_modules/@author.io/arg": {
- "version": "1.3.13",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.13.tgz",
- "integrity": "sha512-115k2jRIC/GGYkP9qDryyvH8yDCHsrsYSjLfnNO/63yQKTuXYnGj30lihKkmxG12envHDStD6WxkeLrNl2zZ8Q==",
+ "version": "1.3.14",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.14.tgz",
+ "integrity": "sha512-0dRejm29w8MKBNw6Ua1foOuIWADBg8tcK+Hx5R7KJlST8toZgOJlZ3rln/Sxy7h2Nd/xbh5CwK8cwGbyLHc/0A==",
"dev": true,
"engines": {
"node": ">=12.0.0"
@@ -256,9 +256,9 @@
},
"dependencies": {
"@author.io/arg": {
- "version": "1.3.13",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.13.tgz",
- "integrity": "sha512-115k2jRIC/GGYkP9qDryyvH8yDCHsrsYSjLfnNO/63yQKTuXYnGj30lihKkmxG12envHDStD6WxkeLrNl2zZ8Q==",
+ "version": "1.3.14",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.14.tgz",
+ "integrity": "sha512-0dRejm29w8MKBNw6Ua1foOuIWADBg8tcK+Hx5R7KJlST8toZgOJlZ3rln/Sxy7h2Nd/xbh5CwK8cwGbyLHc/0A==",
"dev": true
},
"@author.io/dev": {
diff --git a/package.json b/package.json
index dfb49f4..35524c9 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.7",
+ "version": "1.8.8",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
@@ -10,6 +10,7 @@
"test:node:sanity": "dev test -rt node tests/01-sanity.js",
"test:node:base": "dev test -rt node tests/02-base.js",
"test:node:relationships": "dev test -rt node tests/06-relationships.js",
+ "test:node:regression": "dev test -rt node tests/100-regression.js",
"test:browser": "dev test -rt browser tests/*.js",
"test:browser:sanity": "dev test -rt browser tests/01-sanity.js",
"test:browser:base": "dev test -rt browser tests/02-base.js",
@@ -46,12 +47,12 @@
"<#REPLACE_VERSION#>": "package.version"
},
"volume": [
- "./node_modules/@author.io/arg:/node_modules/@author.io/arg/src",
+ "./node_modules/@author.io/arg:/node_modules/@author.io/arg",
"./node_modules/@author.io/table:/node_modules/@author.io/table"
],
"alias": {
"@author.io/shell": "/app/.dist/shell/index.js",
- "@author.io/arg": "/node_modules/@author.io/arg/index.js",
+ "@author.io/arg": "/node_modules/@author.io/arg/src/index.js",
"@author.io/table": "/node_modules/@author.io/table/src/index.js"
},
"ci": {
@@ -93,7 +94,7 @@
]
},
"devDependencies": {
- "@author.io/arg": "^1.3.13",
+ "@author.io/arg": "^1.3.14",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
}
diff --git a/tests/100-regression.js b/tests/100-regression.js
index 51cc1a7..5ebceda 100644
--- a/tests/100-regression.js
+++ b/tests/100-regression.js
@@ -42,9 +42,9 @@ test('Metadata duplication of flag values when multiple values are allowed', t =
}
},
handler (meta) {
- t.ok(meta.data.file[0] === 'a.js', 'First value is correct')
- t.ok(meta.data.file[1] === 'b.js', 'Second value is correct')
- t.ok(meta.data.file.length === 2, 'Only two unique flag values provided.')
+ t.expect('a.js', meta.data.file[0], 'First value is correct')
+ t.expect('b.js', meta.data.file[1], 'Second value is correct')
+ t.expect(2, meta.data.file.length, 'Only two unique flag values provided.')
t.end()
}
}]
@@ -52,3 +52,23 @@ test('Metadata duplication of flag values when multiple values are allowed', t =
sh.exec('run -f a.js -f b.js').catch(t.fail)
})
+
+test('Properly parsing input values with spaces', t => {
+ const sh = new Shell({
+ name: 'test',
+ commands: [{
+ name: 'run',
+ flags: {
+ connection: {
+ alias: 'c'
+ }
+ },
+ handler(meta) {
+ t.expect('a connection', meta.data.connection, 'Support flag values with spaces')
+ t.end()
+ }
+ }]
+ })
+
+ sh.exec('run -c "a connection"').catch(t.fail)
+})
From 2f9f61a9478bb8ed787ae572520b7103b68a16c0 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 3 Aug 2021 22:54:16 -0500
Subject: [PATCH 112/152] Fix dev config
---
package.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index 35524c9..10a53d9 100644
--- a/package.json
+++ b/package.json
@@ -52,8 +52,8 @@
],
"alias": {
"@author.io/shell": "/app/.dist/shell/index.js",
- "@author.io/arg": "/node_modules/@author.io/arg/src/index.js",
- "@author.io/table": "/node_modules/@author.io/table/src/index.js"
+ "@author.io/arg": "/node_modules/@author.io/arg/index.js",
+ "@author.io/table": "/node_modules/@author.io/table/index.js"
},
"ci": {
"verbose": true,
From 3d4e2f55178087cdd5f4c676a44d1e269b08f748 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Tue, 3 Aug 2021 23:29:28 -0500
Subject: [PATCH 113/152] Fix dev config
---
package.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index 10a53d9..35524c9 100644
--- a/package.json
+++ b/package.json
@@ -52,8 +52,8 @@
],
"alias": {
"@author.io/shell": "/app/.dist/shell/index.js",
- "@author.io/arg": "/node_modules/@author.io/arg/index.js",
- "@author.io/table": "/node_modules/@author.io/table/index.js"
+ "@author.io/arg": "/node_modules/@author.io/arg/src/index.js",
+ "@author.io/table": "/node_modules/@author.io/table/src/index.js"
},
"ci": {
"verbose": true,
From efbf4b433ebe1963d81f123fbb8814fe4c636d8c Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 4 Aug 2021 00:05:07 -0500
Subject: [PATCH 114/152] Fix dev config
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 35524c9..07bc85f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.8",
+ "version": "1.8.9",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
From 0214ddfb9eaee4f9a99a1be04148cf77c285bb0d Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 4 Aug 2021 00:09:55 -0500
Subject: [PATCH 115/152] Fix dev config
---
.github/workflows/deploy.yml | 2 +-
package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 184c83f..e4b6ad0 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -17,7 +17,7 @@ jobs:
- uses: actions/setup-node@v1
name: Setup Node.js
with:
- node-version: '15'
+ node-version: '16'
- uses: actions/cache@v2
name: Establish Docker Cache
diff --git a/package.json b/package.json
index 07bc85f..e3dd824 100644
--- a/package.json
+++ b/package.json
@@ -47,7 +47,7 @@
"<#REPLACE_VERSION#>": "package.version"
},
"volume": [
- "./node_modules/@author.io/arg:/node_modules/@author.io/arg",
+ "./node_modules/@author.io/arg:/node_modules/@author.io/arg/src",
"./node_modules/@author.io/table:/node_modules/@author.io/table"
],
"alias": {
From 427cc09c1712c7e74cd986c10da38c17704ce76a Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 4 Aug 2021 21:29:05 -0500
Subject: [PATCH 116/152] Updated arg dependency to add support for quoted
arguments
---
package-lock.json | 18 +++++++++---------
package.json | 4 ++--
tests/04-metadata.js | 5 +++--
3 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index e642d4f..24eb607 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,14 +1,14 @@
{
"name": "@author.io/shell",
- "version": "1.8.7",
+ "version": "1.8.9",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
- "version": "1.8.7",
+ "version": "1.8.9",
"license": "MIT",
"devDependencies": {
- "@author.io/arg": "^1.3.14",
+ "@author.io/arg": "^1.3.15",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
},
@@ -17,9 +17,9 @@
}
},
"node_modules/@author.io/arg": {
- "version": "1.3.14",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.14.tgz",
- "integrity": "sha512-0dRejm29w8MKBNw6Ua1foOuIWADBg8tcK+Hx5R7KJlST8toZgOJlZ3rln/Sxy7h2Nd/xbh5CwK8cwGbyLHc/0A==",
+ "version": "1.3.15",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.15.tgz",
+ "integrity": "sha512-11wO5n5Ar+KdzrNtFhy+YcfmuyRowgBmyRfTBKJN6HTkGveajuyqtZoyMydCD2ISILqlt/+wWaYHFsFtZmcvOw==",
"dev": true,
"engines": {
"node": ">=12.0.0"
@@ -256,9 +256,9 @@
},
"dependencies": {
"@author.io/arg": {
- "version": "1.3.14",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.14.tgz",
- "integrity": "sha512-0dRejm29w8MKBNw6Ua1foOuIWADBg8tcK+Hx5R7KJlST8toZgOJlZ3rln/Sxy7h2Nd/xbh5CwK8cwGbyLHc/0A==",
+ "version": "1.3.15",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.15.tgz",
+ "integrity": "sha512-11wO5n5Ar+KdzrNtFhy+YcfmuyRowgBmyRfTBKJN6HTkGveajuyqtZoyMydCD2ISILqlt/+wWaYHFsFtZmcvOw==",
"dev": true
},
"@author.io/dev": {
diff --git a/package.json b/package.json
index e3dd824..8c2e78e 100644
--- a/package.json
+++ b/package.json
@@ -47,7 +47,7 @@
"<#REPLACE_VERSION#>": "package.version"
},
"volume": [
- "./node_modules/@author.io/arg:/node_modules/@author.io/arg/src",
+ "./node_modules/@author.io/arg:/node_modules/@author.io/arg",
"./node_modules/@author.io/table:/node_modules/@author.io/table"
],
"alias": {
@@ -94,7 +94,7 @@
]
},
"devDependencies": {
- "@author.io/arg": "^1.3.14",
+ "@author.io/arg": "^1.3.15",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
}
diff --git a/tests/04-metadata.js b/tests/04-metadata.js
index 5a8f3c4..925ec13 100644
--- a/tests/04-metadata.js
+++ b/tests/04-metadata.js
@@ -27,9 +27,10 @@ test('Map unnamed arguments', t => {
arguments: 'email displayName',
handler (meta) {
t.ok(meta.data.hasOwnProperty('email'), 'Automapped email data exists.')
- t.ok(meta.data.email === 'me@domain.com', `Attribute named email expected a value of "me@domain.com". Received "${meta.data.email}".`)
+ t.expect('me@domain.com', meta.data.email, 'Recognized email')
t.ok(meta.data.hasOwnProperty('displayName'), 'Automapped displayName data exists.')
- t.ok(meta.data.displayName === 'John Doe', `Attribute named displayName expected a value of "John Doe". Received "${meta.data.displayName}".`)
+ console.log(meta.data)
+ t.expect('John Doe', meta.data.displayName, 'Recognized displayName')
}
}]
})
From fc55967bf301af20830f87e06accbec9efc367cb Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 4 Aug 2021 22:38:30 -0500
Subject: [PATCH 117/152] Update build process
---
.github/workflows/deploy.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index e4b6ad0..4cf7acf 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -104,6 +104,7 @@ jobs:
id: build_release
if: steps.create_release.outputs.id != ''
run: |
+ ls -l
dev build --pack --mode ci --peer
cp -rf .dist ./dist
From ea97fdc53660b1e597a2979572e7954087f7b6fd Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 4 Aug 2021 22:44:40 -0500
Subject: [PATCH 118/152] Update build process
---
.github/workflows/deploy.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 4cf7acf..e18e36d 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -105,6 +105,7 @@ jobs:
if: steps.create_release.outputs.id != ''
run: |
ls -l
+ ln -s /node_modules ./node_modules
dev build --pack --mode ci --peer
cp -rf .dist ./dist
From a78210cbfb867dbf637209ce4f86eb6d3c4914ea Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 4 Aug 2021 22:47:33 -0500
Subject: [PATCH 119/152] Update build process
---
.github/workflows/deploy.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index e18e36d..f9a8d67 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -104,8 +104,9 @@ jobs:
id: build_release
if: steps.create_release.outputs.id != ''
run: |
- ls -l
ln -s /node_modules ./node_modules
+ ls -l
+ ls -l ./node_modules
dev build --pack --mode ci --peer
cp -rf .dist ./dist
From 6fbd79f227c0b8c9b0fbe8ba566cb9877db93120 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 4 Aug 2021 22:50:51 -0500
Subject: [PATCH 120/152] Update build process
---
.github/workflows/deploy.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index f9a8d67..0ac82bd 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -105,8 +105,9 @@ jobs:
if: steps.create_release.outputs.id != ''
run: |
ln -s /node_modules ./node_modules
+ pwd
ls -l
- ls -l ./node_modules
+ ls -l /node_modules
dev build --pack --mode ci --peer
cp -rf .dist ./dist
From d8b0cab9a4fe574dd29200372107d01df88a2039 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 4 Aug 2021 22:53:37 -0500
Subject: [PATCH 121/152] Update build process
---
.github/workflows/deploy.yml | 3 ---
1 file changed, 3 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 0ac82bd..29bb163 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -105,9 +105,6 @@ jobs:
if: steps.create_release.outputs.id != ''
run: |
ln -s /node_modules ./node_modules
- pwd
- ls -l
- ls -l /node_modules
dev build --pack --mode ci --peer
cp -rf .dist ./dist
From 83aa3e610436b63e5c44527b93507099711f25b7 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 4 Aug 2021 22:58:11 -0500
Subject: [PATCH 122/152] Update build process
---
.github/workflows/deploy.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 29bb163..c1699dc 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -69,6 +69,7 @@ jobs:
- name: Test
if: success()
run: |
+ npm i
dev -v
npm run ci
From 6b6eae3231b6b7f4912d5f34977fab988e158779 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Thu, 5 Aug 2021 11:47:33 -0500
Subject: [PATCH 123/152] add shell.exec support for auto-quoting arguments
with spaces in them (when arguments are passed as an array)
---
package.json | 2 +-
src/shell.js | 8 ++++++-
tests/100-regression.js | 47 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 55 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index 8c2e78e..efa45f3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.9",
+ "version": "1.8.10",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
diff --git a/src/shell.js b/src/shell.js
index edca10a..c5bad75 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -167,7 +167,13 @@ export default class Shell extends Base {
// The array check exists because people are passing process.argv.slice(2) into this
// method, often forgetting to join the values into a string.
if (Array.isArray(input)) {
- input = input.join(' ')
+ input = input.map(i => {
+ if (i.indexOf(' ') >= 0 && !/^[\"\'].+ [\"\']$/.test(i)) {
+ return `"${i}"`
+ } else {
+ return i
+ }
+ }).join(' ')
}
this.#history.unshift({ input, time: new Date().toLocaleString() })
diff --git a/tests/100-regression.js b/tests/100-regression.js
index 5ebceda..762f27c 100644
--- a/tests/100-regression.js
+++ b/tests/100-regression.js
@@ -72,3 +72,50 @@ test('Properly parsing input values with spaces', t => {
sh.exec('run -c "a connection"').catch(t.fail)
})
+
+test('Recognize flags with quotes', t => {
+ const input = 'run --connection "a connection" --save'
+ const sh = new Shell({
+ name: 'test',
+ commands: [{
+ name: 'run',
+ flags: {
+ connection: {
+ alias: 'c',
+ description: 'connection string',
+ type: 'string'
+ }
+ },
+ handler(meta) {
+ t.expect('a connection', meta.data.connection, 'Support flag values with spaces')
+ t.end()
+ }
+ }]
+ })
+
+ sh.exec('run -c "a connection"').catch(t.fail)
+})
+
+test('Accept arrays with values containing spaces', t => {
+ const input = 'run --connection "a connection" --save'
+ const sh = new Shell({
+ name: 'test',
+ commands: [{
+ name: 'run',
+ flags: {
+ connection: {
+ alias: 'c',
+ description: 'connection string',
+ type: 'string'
+ }
+ },
+ handler(meta) {
+ t.expect('a connection', meta.data.connection, 'Support flag values with spaces')
+ t.end()
+ }
+ }]
+ })
+
+ const argv = ["run", "-c", "a connection", "--save"]
+ sh.exec(argv).catch(t.fail)
+})
From e99f677a04aaa8f6cde7b5dc6f588c502e3bcc41 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sat, 16 Oct 2021 21:40:27 -0500
Subject: [PATCH 124/152] Update dependencies
Updated @author.io/arg to fix boolean flag/unnamed flag conflict.
---
package.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index efa45f3..72c77d4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.10",
+ "version": "1.8.11",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "src/index.js",
"scripts": {
@@ -94,7 +94,7 @@
]
},
"devDependencies": {
- "@author.io/arg": "^1.3.15",
+ "@author.io/arg": "^1.3.16",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
}
From 7b82be4a19cabd66c2517e4db82a220ae59bc488 Mon Sep 17 00:00:00 2001
From: coreybutler
Date: Sat, 16 Oct 2021 22:03:21 -0500
Subject: [PATCH 125/152] Updated dependencies
---
package-lock.json | 19 ++++++++++---------
package.json | 13 ++++++++++---
2 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 24eb607..99b3ffe 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,14 +1,15 @@
{
"name": "@author.io/shell",
- "version": "1.8.9",
+ "version": "1.8.12",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
- "version": "1.8.9",
+ "name": "@author.io/shell",
+ "version": "1.8.12",
"license": "MIT",
"devDependencies": {
- "@author.io/arg": "^1.3.15",
+ "@author.io/arg": "^1.3.17",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
},
@@ -17,9 +18,9 @@
}
},
"node_modules/@author.io/arg": {
- "version": "1.3.15",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.15.tgz",
- "integrity": "sha512-11wO5n5Ar+KdzrNtFhy+YcfmuyRowgBmyRfTBKJN6HTkGveajuyqtZoyMydCD2ISILqlt/+wWaYHFsFtZmcvOw==",
+ "version": "1.3.17",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.17.tgz",
+ "integrity": "sha512-DkYHUFKkS3VPxe09ZGZvZBW1v/XNIiM3pey5WAP7iOtvOvwJWaRMcySbkKseuHmg/VjeoYexB6c3BqiXiqmFOw==",
"dev": true,
"engines": {
"node": ">=12.0.0"
@@ -256,9 +257,9 @@
},
"dependencies": {
"@author.io/arg": {
- "version": "1.3.15",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.15.tgz",
- "integrity": "sha512-11wO5n5Ar+KdzrNtFhy+YcfmuyRowgBmyRfTBKJN6HTkGveajuyqtZoyMydCD2ISILqlt/+wWaYHFsFtZmcvOw==",
+ "version": "1.3.17",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.17.tgz",
+ "integrity": "sha512-DkYHUFKkS3VPxe09ZGZvZBW1v/XNIiM3pey5WAP7iOtvOvwJWaRMcySbkKseuHmg/VjeoYexB6c3BqiXiqmFOw==",
"dev": true
},
"@author.io/dev": {
diff --git a/package.json b/package.json
index 72c77d4..49657cf 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,15 @@
{
"name": "@author.io/shell",
- "version": "1.8.11",
+ "version": "1.8.12",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
- "main": "src/index.js",
+ "main": "./src/index.js",
+ "module": "index.js",
+ "exports": {
+ ".": {
+ "import": "./index.js"
+ }
+ },
+ "browser": "./index.js",
"scripts": {
"start": "dev workspace",
"test": "npm run test:node && npm run test:deno && npm run test:browser && npm run report:syntax && npm run report:size",
@@ -94,7 +101,7 @@
]
},
"devDependencies": {
- "@author.io/arg": "^1.3.16",
+ "@author.io/arg": "^1.3.17",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
}
From c9866a40be49e81ddae9cd4e9d481a15788bdb41 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sun, 17 Oct 2021 19:43:06 -0500
Subject: [PATCH 126/152] Update package.json
Updated dependencies
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 49657cf..1a0e66d 100644
--- a/package.json
+++ b/package.json
@@ -101,7 +101,7 @@
]
},
"devDependencies": {
- "@author.io/arg": "^1.3.17",
+ "@author.io/arg": "^1.3.18",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
}
From 13cad3b1e1babeabffca6672a13e3b36d21009a0 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sun, 17 Oct 2021 19:46:07 -0500
Subject: [PATCH 127/152] Update package.json
version bump
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 1a0e66d..beff29e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.12",
+ "version": "1.8.13",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "./src/index.js",
"module": "index.js",
From 6978cb1d656b160e517fcd5ec1fc80cebc01b23c Mon Sep 17 00:00:00 2001
From: coreybutler
Date: Mon, 18 Oct 2021 00:08:10 -0500
Subject: [PATCH 128/152] converted to jsdev build tool
---
package-lock.json | 14 +++++++-------
package.json | 19 +++++++------------
2 files changed, 14 insertions(+), 19 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 99b3ffe..add101d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,7 @@
"version": "1.8.12",
"license": "MIT",
"devDependencies": {
- "@author.io/arg": "^1.3.17",
+ "@author.io/arg": "^1.3.19",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
},
@@ -18,9 +18,9 @@
}
},
"node_modules/@author.io/arg": {
- "version": "1.3.17",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.17.tgz",
- "integrity": "sha512-DkYHUFKkS3VPxe09ZGZvZBW1v/XNIiM3pey5WAP7iOtvOvwJWaRMcySbkKseuHmg/VjeoYexB6c3BqiXiqmFOw==",
+ "version": "1.3.19",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.19.tgz",
+ "integrity": "sha512-3EyWe8ZXMwD18GdBkFZYJugY4v+iS9m0TbjzGH2p1yi9XKrlnPlOkyU11I6wlcd/CQGeL4nu8n1QAHrUSsxmuw==",
"dev": true,
"engines": {
"node": ">=12.0.0"
@@ -257,9 +257,9 @@
},
"dependencies": {
"@author.io/arg": {
- "version": "1.3.17",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.17.tgz",
- "integrity": "sha512-DkYHUFKkS3VPxe09ZGZvZBW1v/XNIiM3pey5WAP7iOtvOvwJWaRMcySbkKseuHmg/VjeoYexB6c3BqiXiqmFOw==",
+ "version": "1.3.19",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.19.tgz",
+ "integrity": "sha512-3EyWe8ZXMwD18GdBkFZYJugY4v+iS9m0TbjzGH2p1yi9XKrlnPlOkyU11I6wlcd/CQGeL4nu8n1QAHrUSsxmuw==",
"dev": true
},
"@author.io/dev": {
diff --git a/package.json b/package.json
index 49657cf..fe210f2 100644
--- a/package.json
+++ b/package.json
@@ -1,13 +1,12 @@
{
"name": "@author.io/shell",
- "version": "1.8.12",
+ "version": "1.8.13",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "./src/index.js",
- "module": "index.js",
+ "module": "./index.js",
"exports": {
- ".": {
- "import": "./index.js"
- }
+ "import": "./index.js",
+ "default": "./index.js"
},
"browser": "./index.js",
"scripts": {
@@ -41,10 +40,6 @@
"type": "git",
"url": "https://github.com/author/shell"
},
- "exports": {
- "import": "./index.js",
- "default": "./index.js"
- },
"dev": {
"ignorecircular": [
"src/command.js",
@@ -58,8 +53,8 @@
"./node_modules/@author.io/table:/node_modules/@author.io/table"
],
"alias": {
- "@author.io/shell": "/app/.dist/shell/index.js",
- "@author.io/arg": "/node_modules/@author.io/arg/src/index.js",
+ "@author.io/shell": "/app/.dist/@author.io/shell/index.js",
+ "@author.io/arg": "/node_modules/@author.io/arg/index.js",
"@author.io/table": "/node_modules/@author.io/table/src/index.js"
},
"ci": {
@@ -101,7 +96,7 @@
]
},
"devDependencies": {
- "@author.io/arg": "^1.3.17",
+ "@author.io/arg": "^1.3.19",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
}
From f464c73c49de90871ed19a209042ba64603e7ff4 Mon Sep 17 00:00:00 2001
From: coreybutler
Date: Tue, 19 Oct 2021 22:09:19 -0500
Subject: [PATCH 129/152] Rebuilt with ESM output
---
.travis.yml | 14 ----
package-lock.json | 180 +++++++++++++++++++++++++++++++---------------
package.json | 6 +-
3 files changed, 125 insertions(+), 75 deletions(-)
delete mode 100644 .travis.yml
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 580b705..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-language: node_js
-node_js:
-- '14.0.0'
-
-install:
- - npm run setup
- - npm install
- - cd ./test && rm -rf node_modules/yaml && npm i yaml@1.7.2 && cd ../
-
-script:
- # Only run node tests since sauce labs fails all the time
- - npm run test:node
- # - ls -l
- # - cd ./test && ls -l && npm run node
diff --git a/package-lock.json b/package-lock.json
index add101d..528fac1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@author.io/shell",
- "version": "1.8.12",
+ "version": "1.8.13",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@author.io/shell",
- "version": "1.8.12",
+ "version": "1.8.13",
"license": "MIT",
"devDependencies": {
"@author.io/arg": "^1.3.19",
@@ -27,9 +27,10 @@
}
},
"node_modules/@author.io/dev": {
- "version": "1.1.5",
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@author.io/dev/-/dev-1.1.6.tgz",
+ "integrity": "sha512-unNtw/ibtPjbkhd7IDmO4e+JDpWoxqFmuQgF+gu3LDms2Nd0k/pN+umAPaxLPNHW/r7yvaTarMYtwdZOWQsf6A==",
"dev": true,
- "license": "ISC",
"dependencies": {
"@author.io/node-shell": "^1.8.2",
"@author.io/shell": "^1.3.8",
@@ -39,13 +40,14 @@
},
"bin": {
"dev": "index.js",
- "space": "index.js"
+ "jsdev": "index.js"
}
},
"node_modules/@author.io/node-shell": {
"version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/@author.io/node-shell/-/node-shell-1.8.2.tgz",
+ "integrity": "sha512-mnOwUASxLYV3NcSlUvjHwnLkbwhxSUcq/dwUPkawWmu5TJ6txYcU+Eub4QMyCXqpiThyiFrRc6Za89Nh+dKo0w==",
"dev": true,
- "license": "MIT",
"dependencies": {
"@author.io/arg": "^1.3.8",
"@author.io/table": "^1.0.3"
@@ -55,26 +57,25 @@
}
},
"node_modules/@author.io/shell": {
- "version": "1.3.8",
+ "version": "1.8.13",
+ "resolved": "https://registry.npmjs.org/@author.io/shell/-/shell-1.8.13.tgz",
+ "integrity": "sha512-5cXWXOjilxtfdKynAyGkoPbjj5JG15JafLPxmylH61i5cvD3ZecpAhNYUwrucmCOP+EspixAY1Tlvr0DyBEjVw==",
"dev": true,
- "license": "MIT",
- "dependencies": {
- "@author.io/arg": "^1.2.6",
- "@author.io/table": "^1.0.1"
- },
"engines": {
"node": ">=13.5.0"
}
},
"node_modules/@author.io/table": {
- "version": "1.0.3",
- "dev": true,
- "license": "MIT"
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.1.1.tgz",
+ "integrity": "sha512-QvDVZnZ4qZHKrFkGi44QZBJAAkm0lsYKIrdA17ZKzrl5jUjO38qyiatSBl4ttqpWcHNJRBP8A/p7kLAOiRrK8Q==",
+ "dev": true
},
"node_modules/ansi-styles": {
"version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
- "license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -86,23 +87,26 @@
}
},
"node_modules/balanced-match": {
- "version": "1.0.0",
- "dev": true,
- "license": "MIT"
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
},
"node_modules/brace-expansion": {
"version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/chalk": {
- "version": "4.1.0",
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -116,8 +120,9 @@
},
"node_modules/color-convert": {
"version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
@@ -127,23 +132,27 @@
},
"node_modules/color-name": {
"version": "1.1.4",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
},
"node_modules/concat-map": {
"version": "0.0.1",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
},
"node_modules/fs.realpath": {
"version": "1.0.0",
- "dev": true,
- "license": "ISC"
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
},
"node_modules/glob": {
- "version": "7.1.6",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
"dev": true,
- "license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@@ -161,16 +170,18 @@
},
"node_modules/has-flag": {
"version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/inflight": {
"version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
- "license": "ISC",
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
@@ -178,13 +189,15 @@
},
"node_modules/inherits": {
"version": "2.0.4",
- "dev": true,
- "license": "ISC"
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
},
"node_modules/lru-cache": {
"version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
- "license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
},
@@ -194,8 +207,9 @@
},
"node_modules/minimatch": {
"version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
- "license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@@ -205,24 +219,27 @@
},
"node_modules/once": {
"version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
- "license": "ISC",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/semver": {
- "version": "7.3.4",
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+ "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"dev": true,
- "license": "ISC",
"dependencies": {
"lru-cache": "^6.0.0"
},
@@ -235,8 +252,9 @@
},
"node_modules/supports-color": {
"version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
- "license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -246,13 +264,15 @@
},
"node_modules/wrappy": {
"version": "1.0.2",
- "dev": true,
- "license": "ISC"
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
},
"node_modules/yallist": {
"version": "4.0.0",
- "dev": true,
- "license": "ISC"
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
}
},
"dependencies": {
@@ -263,7 +283,9 @@
"dev": true
},
"@author.io/dev": {
- "version": "1.1.5",
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@author.io/dev/-/dev-1.1.6.tgz",
+ "integrity": "sha512-unNtw/ibtPjbkhd7IDmO4e+JDpWoxqFmuQgF+gu3LDms2Nd0k/pN+umAPaxLPNHW/r7yvaTarMYtwdZOWQsf6A==",
"dev": true,
"requires": {
"@author.io/node-shell": "^1.8.2",
@@ -275,6 +297,8 @@
},
"@author.io/node-shell": {
"version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/@author.io/node-shell/-/node-shell-1.8.2.tgz",
+ "integrity": "sha512-mnOwUASxLYV3NcSlUvjHwnLkbwhxSUcq/dwUPkawWmu5TJ6txYcU+Eub4QMyCXqpiThyiFrRc6Za89Nh+dKo0w==",
"dev": true,
"requires": {
"@author.io/arg": "^1.3.8",
@@ -282,30 +306,36 @@
}
},
"@author.io/shell": {
- "version": "1.3.8",
- "dev": true,
- "requires": {
- "@author.io/arg": "^1.2.6",
- "@author.io/table": "^1.0.1"
- }
+ "version": "1.8.13",
+ "resolved": "https://registry.npmjs.org/@author.io/shell/-/shell-1.8.13.tgz",
+ "integrity": "sha512-5cXWXOjilxtfdKynAyGkoPbjj5JG15JafLPxmylH61i5cvD3ZecpAhNYUwrucmCOP+EspixAY1Tlvr0DyBEjVw==",
+ "dev": true
},
"@author.io/table": {
- "version": "1.0.3",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.1.1.tgz",
+ "integrity": "sha512-QvDVZnZ4qZHKrFkGi44QZBJAAkm0lsYKIrdA17ZKzrl5jUjO38qyiatSBl4ttqpWcHNJRBP8A/p7kLAOiRrK8Q==",
"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"
}
},
"balanced-match": {
- "version": "1.0.0",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
@@ -313,7 +343,9 @@
}
},
"chalk": {
- "version": "4.1.0",
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
@@ -322,6 +354,8 @@
},
"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"
@@ -329,18 +363,26 @@
},
"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
},
"fs.realpath": {
"version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
},
"glob": {
- "version": "7.1.6",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
@@ -353,10 +395,14 @@
},
"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
},
"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",
@@ -365,10 +411,14 @@
},
"inherits": {
"version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"lru-cache": {
"version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"requires": {
"yallist": "^4.0.0"
@@ -376,6 +426,8 @@
},
"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"
@@ -383,6 +435,8 @@
},
"once": {
"version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
"wrappy": "1"
@@ -390,10 +444,14 @@
},
"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
},
"semver": {
- "version": "7.3.4",
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+ "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"dev": true,
"requires": {
"lru-cache": "^6.0.0"
@@ -401,6 +459,8 @@
},
"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"
@@ -408,10 +468,14 @@
},
"wrappy": {
"version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"yallist": {
"version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
}
}
diff --git a/package.json b/package.json
index fe210f2..5771d6a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.13",
+ "version": "1.8.14",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "./src/index.js",
"module": "./index.js",
@@ -55,7 +55,7 @@
"alias": {
"@author.io/shell": "/app/.dist/@author.io/shell/index.js",
"@author.io/arg": "/node_modules/@author.io/arg/index.js",
- "@author.io/table": "/node_modules/@author.io/table/src/index.js"
+ "@author.io/table": "/node_modules/@author.io/table/index.js"
},
"ci": {
"verbose": true,
@@ -100,4 +100,4 @@
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
}
-}
+}
\ No newline at end of file
From 11618259587e18269b93b97c74afe2494b34f97b Mon Sep 17 00:00:00 2001
From: coreybutler
Date: Wed, 20 Oct 2021 20:06:30 -0500
Subject: [PATCH 130/152] Dependency updates
---
package.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index 5771d6a..a9a29bc 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.14",
+ "version": "1.8.15",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "./src/index.js",
"module": "./index.js",
@@ -96,7 +96,7 @@
]
},
"devDependencies": {
- "@author.io/arg": "^1.3.19",
+ "@author.io/arg": "^1.3.20",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
}
From 22c47daa607d3e1809067bd8b055a2c06f316e9b Mon Sep 17 00:00:00 2001
From: coreybutler
Date: Wed, 20 Oct 2021 20:37:31 -0500
Subject: [PATCH 131/152] Version bump
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index a9a29bc..79e73a2 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.15",
+ "version": "1.8.16",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "./src/index.js",
"module": "./index.js",
From fdffbf57b10add6c1d29ede91f660eb2de7ac56a Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Sun, 19 Dec 2021 21:27:09 -0600
Subject: [PATCH 132/152] Updated arg dependency (fixes a regression)
---
package.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index 79e73a2..d631aa3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.16",
+ "version": "1.8.17",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "./src/index.js",
"module": "./index.js",
@@ -96,7 +96,7 @@
]
},
"devDependencies": {
- "@author.io/arg": "^1.3.20",
+ "@author.io/arg": "^1.3.21",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
}
From dfd6123edde33a33246fa9728085b5533f43b6fc Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 20 Dec 2021 13:58:51 -0600
Subject: [PATCH 133/152] Update deploy script
---
.github/workflows/deploy.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index c1699dc..e038c4b 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -106,6 +106,7 @@ jobs:
if: steps.create_release.outputs.id != ''
run: |
ln -s /node_modules ./node_modules
+ npm i --prefix /node_modules
dev build --pack --mode ci --peer
cp -rf .dist ./dist
From fbddeea9c032ee6bdfc8af78ea767050787d9be2 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 20 Dec 2021 14:01:12 -0600
Subject: [PATCH 134/152] Update deploy script
---
.github/workflows/deploy.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index e038c4b..6833106 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -105,8 +105,8 @@ jobs:
id: build_release
if: steps.create_release.outputs.id != ''
run: |
+ npm i --prefix ./node_modules
ln -s /node_modules ./node_modules
- npm i --prefix /node_modules
dev build --pack --mode ci --peer
cp -rf .dist ./dist
From 6d2e9cf2ad8d7f1f905fb403c1cff660962325ce Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 20 Dec 2021 14:04:46 -0600
Subject: [PATCH 135/152] Update deploy script
---
.github/workflows/deploy.yml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 6833106..c1699dc 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -105,7 +105,6 @@ jobs:
id: build_release
if: steps.create_release.outputs.id != ''
run: |
- npm i --prefix ./node_modules
ln -s /node_modules ./node_modules
dev build --pack --mode ci --peer
cp -rf .dist ./dist
From b9c7022e2a9753089e2b710b34f04d7e214f9f63 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 20 Dec 2021 14:07:28 -0600
Subject: [PATCH 136/152] Update deploy script
---
.github/workflows/deploy.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index c1699dc..4231810 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -106,6 +106,8 @@ jobs:
if: steps.create_release.outputs.id != ''
run: |
ln -s /node_modules ./node_modules
+ ls -l /node_modules
+ ls -l /node_modules/@author.io
dev build --pack --mode ci --peer
cp -rf .dist ./dist
From feafc4264c9f4427456dde9004d4a1090277ea31 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 20 Dec 2021 14:11:03 -0600
Subject: [PATCH 137/152] Update deploy script
---
.github/workflows/deploy.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 4231810..17e994b 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -106,8 +106,8 @@ jobs:
if: steps.create_release.outputs.id != ''
run: |
ln -s /node_modules ./node_modules
- ls -l /node_modules
- ls -l /node_modules/@author.io
+ ls -l ./node_modules
+ ls -l ./node_modules/@author.io
dev build --pack --mode ci --peer
cp -rf .dist ./dist
From de45ba17a8ef43a72426260e2018f5e0e8c00188 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 20 Dec 2021 14:14:34 -0600
Subject: [PATCH 138/152] Update deploy script
---
.github/workflows/deploy.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 17e994b..15d7e24 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -105,6 +105,7 @@ jobs:
id: build_release
if: steps.create_release.outputs.id != ''
run: |
+ ls /node_modules
ln -s /node_modules ./node_modules
ls -l ./node_modules
ls -l ./node_modules/@author.io
From c6b40c5001b7533b1520178362e760ee3958aabb Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 20 Dec 2021 14:17:43 -0600
Subject: [PATCH 139/152] Update deploy script
---
.github/workflows/deploy.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 15d7e24..58b7165 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -109,7 +109,7 @@ jobs:
ln -s /node_modules ./node_modules
ls -l ./node_modules
ls -l ./node_modules/@author.io
- dev build --pack --mode ci --peer
+ dev build --pack --mode ci --peer -v "./node_modules:/node_modules"
cp -rf .dist ./dist
# Upload tarballs to the release.
From 1cb5b77f5cad43ce2f0fc9228db75d8ca8f9aab9 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 20 Dec 2021 14:23:19 -0600
Subject: [PATCH 140/152] Update deploy script
---
.github/workflows/deploy.yml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 58b7165..61ade0c 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -105,7 +105,6 @@ jobs:
id: build_release
if: steps.create_release.outputs.id != ''
run: |
- ls /node_modules
ln -s /node_modules ./node_modules
ls -l ./node_modules
ls -l ./node_modules/@author.io
From 901d44f6c535ac82acab69c11057a702ebbc0b71 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 20 Dec 2021 14:59:00 -0600
Subject: [PATCH 141/152] Update deploy script
---
.github/workflows/deploy.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 61ade0c..ac4eb35 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -105,7 +105,7 @@ jobs:
id: build_release
if: steps.create_release.outputs.id != ''
run: |
- ln -s /node_modules ./node_modules
+ ln -s ./node_modules /node_modules
ls -l ./node_modules
ls -l ./node_modules/@author.io
dev build --pack --mode ci --peer -v "./node_modules:/node_modules"
From b427e9b8a754d14bb5144d9fb6c9da23c60a3497 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 20 Dec 2021 15:02:25 -0600
Subject: [PATCH 142/152] Update deploy script
---
.github/workflows/deploy.yml | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index ac4eb35..4ffa3fd 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -105,10 +105,9 @@ jobs:
id: build_release
if: steps.create_release.outputs.id != ''
run: |
- ln -s ./node_modules /node_modules
- ls -l ./node_modules
- ls -l ./node_modules/@author.io
- dev build --pack --mode ci --peer -v "./node_modules:/node_modules"
+ ln -s ./node_modules /build_release/node_modules
+ ls -l ./build_release/@author.io
+ dev build --pack --mode ci --peer -v "/build_release/:/node_modules"
cp -rf .dist ./dist
# Upload tarballs to the release.
From dc27eabea2cd2683e5317dfedfbf91005c8f5f3b Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 20 Dec 2021 15:05:01 -0600
Subject: [PATCH 143/152] Update deploy script
---
.github/workflows/deploy.yml | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 4ffa3fd..52a56cb 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -105,9 +105,7 @@ jobs:
id: build_release
if: steps.create_release.outputs.id != ''
run: |
- ln -s ./node_modules /build_release/node_modules
- ls -l ./build_release/@author.io
- dev build --pack --mode ci --peer -v "/build_release/:/node_modules"
+ dev build --pack --mode ci --peer
cp -rf .dist ./dist
# Upload tarballs to the release.
From d380a228b49806a7032f31b34ff78fc461ee9b88 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Thu, 10 Feb 2022 18:29:16 -0600
Subject: [PATCH 144/152] shell.exec now returns promise/callback values.
Closes #9
---
dist/shell-debug/LICENSE | 21 +
dist/shell-debug/README.md | 5 +
dist/shell-debug/index.js.map | 1 +
dist/shell-debug/package.json | 52 ++
dist/shell/LICENSE | 21 +
dist/shell/README.md | 972 ++++++++++++++++++++++++++++++++++
dist/shell/index.js | 5 +
dist/shell/package.json | 84 +++
package-lock.json | 18 +-
package.json | 11 +-
src/command.js | 14 +-
src/shell.js | 7 +-
tests/100-regression.js | 36 ++
13 files changed, 1227 insertions(+), 20 deletions(-)
create mode 100644 dist/shell-debug/LICENSE
create mode 100644 dist/shell-debug/README.md
create mode 100644 dist/shell-debug/index.js.map
create mode 100644 dist/shell-debug/package.json
create mode 100644 dist/shell/LICENSE
create mode 100644 dist/shell/README.md
create mode 100644 dist/shell/index.js
create mode 100644 dist/shell/package.json
diff --git a/dist/shell-debug/LICENSE b/dist/shell-debug/LICENSE
new file mode 100644
index 0000000..166549b
--- /dev/null
+++ b/dist/shell-debug/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Author.io
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/dist/shell-debug/README.md b/dist/shell-debug/README.md
new file mode 100644
index 0000000..c26e24d
--- /dev/null
+++ b/dist/shell-debug/README.md
@@ -0,0 +1,5 @@
+# shell 1.8.18
+
+Please see [https://github.com/author/shell](https://github.com/author/shell).
+
+Generated on Tue Jan 04 2022 23:59:11 GMT+0000 (Coordinated Universal Time).
\ No newline at end of file
diff --git a/dist/shell-debug/index.js.map b/dist/shell-debug/index.js.map
new file mode 100644
index 0000000..828db20
--- /dev/null
+++ b/dist/shell-debug/index.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sources":["../../src/middleware.js","../../src/format.js","../../src/base.js","../../src/utility.js","../../src/shell.js","../../src/command.js","../../src/index.js"],"sourcesContent":["export default class Middleware {\n constructor () {\n Object.defineProperties(this, {\n _data: { enumerable: false, configurable: false, value: [] },\n go: { enumerable: false, configurable: false, writable: true, value: (...args) => { args.pop().apply(this, args) } }\n })\n }\n\n get size () { return this._data.length }\n\n get data () { return this._data }\n\n use (method) {\n const methodBody = method.toString()\n if (methodBody.indexOf('[native code]') < 0) {\n this._data.push(methodBody)\n }\n\n this.go = (stack => (...args) => {\n const next = args.pop()\n stack(...args, () => {\n method.apply(this, [...args, next.bind(null, ...args)])\n })\n })(this.go)\n }\n\n run () {\n const args = Array.from(arguments)\n if (args.length === 0 || typeof args[args.length - 1] !== 'function') {\n args.push(() => {})\n }\n\n this.go(...args)\n }\n}\n","import Table from '@author.io/table'\nimport Command from './command.js'\nimport Shell from './shell.js'\n\nclass Formatter {\n #data = null\n #tableWidth = 80\n #colAlign = [] // Defaults to ['l', 'l', 'l']\n #colWidth = ['20%', '15%', '65%']\n\n constructor (data) {\n this.#data = data\n }\n\n set width (value) {\n this.#tableWidth = value < 20 ? 20 : value\n }\n\n set columnWidths (value) {\n this.#colWidth = value\n }\n\n set columnAlignment (value) {\n this.#colAlign = value\n }\n\n get usage () {\n const desc = this.#data.description.trim()\n\n if (this.#data instanceof Command) {\n const aliases = this.#data.aliases\n const out = [`${this.#data.commandroot}${aliases.length > 0 ? '|' + aliases.join('|') : ''}${this.#data.__flagConfig.size > 0 ? ' [FLAGS]' : ''}${this.#data.arguments.size > 0 ? ' ' + Array.from(this.#data.arguments).map(i => '<' + i + '>').join(' ') : ''}`]\n\n if (this.#data.__processors.size > 0) {\n out[out.length - 1] += (this.#data.arguments.size > 0 || this.#data.__flagConfig.size > 0 ? ' |' : '') + ' [COMMAND]'\n }\n\n if (desc.trim().length > 0 && out !== desc) {\n out.push(new Table([[desc.trim().replace(/\\n/gi, '\\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output)\n }\n\n return out.join('\\n')\n } else if (this.#data instanceof Shell) {\n return `${this.#data.name}${this.#data.__processors.size > 0 ? ' [COMMAND]' : ''}\\n${desc.trim().length > 0 ? new Table([[desc.trim().replace(/\\n/gi, '\\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output : ''}${this.#data.arguments.size > 0 ? ' ' + Array.from(this.#data.arguments).map(i => '[' + i + ']').join(' ') : ''}\\n`.trim()\n }\n\n return ''\n }\n\n get subcommands () {\n const rows = Array.from(this.#data.__processors.values()).map(cmd => {\n const nm = [cmd.name].concat(cmd.aliases)\n return [nm.join('|'), cmd.description]\n })\n\n const result = []\n\n if (rows.length > 0) {\n const table = new Table(rows, this.#colAlign, ['25%', '75%'], this.#tableWidth, [2])\n result.push('\\nCommands:\\n')\n result.push(table.output)\n }\n\n return result.join('\\n')\n }\n\n get help () {\n const usage = this.usage.trim()\n\n if (this.#data instanceof Command) {\n const flags = this.#data.__flagConfig\n const rows = []\n\n if (flags.size > 0) {\n flags.forEach((cfg, flag) => {\n let aliases = Array.from(cfg.aliases || cfg.alias || [])\n aliases = aliases.length === 0 ? '' : '[' + aliases.map(a => `-${a}`).join(', ') + ']'\n\n let dsc = [cfg.description || '']\n\n if (cfg.hasOwnProperty('options') && this.#data.describeOptions) { // eslint-disable-line no-prototype-builtins\n dsc.push(`Options: ${cfg.options.join(', ')}.`)\n }\n\n if (cfg.hasOwnProperty('allowMultipleValues') && cfg.allowMultipleValues === true && this.#data.describeMultipleValues) { // eslint-disable-line no-prototype-builtins\n dsc.push('Can be used multiple times.')\n }\n\n if (cfg.hasOwnProperty('default') && this.#data.describeDefault) { // eslint-disable-line no-prototype-builtins\n dsc.push(`(Default: ${cfg.default.toString()})`)\n }\n\n if (cfg.hasOwnProperty('required') && cfg.required === true && this.#data.describeRequired) { // eslint-disable-line no-prototype-builtins\n dsc.unshift('Required.')\n }\n\n dsc = dsc.join(' ').trim()\n\n rows.push(['--' + flag, aliases || '', dsc || ''])\n })\n }\n\n const table = new Table(rows, this.#colAlign, this.#colWidth, this.#tableWidth, [2, 0, usage.length > 0 ? 1 : 0, 0])\n\n let subcommands = '\\n' + this.subcommands\n if (subcommands.trim().length === 0) {\n subcommands = ''\n }\n return usage + (flags.size > 0 ? '\\n\\nFlags:\\n' + table.output : '') + subcommands\n } else if (this.#data instanceof Shell) {\n return [usage, this.subcommands].join('\\n')\n }\n\n return ''\n }\n}\n\nexport { Formatter as default, Formatter, Table }\n","import Middleware from './middleware.js'\nimport Formatter from './format.js'\nimport Shell from './shell.js'\nimport Command from './command.js'\n\nexport default class Base {\n #plugins = {}\n #url = null\n #support = null\n #formattedDefaultHelp\n #description\n #customUsage\n #customHelp\n #arguments = new Set()\n #autohelp = true\n #processors = new Map()\n #commands = new Map()\n #width = 80\n #name = 'Unknown'\n #middleware = new Middleware()\n #trailer = new Middleware()\n #commonflags = {}\n #display = {\n // These are all null, representing they're NOT configured.\n Default: null,\n Options: null,\n MultipleValues: null,\n Required: null\n }\n\n #hasCustomDefaultHandler = false\n\n #defaultHandler = function (meta) {\n if (this.parent !== null && this.parent.hasCustomDefaultHandler) {\n return this.parent.defaultHandler(...arguments)\n } else if (this.shell && this.shell !== null && this.shell.hasCustomDefaultHandler) {\n return this.shell.defaultHandler(...arguments)\n }\n\n if (this.#autohelp) {\n console.log(this.help)\n }\n }\n\n constructor (cfg = {}) {\n if (typeof cfg !== 'object') {\n throw new Error('Invalid command configuration. Expected an object.')\n }\n\n if (!cfg.hasOwnProperty('name')) { // eslint-disable-line no-prototype-builtins\n throw new Error('Invalid command configuration. A \"name\" attribute is required.')\n }\n\n if (cfg.hasOwnProperty('help')) { // eslint-disable-line no-prototype-builtins\n this.#customHelp = cfg.help\n }\n\n if (cfg.hasOwnProperty('usage')) { // eslint-disable-line no-prototype-builtins\n this.#customUsage = cfg.usage\n }\n\n if (cfg.hasOwnProperty('disablehelp') && !cfg.hasOwnProperty('disableHelp')) { // eslint-disable-line no-prototype-builtins\n cfg.disableHelp = cfg.disablehelp\n }\n\n if (cfg.hasOwnProperty('disableHelp') && cfg.disableHelp === true) { // eslint-disable-line no-prototype-builtins\n this.#autohelp = false\n }\n\n if (typeof cfg.help === 'function' || typeof cfg.help === 'string') {\n this.help = cfg.help\n }\n\n if (typeof cfg.usage === 'function' || typeof cfg.usage === 'string') {\n this.usage = cfg.usage\n }\n\n if (cfg.hasOwnProperty('defaultHandler') && cfg.defaultHandler.toString() !== this.#defaultHandler.toString()) { // eslint-disable-line no-prototype-builtins\n this.defaultHandler = cfg.defaultHandler\n }\n\n if (typeof cfg.arguments === 'string') {\n cfg.arguments = cfg.arguments.split(/\\s+|\\t+|\\,+|\\;+/).map(arg => arg.trim()) // eslint-disable-line no-useless-escape\n }\n\n if (Array.isArray(cfg.arguments)) {\n this.#arguments = new Set(cfg.arguments)\n }\n\n if (typeof cfg.url === 'string') {\n this.#url = cfg.url\n }\n\n if (typeof cfg.support === 'string') {\n this.#support = cfg.support\n }\n\n this.#name = (cfg.name || 'unknown').trim().split(/\\s+/)[0]\n this.#description = cfg.description || null\n\n if (Array.isArray(cfg.commands)) {\n cfg.commands.forEach(cmd => this.add(cmd))\n } else if (typeof cfg.commands === 'object') {\n for (const key in cfg.commands) {\n const data = cfg.commands[key]\n data.name = key\n this.add(data)\n }\n }\n\n if (cfg.hasOwnProperty('middleware')) { // eslint-disable-line no-prototype-builtins\n console.warn('The \"middleware\" attribute has been replaced with the \"use\" attribute.')\n cfg.use = cfg.middleware\n delete cfg.middleware\n }\n\n if (!cfg.hasOwnProperty('commonflag')) { // eslint-disable-line no-prototype-builtins\n if (cfg.hasOwnProperty('commonFlag')) { // eslint-disable-line no-prototype-builtins\n cfg.commonflag = cfg.commonFlag\n } else if (cfg.hasOwnProperty('commonflags')) { // eslint-disable-line no-prototype-builtins\n cfg.commonflag = cfg.commonflags\n } else if (cfg.hasOwnProperty('commonFlag')) { // eslint-disable-line no-prototype-builtins\n cfg.commonflag = cfg.commonFlag\n } else if (cfg.hasOwnProperty('commonFlags')) { // eslint-disable-line no-prototype-builtins\n cfg.commonflag = cfg.commonFlags\n }\n }\n\n if (cfg.hasOwnProperty('commonflag')) { // eslint-disable-line no-prototype-builtins\n if (typeof cfg.commonflag !== 'object') {\n throw new Error('The \"commonflag\" configuration attribute must be an object.')\n }\n }\n\n if (typeof cfg.plugins === 'object') {\n this.#plugins = cfg.plugins\n }\n\n Object.defineProperties(this, {\n __processors: {\n enumerable: false,\n get () {\n return this.#processors\n }\n },\n __commands: {\n enumerable: false,\n get () {\n return this.#commands\n }\n },\n __width: {\n enumerable: false,\n get () {\n return this.#width\n },\n set (v) {\n this.#width = v || 80\n }\n },\n __commonflags: {\n enumerable: false,\n get () {\n return this.#commonflags\n },\n set (value) {\n this.#commonflags = value\n }\n },\n arguments: {\n enumerable: false,\n get () {\n return this.#arguments\n }\n },\n initializeMiddleware: {\n enumerable: false,\n configurable: false,\n writable: false,\n value: code => {\n if (typeof code === 'string') {\n this.use(Function('return ' + code)()) // eslint-disable-line no-new-func\n } else if (typeof code === 'function') {\n this.use(code)\n } else {\n throw new Error('Invalid middleware: ' + code.toString())\n }\n }\n },\n initializeTrailer: {\n enumerable: false,\n configurable: false,\n writable: false,\n value: code => {\n if (typeof code === 'string') {\n this.trailer(Function('return ' + code)()) // eslint-disable-line no-new-func\n } else if (typeof code === 'function') {\n this.trailer(code)\n } else {\n throw new Error('Invalid trailer: ' + code.toString())\n }\n }\n },\n initializeHelpAnnotations: {\n enumerable: false,\n configurable: false,\n writable: false,\n value: cfg => {\n if (cfg.hasOwnProperty('describeDefault') && typeof cfg.describeDefault === 'boolean') { // eslint-disable-line no-prototype-builtins\n this.#display.Default = cfg.describeDefault\n }\n if (cfg.hasOwnProperty('describeOptions') && typeof cfg.describeOptions === 'boolean') { // eslint-disable-line no-prototype-builtins\n this.#display.Options = cfg.describeOptions\n }\n if (cfg.hasOwnProperty('describeMultipleValues') && typeof cfg.describeMultipleValues === 'boolean') { // eslint-disable-line no-prototype-builtins\n this.#display.MultipleValues = cfg.describeMultipleValues\n }\n if (cfg.hasOwnProperty('describeRequired') && typeof cfg.describeRequired === 'boolean') { // eslint-disable-line no-prototype-builtins\n this.#display.Required = cfg.describeRequired\n }\n }\n }\n })\n\n this.updateHelp()\n }\n\n get plugins () {\n return this.#plugins\n }\n\n // @readonly\n get name () {\n return this.#name || 'Unknown'\n }\n\n // @readonly\n get description () {\n return this.#description || this.usage || ''\n }\n\n // @readonly\n get url () {\n return this.URL\n }\n\n // @readonly\n get URL () {\n const uri = (this.#url || '').trim()\n\n if (uri.length === 0) {\n if (this.hasOwnProperty('parent')) { // eslint-disable-line no-prototype-builtins\n return this.parent.URL\n } else if (this instanceof Command) {\n return this.shell.URL\n }\n }\n\n return uri\n }\n\n // @readonly\n get support () {\n const support = (this.#support || '').trim()\n\n if (support.length === 0) {\n if (this.hasOwnProperty('parent')) { // eslint-disable-line no-prototype-builtins\n return this.parent.support\n } else if (this instanceof Command) {\n return this.shell.support\n }\n }\n\n return support\n }\n\n get autohelp () {\n return this.#autohelp\n }\n\n set autohelp (value) {\n if (typeof value !== 'boolean') {\n return\n }\n this.#autohelp = value\n this.#processors.forEach(cmd => { cmd.autohelp = value })\n }\n\n updateHelp () {\n this.#formattedDefaultHelp = new Formatter(this)\n this.#formattedDefaultHelp.width = this.#width\n }\n\n describeHelp (attr, prop) {\n if (this.#display[prop] !== null) {\n return this.#display[prop]\n }\n\n if (this instanceof Command) {\n if (this.shell && this.shell !== null && this.shell[attr] !== null) {\n return this.shell[attr]\n }\n\n if (this.parent !== null) {\n return this.parent[attr]\n }\n }\n\n return true\n }\n\n get describeDefault () {\n return this.describeHelp('describeDefault', 'Default')\n }\n\n get describeOptions () {\n return this.describeHelp('describeOptions', 'Options')\n }\n\n get describeMultipleValues () {\n return this.describeHelp('describeMultipleValues', 'MultipleValues')\n }\n\n get describeRequired () {\n return this.describeHelp('describeRequired', 'Required')\n }\n\n get usage () {\n if (this.#customUsage !== null) {\n return typeof this.#customUsage === 'function' ? this.#customUsage() : this.#customUsage\n }\n\n return this.#formattedDefaultHelp.usage\n }\n\n set usage (value) {\n if (typeof value === 'string' && value.trim().length === 0) {\n value = null\n }\n\n this.#customUsage = value\n\n this.updateHelp()\n }\n\n get help () {\n if (this.#customHelp) {\n return typeof this.#customHelp === 'function' ? this.#customHelp(this) : this.#customHelp\n }\n\n if (!this.autohelp) {\n return ''\n }\n\n return this.#formattedDefaultHelp.help\n }\n\n set help (value) {\n if (typeof value === 'string' && value.trim().length === 0) {\n value = null\n }\n\n this.#customHelp = value\n\n this.updateHelp()\n }\n\n // @private\n set defaultHandler (value) {\n if (typeof value === 'function') {\n this.#defaultHandler = value\n this.#hasCustomDefaultHandler = true\n this.#processors.forEach(cmd => { cmd.defaultProcessor = value })\n } else {\n throw new Error(`Invalid default method (must be a function, not \"${typeof value}\").`)\n }\n }\n\n get defaultHandler () {\n return this.#defaultHandler\n }\n\n // @private\n get hasCustomDefaultHandler () {\n return this.#hasCustomDefaultHandler\n }\n\n get data () {\n const commands = {}\n\n Array.from(this.#processors.values()).forEach(cmd => {\n const data = cmd.data\n const name = data.name\n delete data.name\n commands[name] = data\n })\n\n return commands\n }\n\n get middleware () {\n return this.#middleware\n }\n\n get trailers () {\n return this.#trailer\n }\n\n get commands () {\n return this.#processors\n }\n\n get commandlist () {\n const list = new Set()\n this.commands.forEach(cmd => {\n list.add(cmd.name)\n cmd.commandlist.forEach(subcmd => list.add(`${cmd.name} ${subcmd}`))\n })\n\n return Array.from(list).sort()\n }\n\n getCommand (name = null) {\n if (!name) {\n return null\n }\n\n const names = name.split(/\\s+/i)\n let cmd = this.#commands.get(names.shift())\n if (cmd) {\n cmd = this.#processors.get(cmd)\n for (const nm of names) {\n cmd = cmd.getCommand(nm)\n }\n }\n\n return cmd instanceof Command ? cmd : null\n }\n\n remove () {\n for (const cmd of arguments) {\n if (typeof cmd === 'symbol') {\n this.#processors.delete(cmd)\n this.#commands.forEach(oid => oid === cmd && this.#commands.delete(oid))\n }\n\n if (typeof cmd === 'string') {\n const OID = this.#commands.get(cmd)\n if (OID) {\n this.remove(OID)\n }\n }\n }\n }\n\n use () {\n for (const arg of arguments) {\n if (typeof arg !== 'function') {\n throw new Error(`All \"use()\" arguments must be valid functions.\\n${arg.toString().substring(0, 50)} ${arg.toString().length > 50 ? '...' : ''}`)\n }\n\n this.#middleware.use(arg)\n }\n\n this.#processors.forEach(subCmd => subCmd.use(...arguments))\n }\n\n trailer () {\n this.#trailer = this.#trailer || new Middleware()\n\n for (const arg of arguments) {\n if (typeof arg !== 'function') {\n throw new Error(`All \"trailer()\" arguments must be valid functions.\\n${arg.toString().substring(0, 50)} ${arg.toString().length > 50 ? '...' : ''}`)\n }\n\n this.#trailer.use(arg)\n }\n\n this.#processors.forEach(subCmd => subCmd.trailer(...arguments))\n }\n\n add () {\n for (let command of arguments) {\n if (!(command instanceof Command)) {\n if (typeof command === 'object') {\n command = new Command(command)\n } else {\n throw new Error('Invalid argument. Only \"Command\" instances may be added to the processor.')\n }\n }\n\n command.autohelp = this.autohelp\n\n if (this instanceof Shell) {\n command.shell = this\n } else if (this instanceof Command) {\n command.parent = this\n }\n\n this.#processors.set(command.OID, command)\n this.#commands.set(command.name, command.OID)\n\n command.aliases.forEach(alias => this.#commands.set(alias, command.OID))\n }\n }\n}\n","// const STRIP_EQUAL_SIGNS = /(\\=+)(?=([^'\"\\\\]*(\\\\.|['\"]([^'\"\\\\]*\\\\.)*[^'\"\\\\]*['\"]))*[^'\"]*$)/g\n\nconst SUBCOMMAND_PATTERN = /^([^\"'][\\S\\b]+)[\\s+]?([^-].*)$/i // eslint-disable-line no-useless-escape\nconst FLAG_PATTERN = /((?:\"[^\"\\\\]*(?:\\\\[\\S\\s][^\"\\\\]*)*\"|'[^'\\\\]*(?:\\\\[\\S\\s][^'\\\\]*)*'|\\/[^\\/\\\\]*(?:\\\\[\\S\\s][^\\/\\\\]*)*\\/[gimy]*(?=\\s|$)|(?:\\\\\\s|\\S))+)(?=\\s|$)/g // eslint-disable-line no-useless-escape\nconst METHOD_PATTERN = /^([\\w]+\\s?)\\(.*\\)\\s?{/i // eslint-disable-line no-useless-escape\nconst STRIP_QUOTE_PATTERN = /\"([^\"\\\\]*(\\\\.[^\"\\\\]*)*)\"|\\'([^\\'\\\\]*(\\\\.[^\\'\\\\]*)*)\\'/ig // eslint-disable-line no-useless-escape\nconst COMMAND_PATTERN = /^(\\w+)\\s+([\\s\\S]+)?/i // eslint-disable-line no-useless-escape\nconst CONSTANTS = Object.freeze({\n SUBCOMMAND_PATTERN,\n FLAG_PATTERN,\n METHOD_PATTERN,\n STRIP_QUOTE_PATTERN,\n COMMAND_PATTERN\n})\n\nexport {\n CONSTANTS as default,\n CONSTANTS,\n SUBCOMMAND_PATTERN,\n FLAG_PATTERN,\n METHOD_PATTERN,\n STRIP_QUOTE_PATTERN,\n COMMAND_PATTERN\n}\n","import Command from './command.js'\nimport Base from './base.js'\nimport { COMMAND_PATTERN } from './utility.js'\n\nexport default class Shell extends Base {\n #middlewareGroups = new Map()\n #history = []\n #maxHistoryItems\n #version\n #cursor = 0\n #tabWidth\n #runtime = globalThis.hasOwnProperty('window') // eslint-disable-line no-prototype-builtins\n ? 'browser'\n : (\n globalThis.hasOwnProperty('process') && // eslint-disable-line no-prototype-builtins\n globalThis.process.release &&\n globalThis.process.release.name\n ? globalThis.process.release.name\n : 'unknown'\n )\n\n constructor (cfg = { maxhistory: 100 }) {\n super(cfg)\n\n this.initializeHelpAnnotations(cfg)\n\n this.__commonflags = cfg.commonflags || {}\n\n if (cfg.hasOwnProperty('use') && Array.isArray(cfg.use)) { // eslint-disable-line no-prototype-builtins\n cfg.use.forEach(code => this.initializeMiddleware(code))\n }\n\n if (cfg.hasOwnProperty('trailer') && Array.isArray(cfg.trailer)) { // eslint-disable-line no-prototype-builtins\n cfg.trailer.forEach(code => this.initializeTrailer(code))\n }\n\n this.#version = cfg.version || '1.0.0'\n this.#maxHistoryItems = cfg.maxhistory || cfg.maxHistoryItems || 100\n this.#tabWidth = cfg.hasOwnProperty('tabWidth') ? cfg.tabWidth : 4 // eslint-disable-line no-prototype-builtins\n\n // This sets a global symbol that dev tools can find.\n globalThis[Symbol('SHELL_INTEGRATIONS')] = this\n }\n\n get data () {\n const commands = super.data\n\n return {\n name: this.name,\n description: this.description,\n version: this.version,\n commands,\n use: this.middleware.data,\n trailer: this.trailers.data,\n help: this.help,\n usage: this.usage,\n defaultHandler: this.defaultHandler.toString(),\n disableHelp: !this.autohelp,\n runtime: this.#runtime,\n maxHistoryItems: this.#maxHistoryItems\n }\n }\n\n get version () {\n return this.#version || 'Unknown'\n }\n\n set tableWidth (value) {\n this.__width = value\n }\n\n get tableWidth () {\n return this.__width\n }\n\n history (count = null) {\n if (this.#history.length === 0) {\n return []\n }\n\n return count === null ? this.#history.slice() : this.#history.slice(0, count)\n }\n\n priorCommand (count = 0) {\n if (this.#history.length === 0) {\n return null\n }\n\n if (count < 0) {\n return this.nextCommand(Math.abs(count))\n }\n\n count = count % this.#history.length\n\n this.#cursor += count\n\n if (this.#cursor >= this.#history.length) {\n this.#cursor = this.#history.length - 1\n }\n\n return this.#history[this.#cursor].input\n }\n\n nextCommand (count = 1) {\n if (this.#history.length === 0) {\n return null\n }\n\n if (count < 0) {\n return this.priorCommand(Math.abs(count))\n }\n\n count = count % this.#history.length\n\n this.#cursor -= count\n if (this.#cursor < 0) {\n this.#cursor = 0\n return undefined\n }\n\n return this.#history[this.#cursor].input\n }\n\n useWith (commands) {\n if (arguments.length < 2) {\n throw new Error('useWith([\\'command\\', \\'command\\'], fn) requires two or more arguments.')\n }\n\n commands = typeof commands === 'string' ? commands.split(/\\s+/) : commands\n\n if (!Array.isArray(commands) || commands.filter(c => typeof c !== 'string').length > 0) {\n throw new Error(`The first argument of useWith must be a string or array of strings. Received ${typeof commands}`)\n }\n\n const fns = Array.from(arguments).slice(1)\n\n commands.forEach(cmd => this.#middlewareGroups.set(cmd.trim(), (this.#middlewareGroups.get(cmd.trim()) || []).concat(fns)))\n }\n\n useExcept (commands) {\n if (arguments.length < 2) {\n throw new Error('useExcept([\\'command\\', \\'command\\'], fn) requires two or more arguments.')\n }\n\n commands = typeof commands === 'string' ? commands.split(/\\s+/) : commands\n\n if (!Array.isArray(commands) || commands.filter(c => typeof c !== 'string').length > 0) {\n throw new Error(`The first argument of useExcept must be a string or array of strings. Received ${typeof commands}`)\n }\n\n const fns = Array.from(arguments).slice(1)\n const all = new Set(this.commandlist.map(i => i.toLowerCase()))\n\n commands.forEach(cmd => {\n all.delete(cmd)\n for (const c of all) {\n if (c.indexOf(cmd) === 0) {\n all.delete(c)\n }\n }\n })\n\n this.useWith(Array.from(all), ...fns)\n }\n\n async exec (input, callback) {\n // The array check exists because people are passing process.argv.slice(2) into this\n // method, often forgetting to join the values into a string.\n if (Array.isArray(input)) {\n input = input.map(i => {\n if (i.indexOf(' ') >= 0 && !/^[\\\"\\'].+ [\\\"\\']$/.test(i)) {\n return `\"${i}\"`\n } else {\n return i\n }\n }).join(' ')\n }\n\n this.#history.unshift({ input, time: new Date().toLocaleString() })\n\n if (this.#history.length > this.#maxHistoryItems) {\n this.#history.pop()\n }\n\n let parsed = COMMAND_PATTERN.exec(input + ' ')\n\n if (parsed === null) {\n if (input.indexOf('version') !== -1 || input.indexOf('-v') !== -1) {\n return console.log(this.version)\n } else if (input.indexOf('help') !== -1) {\n return console.log(this.help)\n }\n\n return Command.stderr(this.help)\n }\n\n parsed = parsed.filter(item => item !== undefined)\n\n const cmd = parsed[1]\n const args = parsed.length > 2 ? parsed[2] : ''\n // const command = null\n\n const action = this.__commands.get(cmd)\n\n if (!action) {\n if (cmd.toLowerCase() === 'version') {\n return console.log(this.version)\n }\n\n return Command.stderr(this.help)\n }\n\n const processor = this.__processors.get(action)\n\n if (!processor) {\n return Command.stderr('Command not found.')\n }\n\n const term = processor.getTerminalCommand(args)\n return await Command.reply(await term.command.run(term.arguments, callback))\n }\n\n getCommandMiddleware (cmd) {\n const results = []\n cmd.split(/\\s+/).forEach((c, i, a) => {\n const r = this.#middlewareGroups.get(a.slice(0, i + 1).join(' '))\n r && results.push(r.flat(Infinity))\n })\n\n return results.flat(Infinity)\n }\n\n clearHistory () {\n this.#history = []\n }\n\n // Clear the terminal\n clear () {\n this.#history = []\n console.clear()\n // .write('\\x1b[0f') // regular clear\n // .write('\\x1b[2J') // full clear\n // .write('\\033[0;0f') //ubuntu\n }\n}\n","// import { Parser } from '../../../@author.io/arg/index.js'\nimport { Parser } from '@author.io/arg'\nimport Shell from './shell.js'\nimport Base from './base.js'\nimport { METHOD_PATTERN, FLAG_PATTERN, STRIP_QUOTE_PATTERN } from './utility.js'\n\nexport default class Command extends Base {\n #pattern\n #oid\n #aliases = new Set()\n #fn\n #flagConfig = {}\n #parent = null\n #shell = null\n\n constructor (cfg = {}) {\n if (cfg.hasOwnProperty('handler')) { // eslint-disable-line no-prototype-builtins\n if (typeof cfg.handler === 'string') {\n cfg.handler = Function('return (' + cfg.handler.replace('function anonymous', 'function') + ').call(this)').call(globalThis) // eslint-disable-line no-new-func\n }\n\n if (typeof cfg.handler !== 'function') {\n throw new Error('Invalid command configuration. A \"handler\" function is required.')\n }\n }\n\n super(cfg)\n\n if (cfg.hasOwnProperty('use') && Array.isArray(cfg.use)) { // eslint-disable-line no-prototype-builtins\n cfg.use.forEach(code => this.initializeMiddleware(code))\n }\n\n if (cfg.hasOwnProperty('trailer') && Array.isArray(cfg.trailer)) { // eslint-disable-line no-prototype-builtins\n cfg.trailer.forEach(code => this.initializeTrailer(code))\n }\n\n this.initializeHelpAnnotations(cfg)\n\n this.#fn = cfg.handler\n this.#oid = Symbol(((cfg.name || cfg.usage) || cfg.pattern) || 'command')\n this.#pattern = cfg.pattern || /[\\s\\S]+/i\n\n if (cfg.alias && !cfg.aliases) {\n cfg.aliases = typeof cfg.alias === 'string' ? [cfg.alias] : (Array.isArray(cfg.alias) ? cfg.alias : Array.from(cfg.alias))\n delete cfg.alias\n }\n\n if (cfg.aliases) {\n if (!Array.isArray(cfg.aliases)) {\n throw new Error('The alias property only accepts an array.')\n }\n\n this.#aliases = new Set(cfg.aliases)\n }\n\n if (cfg.flags) {\n if (typeof cfg.flags !== 'object') {\n throw new Error(`Invalid flag configuration (expected and object, received ${typeof cfg.flags}).`)\n }\n\n for (const [key, value] of Object.entries(cfg.flags)) {\n if (value.hasOwnProperty('alias')) { // eslint-disable-line no-prototype-builtins\n value.aliases = value.aliases || []\n\n if (Array.isArray(value.alias)) {\n value.aliases = Array.from(new Set(...value.aliases, ...value.alias))\n if (value.aliases.filter(a => typeof a !== 'string') > 0) {\n throw new Error(`${key} flag aliases must be strings. Type failure on: ${value.aliases.filter(a => typeof a !== 'string').join(', ')}.`)\n }\n } else if (typeof value.alias === 'string') {\n value.aliases.push(value.alias)\n } else {\n throw new Error(`Aliases must be strings, not ${typeof value.alias} (${key} flag).`)\n }\n\n delete value.alias\n }\n }\n\n this.#flagConfig = cfg.flags\n }\n\n if (Array.isArray(cfg.subcommands)) {\n this.add(...cfg.subcommands)\n }\n\n const attributes = new Set([\n 'commands',\n 'subcommands',\n 'plugins',\n 'defaultHandler',\n 'disableHelp',\n 'describeDefault',\n 'describeOptions',\n 'describeMultipleValues',\n 'describeRequired',\n 'flags',\n 'alias',\n 'aliases',\n 'description',\n 'help',\n 'usage',\n 'pattern',\n 'name',\n 'handler',\n 'middleware',\n 'use',\n 'arguments',\n 'commonflag',\n 'commonflags',\n 'trailer',\n 'url',\n 'support'\n ])\n\n const unrecognized = Object.keys(cfg).filter(attribute => !attributes.has(attribute))\n\n if (unrecognized.length > 0) {\n throw new Error(`Unrecognized configuration attribute(s): ${unrecognized.join(', ')}`)\n }\n\n const ignoreFlags = commonFlags => {\n if (commonFlags.ignore && (Array.isArray(commonFlags.ignore) || typeof commonFlags.ignore === 'string')) {\n const ignore = new Set(Array.isArray(commonFlags.ignore) ? commonFlags.ignore : [commonFlags.ignore])\n // delete commonFlags.ignore\n const root = this.commandroot.replace(new RegExp(`^${this.shell.name}\\\\s+`, 'i'), '')\n\n for (const cmd of ignore) {\n if (root.startsWith(cmd)) {\n commonFlags = {}\n break\n }\n }\n }\n\n return commonFlags\n }\n\n Object.defineProperties(this, {\n __commonFlags: {\n enumerable: false,\n get () {\n let flags = ignoreFlags(this.__commonflags) // Object.assign({}, this.__commonflags, this.#flagConfig)\n\n if (this.parent !== null) {\n flags = Object.assign(flags, this.parent.__commonFlags)\n }\n\n const result = Object.assign({}, this.shell !== null ? ignoreFlags(this.shell.__commonflags) : {}, flags)\n\n if (Array.isArray(result.ignore) || typeof result.ignore === 'string') {\n delete result.ignore\n }\n\n return result\n }\n },\n __flagConfig: {\n enumerable: false,\n get () {\n const flags = new Map(Object.entries(Object.assign(this.__commonFlags, this.#flagConfig || {})))\n flags.delete('help')\n return flags\n }\n },\n getTerminalCommand: {\n enumerable: false,\n configurable: false,\n writable: false,\n value: input => {\n const args = input.trim().split(/\\t+|\\s+/)\n let cmd = this\n\n while (args.length > 0) {\n const arg = args[0]\n const subcmd = cmd.getCommand(arg)\n if (subcmd) {\n cmd = subcmd\n args.shift()\n } else {\n break\n }\n }\n\n return {\n command: cmd,\n arguments: args.join(' ')\n }\n }\n }\n })\n\n this.__commonflags = cfg.commonflags || {}\n\n this.__width = this.shell === null ? 80 : this.shell.tableWidth || 80\n\n this.updateHelp()\n }\n\n get data () {\n const commands = super.data\n\n let handler = (this.#fn || this.defaultHandler).toString()\n if (METHOD_PATTERN.test(handler)) {\n handler = handler.replace(METHOD_PATTERN.exec(handler)[1], 'function ')\n }\n\n const flags = Object.assign(this.__commonFlags, this.#flagConfig || {})\n\n for (const [key, value] of Object.entries(flags)) { // eslint-disable-line no-unused-vars\n value.aliases = value.aliases || []\n\n if (value.hasOwnProperty('alias')) { // eslint-disable-line no-prototype-builtins\n if (value.aliases.indexOf(value.alias) < 0) {\n value.aliases.push(value.alias)\n }\n }\n\n delete value.alias\n }\n\n // Apply any missing default values to flags.\n Object.keys(flags).forEach(name => { flags[name] = Object.assign(this.getFlagConfiguration(name), flags[name]) })\n\n const data = {\n name: this.name,\n description: this.description,\n help: this.help,\n usage: this.usage,\n aliases: Array.from(this.#aliases),\n flags,\n handler,\n commands,\n disableHelp: !this.autohelp,\n use: this.middleware.data,\n trailer: this.trailers.data\n }\n\n for (const [key, value] of Object.entries(data.flags)) { // eslint-disable-line no-unused-vars\n delete value.alias\n }\n\n return data\n }\n\n set parent (cmd) {\n if (cmd instanceof Command) {\n this.#parent = cmd\n } else {\n throw new Error(`Cannot set parent of \"${this.name}\" command to anything other than another command. To make this command a direct descendent of the main shell, use the shell attribute instead.`)\n }\n }\n\n get parent () {\n return this.#parent\n }\n\n set shell (shell) {\n if (!shell) {\n throw new Error(`Cannot set shell of ${this.name} command to a non-Shell object.`)\n }\n if (shell instanceof Shell) {\n this.#shell = shell\n this.__width = this.shell === null ? 80 : shell.tableWidth\n } else {\n throw new Error(`Expected a Shell object, received a \"${typeof shell}\" object.`)\n }\n }\n\n get shell () {\n if (!this.#shell) {\n if (this.#parent) {\n return this.#parent.shell\n }\n\n return null\n }\n\n return this.#shell\n }\n\n get plugins () {\n return Object.assign({}, this.shell.plugins, this.parent ? this.parent.plugins : {}, super.plugins)\n }\n\n get commandroot () {\n if (this.#parent) {\n return `${this.#parent.commandroot} ${this.name}`.trim()\n }\n\n if (this.#shell) {\n return `${this.#shell.name} ${this.name}`.trim()\n }\n\n return this.name\n }\n\n set aliases (value) {\n if (!value) {\n this.#aliases = []\n return\n }\n\n if (typeof value === 'object') {\n switch (value.constructor.name.toLowerCase()) {\n case 'map':\n value = Array.from(value.keys())\n break\n case 'set':\n value = Array.from(value)\n break\n case 'object':\n value = Object.keys(value).filter(item => typeof item === 'string')\n break\n case 'array':\n break\n case 'string':\n value = value.split(/\\s+/)[0]\n break\n default:\n throw new Error('Invalid alias value. Use an array of strings.')\n }\n }\n\n this.#aliases = Array.from(new Set(value)) // This conversion deduplicates the value\n }\n\n get aliases () {\n return Array.from(this.#aliases) || []\n }\n\n get OID () {\n return this.#oid\n }\n\n addFlag (name, cfg) {\n if (typeof name !== 'string') {\n if (!cfg.hasOwnProperty('name')) { // eslint-disable-line no-prototype-builtins\n throw new Error('Invalid flag name (should be a string).')\n } else {\n name = cfg.name\n }\n }\n\n this.#flagConfig[name] = cfg\n }\n\n removeFlag (name) {\n delete this.#flagConfig[name]\n }\n\n getFlagConfiguration (name) {\n let flag = this.__flagConfig.get(name)\n if (!flag) {\n for (const [f, cfg] of this.__flagConfig) { // eslint-disable-line no-unused-vars\n if ((cfg.aliases && cfg.aliases.indexOf(name) >= 0) || (cfg.alias && cfg.alias === flag)) {\n flag = cfg\n break\n }\n }\n\n if (!flag) {\n return null\n }\n }\n\n return {\n description: flag.description,\n required: flag.hasOwnProperty('required') ? flag.required : false, // eslint-disable-line no-prototype-builtins\n aliases: flag.aliases || [flag.alias].filter(i => i !== null),\n type: flag.type === undefined ? 'string' : (typeof flag.type === 'string' ? flag.type : flag.type.name.toLowerCase()),\n options: flag.hasOwnProperty('options') ? flag.options : null, // eslint-disable-line no-prototype-builtins\n allowMultipleValues: flag.hasOwnProperty('allowMultipleValues') ? flag.allowMultipleValues : false // eslint-disable-line no-prototype-builtins\n }\n }\n\n supportsFlag (name) {\n return this.#flagConfig.hasOwnProperty(name) // eslint-disable-line no-prototype-builtins\n }\n\n deepParse (input) {\n const meta = this.parse(input)\n\n if (this.__commands.size === 0) {\n return meta\n }\n\n if (meta.input.trim().length === 0) {\n return meta\n }\n\n const args = meta.input.split(/\\s+/)\n const subcmd = this.__commands.get(args.shift())\n\n if (!subcmd) {\n return meta\n }\n\n return this.__processors.get(subcmd).deepParse(args.join(' '))\n }\n\n parse (input) {\n // Parse the command input for flags\n const data = { command: this.name, input: input.trim() }\n const flagConfig = Object.assign(this.__commonFlags, this.#flagConfig || {})\n\n if (!flagConfig.hasOwnProperty('help')) { // eslint-disable-line no-prototype-builtins\n flagConfig.help = {\n description: `Display ${this.name} help.`,\n // aliases: ['h'],\n default: false,\n type: 'boolean'\n }\n }\n\n const flags = Array.from(FLAG_PATTERN[Symbol.matchAll](input), x => x[0])\n const parser = new Parser(flags, flagConfig)\n const pdata = parser.data\n const recognized = {}\n\n parser.recognizedFlags.forEach(flag => { recognized[flag] = pdata[flag] })\n parser.unrecognizedFlags.forEach(arg => delete recognized[arg])\n\n data.flags = { recognized, unrecognized: parser.unrecognizedFlags }\n data.valid = parser.valid\n data.violations = parser.violations\n\n data.parsed = {}\n if (Object.keys(pdata.flagSource).length > 0) {\n for (const [key, src] of Object.entries(pdata.flagSource)) { // eslint-disable-line no-unused-vars\n data.parsed[src.name] = src.inputName\n }\n }\n\n data.help = {\n requested: recognized.help\n }\n\n if (recognized.help) {\n data.help.message = this.help\n }\n\n const args = Array.from(this.arguments)\n\n Object.defineProperties(data, {\n flag: {\n enumerable: true,\n configurable: false,\n writable: false,\n value: name => {\n try {\n if (typeof name === 'number') {\n return Array.from(parser.unrecognizedFlags)[name]\n } else {\n if (data.flags.recognized.hasOwnProperty(pdata.flagSource[name].name)) { // eslint-disable-line no-prototype-builtins\n return data.flags.recognized[pdata.flagSource[name].name]\n } else {\n return pdata.flagSource[name].value\n }\n }\n } catch (e) {\n if (this.arguments.has(name)) {\n return Array.from(parser.unrecognizedFlags)[args.indexOf(name)]\n }\n\n return undefined\n }\n }\n },\n command: {\n enumerable: true,\n get: () => this\n },\n shell: {\n enumerable: true,\n get: () => this.shell\n },\n data: {\n enumerable: true,\n get () {\n const uf = parser.unrecognizedFlags\n const result = Object.assign({}, recognized)\n delete result.help\n\n args.forEach((name, i) => {\n const value = uf[i]\n let normalizedValue = Object.keys(pdata).filter(key => key.toLowerCase() === value)\n normalizedValue = (normalizedValue.length > 0 ? normalizedValue.pop() : value)\n\n if (normalizedValue !== undefined) {\n normalizedValue = normalizedValue.trim()\n\n if (STRIP_QUOTE_PATTERN.test(normalizedValue)) {\n normalizedValue = normalizedValue.substring(1, normalizedValue.length - 1)\n }\n }\n\n if (result.hasOwnProperty(name)) { // eslint-disable-line no-prototype-builtins\n result[name] = Array.isArray(result[name]) ? result[name] : [result[name]]\n result[name].push(normalizedValue)\n } else {\n result[name] = normalizedValue\n }\n })\n\n if (uf.length > args.length) {\n uf.slice(args.length)\n .forEach((flag, i) => {\n let name = `unknown${i + 1}`\n while (result.hasOwnProperty(name)) { // eslint-disable-line no-prototype-builtins\n const number = name.substring(7)\n name = 'unknown' + (parseInt(number) + 1)\n }\n\n result[name] = flag\n })\n }\n\n return result\n }\n }\n })\n\n Object.defineProperty(data.help, 'default', {\n enumerable: true,\n get: () => this.help\n })\n\n return data\n }\n\n async run (input, callback) {\n const fn = (this.#fn || this.defaultHandler).bind(this)\n const data = typeof input === 'string' ? this.parse(input) : input\n\n arguments[0] = this.deepParse(input)\n arguments[0].plugins = this.plugins\n\n if (this.shell !== null) {\n const parentMiddleware = this.shell.getCommandMiddleware(this.commandroot.replace(new RegExp(`^${this.shell.name}`, 'i'), '').trim())\n\n if (parentMiddleware.length > 0) {\n this.middleware.use(...parentMiddleware)\n }\n }\n\n const trailers = this.trailers\n\n if (arguments[0].help && arguments[0].help.requested) {\n console.log(this.help)\n\n if (trailers.size > 0) {\n trailers.run(arguments[0])\n }\n\n return\n }\n\n // No subcommand was recognized\n if (this.middleware.size > 0) {\n this.middleware.run(arguments[0], async meta => await Command.reply(fn(meta, callback)))\n\n if (trailers.size > 0) {\n trailers.run(arguments[0])\n }\n\n return\n }\n\n // Command.reply(fn(arguments[0], callback))\n data.plugins = this.plugins\n Command.reply(fn(data, callback))\n\n if (trailers.size > 0) {\n trailers.run(arguments[0])\n }\n }\n\n static stderr (err) {\n if (err instanceof Error) {\n return new Promise((resolve, reject) => reject(err)).catch(console.error)\n }\n\n return new Promise((resolve, reject) => reject(err)).catch(console.error)\n }\n\n static reply (callback) {\n return new Promise((resolve, reject) => {\n try {\n if (typeof callback === 'function') {\n callback()\n }\n\n resolve()\n } catch (e) {\n reject(e)\n }\n })\n }\n}\n","import Command from './command.js'\nimport Shell from './shell.js'\nimport Middleware from './middleware.js'\nimport { Formatter, Table } from './format.js'\nconst all = { Shell, Command, Formatter, Table, Middleware }\nexport { Command, Shell, Formatter, Table, Middleware, all as default }\n"],"names":["Middleware","constructor","Object","defineProperties","this","_data","enumerable","configurable","value","go","writable","args","pop","apply","length","use","method","methodBody","toString","indexOf","push","stack","next","bind","run","Array","from","arguments","Formatter","data","desc","_classPrivateFieldGet","description","trim","Command","aliases","out","commandroot","join","__flagConfig","size","map","i","__processors","Table","replace","output","Shell","name","rows","values","cmd","concat","result","table","usage","flags","forEach","cfg","flag","alias","a","dsc","hasOwnProperty","describeOptions","options","allowMultipleValues","describeMultipleValues","describeDefault","default","required","describeRequired","unshift","subcommands","Base","Set","Map","Default","Options","MultipleValues","Required","meta","parent","hasCustomDefaultHandler","defaultHandler","shell","console","log","help","Error","disableHelp","disablehelp","split","arg","isArray","url","support","commands","add","key","warn","middleware","commonflag","commonFlag","commonflags","commonFlags","plugins","get","__commands","__width","set","v","__commonflags","initializeMiddleware","code","Function","initializeTrailer","trailer","initializeHelpAnnotations","updateHelp","URL","uri","autohelp","width","describeHelp","attr","prop","defaultProcessor","list","commandlist","subcmd","sort","getCommand","names","shift","nm","remove","delete","oid","OID","substring","subCmd","command","FLAG_PATTERN","METHOD_PATTERN","STRIP_QUOTE_PATTERN","COMMAND_PATTERN","freeze","SUBCOMMAND_PATTERN","maxhistory","globalThis","process","release","version","maxHistoryItems","tabWidth","Symbol","super","trailers","runtime","history","count","slice","priorCommand","nextCommand","Math","abs","input","useWith","filter","c","fns","useExcept","all","toLowerCase","callback","test","time","Date","toLocaleString","parsed","exec","stderr","item","undefined","action","processor","term","getTerminalCommand","reply","getCommandMiddleware","results","r","flat","Infinity","clearHistory","clear","handler","call","pattern","entries","attributes","unrecognized","keys","attribute","has","ignoreFlags","ignore","root","RegExp","startsWith","__commonFlags","assign","tableWidth","getFlagConfiguration","addFlag","removeFlag","f","type","supportsFlag","deepParse","parse","flagConfig","matchAll","x","parser","Parser","pdata","recognized","recognizedFlags","unrecognizedFlags","valid","violations","flagSource","src","inputName","requested","message","e","uf","normalizedValue","number","parseInt","defineProperty","fn","parentMiddleware","async","err","Promise","resolve","reject","catch","error"],"mappings":";;;o7BAAe,MAAMA,WACnBC,cACEC,OAAOC,iBAAiBC,KAAM,CAC5BC,MAAO,CAAEC,YAAY,EAAOC,cAAc,EAAOC,MAAO,IACxDC,GAAI,CAAEH,YAAY,EAAOC,cAAc,EAAOG,UAAU,EAAMF,MAAO,IAAIG,QAAWA,KAAKC,MAAMC,MAAMT,KAAMO,4BAI1FP,KAAKC,MAAMS,yBAEXV,KAAKC,MAE1BU,IAAKC,cACGC,WAAaD,OAAOE,WACtBD,WAAWE,QAAQ,iBAAmB,QACnCd,MAAMe,KAAKH,iBAGbR,GAAK,CAACY,OAAS,IAAIV,cAChBW,KAAOX,KAAKC,MAClBS,SAASV,KAAM,KACbK,OAAOH,MAAMT,KAAM,IAAIO,KAAMW,KAAKC,KAAK,QAASZ,WAH1C,CAKPP,KAAKK,IAGVe,YACQb,KAAOc,MAAMC,KAAKC,WACJ,IAAhBhB,KAAKG,QAAiD,mBAA1BH,KAAKA,KAAKG,OAAS,IACjDH,KAAKS,KAAK,aAGPX,MAAME,iGC5Bf,MAAMiB,UAMJ3B,YAAa4B,wCALL,+CACM,2CACF,2CACA,CAAC,MAAO,MAAO,0CAGZA,gBAGJrB,8CACUA,MAAQ,GAAK,GAAKA,wBAGrBA,4CACCA,2BAGEA,4CACFA,yBAIXsB,KAAOC,kCAAWC,YAAYC,UAEhCF,4CAAsBG,QAAS,OAC3BC,QAAUJ,kCAAWI,QACrBC,IAAM,CAAE,GAAEL,kCAAWM,cAAcF,QAAQrB,OAAS,EAAI,IAAMqB,QAAQG,KAAK,KAAO,KAAKP,kCAAWQ,aAAaC,KAAO,EAAI,WAAa,KAAKT,kCAAWJ,UAAUa,KAAO,EAAI,IAAMf,MAAMC,KAAKK,kCAAWJ,WAAWc,IAAIC,GAAK,IAAMA,EAAI,KAAKJ,KAAK,KAAO,aAEzPP,kCAAWY,aAAaH,KAAO,IACjCJ,IAAIA,IAAItB,OAAS,KAAOiB,kCAAWJ,UAAUa,KAAO,GAAKT,kCAAWQ,aAAaC,KAAO,EAAI,KAAO,IAAM,cAGvGV,KAAKG,OAAOnB,OAAS,GAAKsB,MAAQN,MACpCM,IAAIhB,KAAK,IAAIwB,MAAM,CAAC,CAACd,KAAKG,OAAOY,QAAQ,OAAQ,UAAW,KAAM,2BAAMzC,kBAAkB,CAAC,EAAG,EAAG,EAAG,IAAI0C,QAGnGV,IAAIE,KAAK,MACX,OAAIP,4CAAsBgB,MACvB,GAAEhB,kCAAWiB,OAAOjB,kCAAWY,aAAaH,KAAO,EAAI,aAAe,OAAOV,KAAKG,OAAOnB,OAAS,EAAI,IAAI8B,MAAM,CAAC,CAACd,KAAKG,OAAOY,QAAQ,OAAQ,UAAW,KAAM,2BAAMzC,kBAAkB,CAAC,EAAG,EAAG,EAAG,IAAI0C,OAAS,KAAKf,kCAAWJ,UAAUa,KAAO,EAAI,IAAMf,MAAMC,KAAKK,kCAAWJ,WAAWc,IAAIC,GAAK,IAAMA,EAAI,KAAKJ,KAAK,KAAO,OAAOL,OAGxU,2BAIDgB,KAAOxB,MAAMC,KAAKK,kCAAWY,aAAaO,UAAUT,IAAIU,KAErD,CADI,CAACA,IAAIH,MAAMI,OAAOD,IAAIhB,SACtBG,KAAK,KAAMa,IAAInB,cAGtBqB,OAAS,MAEXJ,KAAKnC,OAAS,EAAG,OACbwC,MAAQ,IAAIV,MAAMK,2BAAM7C,gBAAgB,CAAC,MAAO,6BAAQA,kBAAkB,CAAC,IACjFiD,OAAOjC,KAAK,iBACZiC,OAAOjC,KAAKkC,MAAMR,eAGbO,OAAOf,KAAK,uBAIbiB,MAAQnD,KAAKmD,MAAMtB,UAErBF,4CAAsBG,QAAS,OAC3BsB,MAAQzB,kCAAWQ,aACnBU,KAAO,GAETO,MAAMhB,KAAO,GACfgB,MAAMC,QAAQ,CAACC,IAAKC,YACdxB,QAAUV,MAAMC,KAAKgC,IAAIvB,SAAWuB,IAAIE,OAAS,IACrDzB,QAA6B,IAAnBA,QAAQrB,OAAe,GAAK,IAAMqB,QAAQM,IAAIoB,GAAM,IAAGA,GAAKvB,KAAK,MAAQ,QAE/EwB,IAAM,CAACJ,IAAI1B,aAAe,IAE1B0B,IAAIK,eAAe,YAAchC,kCAAWiC,iBAC9CF,IAAI1C,KAAM,YAAWsC,IAAIO,QAAQ3B,KAAK,UAGpCoB,IAAIK,eAAe,yBAAsD,IAA5BL,IAAIQ,qBAAgCnC,kCAAWoC,wBAC9FL,IAAI1C,KAAK,+BAGPsC,IAAIK,eAAe,YAAchC,kCAAWqC,iBAC9CN,IAAI1C,KAAM,aAAYsC,IAAIW,QAAQnD,eAGhCwC,IAAIK,eAAe,cAAgC,IAAjBL,IAAIY,UAAqBvC,kCAAWwC,kBACxET,IAAIU,QAAQ,aAGdV,IAAMA,IAAIxB,KAAK,KAAKL,OAEpBgB,KAAK7B,KAAK,CAAC,KAAOuC,KAAMxB,SAAW,GAAI2B,KAAO,aAI5CR,MAAQ,IAAIV,MAAMK,2BAAM7C,sCAAgBA,sCAAgBA,kBAAkB,CAAC,EAAG,EAAGmD,MAAMzC,OAAS,EAAI,EAAI,EAAG,QAE7G2D,YAAc,KAAOrE,KAAKqE,mBACI,IAA9BA,YAAYxC,OAAOnB,SACrB2D,YAAc,IAETlB,OAASC,MAAMhB,KAAO,EAAI,eAAiBc,MAAMR,OAAS,IAAM2B,YAClE,OAAI1C,4CAAsBgB,MACxB,CAACQ,MAAOnD,KAAKqE,aAAanC,KAAK,MAGjC,2cC5GI,MAAMoC,KAuCnBzE,YAAayD,IAAM,4CAtCR,sCACJ,4CACI,8PAKE,IAAIiB,6CACL,4CACE,IAAIC,4CACN,IAAIA,yCACP,uCACD,oDACM,IAAI5E,kDACP,IAAIA,sDACA,0CACJ,CAET6E,QAAS,KACTC,QAAS,KACTC,eAAgB,KAChBC,SAAU,8DAGe,gDAET,SAAUC,aACN,OAAhB7E,KAAK8E,QAAmB9E,KAAK8E,OAAOC,wBAC/B/E,KAAK8E,OAAOE,kBAAkBzD,WAC5BvB,KAAKiF,OAAwB,OAAfjF,KAAKiF,OAAkBjF,KAAKiF,MAAMF,wBAClD/E,KAAKiF,MAAMD,kBAAkBzD,sCAGlCvB,iBACFkF,QAAQC,IAAInF,KAAKoF,UAKA,iBAAR9B,UACH,IAAI+B,MAAM,0DAGb/B,IAAIK,eAAe,cAChB,IAAI0B,MAAM,qEAGd/B,IAAIK,eAAe,gDACFL,IAAI8B,MAGrB9B,IAAIK,eAAe,kDACDL,IAAIH,OAGtBG,IAAIK,eAAe,iBAAmBL,IAAIK,eAAe,iBAC3DL,IAAIgC,YAAchC,IAAIiC,aAGpBjC,IAAIK,eAAe,iBAAsC,IAApBL,IAAIgC,mDAC1B,GAGK,mBAAbhC,IAAI8B,MAA2C,iBAAb9B,IAAI8B,YAC1CA,KAAO9B,IAAI8B,MAGO,mBAAd9B,IAAIH,OAA6C,iBAAdG,IAAIH,aAC3CA,MAAQG,IAAIH,OAGfG,IAAIK,eAAe,mBAAqBL,IAAI0B,eAAelE,aAAea,4CAAqBb,kBAC5FkE,eAAiB1B,IAAI0B,gBAGC,iBAAlB1B,IAAI/B,YACb+B,IAAI/B,UAAY+B,IAAI/B,UAAUiE,MAAM,mBAAmBnD,IAAIoD,KAAOA,IAAI5D,SAGpER,MAAMqE,QAAQpC,IAAI/B,kDACF,IAAIgD,IAAIjB,IAAI/B,YAGT,iBAAZ+B,IAAIqC,qCACDrC,IAAIqC,KAGS,iBAAhBrC,IAAIsC,6CACGtC,IAAIsC,2CAGRtC,IAAIV,MAAQ,WAAWf,OAAO2D,MAAM,OAAO,4CACrClC,IAAI1B,aAAe,MAEnCP,MAAMqE,QAAQpC,IAAIuC,UACpBvC,IAAIuC,SAASxC,QAAQN,KAAO/C,KAAK8F,IAAI/C,WAChC,GAA4B,iBAAjBO,IAAIuC,aACf,MAAME,OAAOzC,IAAIuC,SAAU,OACxBpE,KAAO6B,IAAIuC,SAASE,KAC1BtE,KAAKmB,KAAOmD,SACPD,IAAIrE,SAIT6B,IAAIK,eAAe,gBACrBuB,QAAQc,KAAK,0EACb1C,IAAI3C,IAAM2C,IAAI2C,kBACP3C,IAAI2C,YAGR3C,IAAIK,eAAe,gBAClBL,IAAIK,eAAe,cACrBL,IAAI4C,WAAa5C,IAAI6C,WACZ7C,IAAIK,eAAe,eAC5BL,IAAI4C,WAAa5C,IAAI8C,YACZ9C,IAAIK,eAAe,cAC5BL,IAAI4C,WAAa5C,IAAI6C,WACZ7C,IAAIK,eAAe,iBAC5BL,IAAI4C,WAAa5C,IAAI+C,cAIrB/C,IAAIK,eAAe,eACS,iBAAnBL,IAAI4C,iBACP,IAAIb,MAAM,+DAIO,iBAAhB/B,IAAIgD,6CACGhD,IAAIgD,SAGtBxG,OAAOC,iBAAiBC,KAAM,CAC5BuC,aAAc,CACZrC,YAAY,EACZqG,mCACSvG,oBAGXwG,WAAY,CACVtG,YAAY,EACZqG,mCACSvG,kBAGXyG,QAAS,CACPvG,YAAY,EACZqG,mCACSvG,cAET0G,IAAKC,qCACWA,GAAK,MAGvBC,cAAe,CACb1G,YAAY,EACZqG,mCACSvG,oBAET0G,IAAKtG,+CACiBA,SAGxBmB,UAAW,CACTrB,YAAY,EACZqG,mCACSvG,mBAGX6G,qBAAsB,CACpB3G,YAAY,EACZC,cAAc,EACdG,UAAU,EACVF,MAAO0G,UACe,iBAATA,UACJnG,IAAIoG,SAAS,UAAYD,KAArBC,QACJ,CAAA,GAAoB,mBAATD,WAGV,IAAIzB,MAAM,uBAAyByB,KAAKhG,iBAFzCH,IAAImG,SAMfE,kBAAmB,CACjB9G,YAAY,EACZC,cAAc,EACdG,UAAU,EACVF,MAAO0G,UACe,iBAATA,UACJG,QAAQF,SAAS,UAAYD,KAArBC,QACR,CAAA,GAAoB,mBAATD,WAGV,IAAIzB,MAAM,oBAAsByB,KAAKhG,iBAFtCmG,QAAQH,SAMnBI,0BAA2B,CACzBhH,YAAY,EACZC,cAAc,EACdG,UAAU,EACVF,MAAOkD,MACDA,IAAIK,eAAe,oBAAqD,kBAAxBL,IAAIU,uDACxCS,QAAUnB,IAAIU,iBAE1BV,IAAIK,eAAe,oBAAqD,kBAAxBL,IAAIM,uDACxCc,QAAUpB,IAAIM,iBAE1BN,IAAIK,eAAe,2BAAmE,kBAA/BL,IAAIS,8DAC/CY,eAAiBrB,IAAIS,wBAEjCT,IAAIK,eAAe,qBAAuD,kBAAzBL,IAAIa,wDACzCS,SAAWtB,IAAIa,2BAMhCgD,wDAIEnH,iCAKA2B,mCAAc,mCAKdA,0CAAqB3B,KAAKmD,OAAS,oBAKnCnD,KAAKoH,oBAKNC,KAAO1F,kCAAa,IAAIE,UAEX,IAAfwF,IAAI3G,OAAc,IAChBV,KAAK2D,eAAe,iBACf3D,KAAK8E,OAAOsC,IACd,GAAIpH,gBAAgB8B,eAClB9B,KAAKiF,MAAMmC,WAIfC,wBAKDzB,SAAWjE,sCAAiB,IAAIE,UAEf,IAAnB+D,QAAQlF,OAAc,IACpBV,KAAK2D,eAAe,iBACf3D,KAAK8E,OAAOc,QACd,GAAI5F,gBAAgB8B,eAClB9B,KAAKiF,MAAMW,eAIfA,oDAIA5F,6BAGKI,OACS,kBAAVA,6CAGMA,+CACAiD,QAAQN,MAASA,IAAIuE,SAAWlH,SAGnD+G,8DAC+B,IAAI3F,UAAUxB,yDAChBuH,4BAAQvH,aAGrCwH,aAAcC,KAAMC,SACU,OAAxB/F,qCAAc+F,aACT/F,qCAAc+F,SAGnB1H,gBAAgB8B,QAAS,IACvB9B,KAAKiF,OAAwB,OAAfjF,KAAKiF,OAAuC,OAArBjF,KAAKiF,MAAMwC,aAC3CzH,KAAKiF,MAAMwC,SAGA,OAAhBzH,KAAK8E,cACA9E,KAAK8E,OAAO2C,aAIhB,+BAIAzH,KAAKwH,aAAa,kBAAmB,wCAIrCxH,KAAKwH,aAAa,kBAAmB,+CAIrCxH,KAAKwH,aAAa,yBAA0B,gDAI5CxH,KAAKwH,aAAa,mBAAoB,+BAInB,OAAtB7F,yCACkC,yCAAtB3B,yCAAmCA,wBAAAA,4BAAsBA,mBAGlE2B,kDAA2BwB,gBAGzB/C,OACY,iBAAVA,OAA8C,IAAxBA,MAAMyB,OAAOnB,SAC5CN,MAAQ,8CAGUA,YAEf+G,qDAIDnH,kBACiC,yCAArBA,wCAAkCA,uBAAAA,KAAiBA,4BAAQA,kBAGtEA,KAAKsH,SAIH3F,kDAA2ByD,KAHzB,YAMDhF,OACa,iBAAVA,OAA8C,IAAxBA,MAAMyB,OAAOnB,SAC5CN,MAAQ,6CAGSA,YAEd+G,gCAIa/G,UACG,mBAAVA,YAKH,IAAIiF,MAAO,2DAA0DjF,uDAJpDA,4DACS,2CACfiD,QAAQN,MAASA,IAAI4E,iBAAmBvH,0DAOpDJ,iFAKAA,gDAID6F,SAAW,UAEjBxE,MAAMC,KAAKK,wCAAiBmB,UAAUO,QAAQN,YACtCtB,KAAOsB,IAAItB,KACXmB,KAAOnB,KAAKmB,YACXnB,KAAKmB,KACZiD,SAASjD,MAAQnB,OAGZoE,uDAIA7F,8DAIAA,2DAIAA,0CAID4H,KAAO,IAAIrD,gBACZsB,SAASxC,QAAQN,MACpB6E,KAAK9B,IAAI/C,IAAIH,MACbG,IAAI8E,YAAYxE,QAAQyE,QAAUF,KAAK9B,IAAK,GAAE/C,IAAIH,QAAQkF,aAGrDzG,MAAMC,KAAKsG,MAAMG,OAG1BC,WAAYpF,KAAO,UACZA,YACI,WAGHqF,MAAQrF,KAAK4C,MAAM,YACrBzC,IAAMpB,sCAAe4E,IAAI0B,MAAMC,YAC/BnF,IAAK,CACPA,IAAMpB,wCAAiB4E,IAAIxD,SACtB,MAAMoF,MAAMF,MACflF,IAAMA,IAAIiF,WAAWG,WAIlBpF,eAAejB,QAAUiB,IAAM,KAGxCqF,aACO,MAAMrF,OAAOxB,aACG,iBAARwB,8CACQsF,OAAOtF,2CACTM,QAAQiF,KAAOA,MAAQvF,KAAOpB,sCAAe0G,OAAOC,OAGlD,iBAARvF,IAAkB,OACrBwF,IAAM5G,sCAAe4E,IAAIxD,KAC3BwF,UACGH,OAAOG,MAMpB5H,UACO,MAAM8E,OAAOlE,UAAW,IACR,mBAARkE,UACH,IAAIJ,MAAO,mDAAkDI,IAAI3E,WAAW0H,UAAU,EAAG,OAAO/C,IAAI3E,WAAWJ,OAAS,GAAK,MAAQ,8CAG5HC,IAAI8E,6CAGNpC,QAAQoF,QAAUA,OAAO9H,OAAOY,YAGnD0F,8CACkBtF,sCAAiB,IAAI/B,gBAEhC,MAAM6F,OAAOlE,UAAW,IACR,mBAARkE,UACH,IAAIJ,MAAO,uDAAsDI,IAAI3E,WAAW0H,UAAU,EAAG,OAAO/C,IAAI3E,WAAWJ,OAAS,GAAK,MAAQ,2CAGnIC,IAAI8E,6CAGHpC,QAAQoF,QAAUA,OAAOxB,WAAW1F,YAGvDuE,UACO,IAAI4C,WAAWnH,UAAW,MACvBmH,mBAAmB5G,SAAU,IACV,iBAAZ4G,cAGH,IAAIrD,MAAM,6EAFhBqD,QAAU,IAAI5G,QAAQ4G,SAM1BA,QAAQpB,SAAWtH,KAAKsH,SAEpBtH,gBAAgB2C,MAClB+F,QAAQzD,MAAQjF,KACPA,gBAAgB8B,UACzB4G,QAAQ5D,OAAS9E,8CAGF0G,IAAIgC,QAAQH,IAAKG,+CACnBhC,IAAIgC,QAAQ9F,KAAM8F,QAAQH,KAEzCG,QAAQ3G,QAAQsB,QAAQG,OAAS7B,sCAAe+E,IAAIlD,MAAOkF,QAAQH,QCpfzE,MACMI,aAAe,2IACfC,eAAiB,yBACjBC,oBAAsB,0DACtBC,gBAAkB,uBACNhJ,OAAOiJ,OAAO,CAC9BC,mBANyB,kCAOzBL,aAAAA,aACAC,eAAAA,eACAC,oBAAAA,oBACAC,gBAAAA,0LCRa,MAAMnG,cAAc2B,KAiBjCzE,YAAayD,IAAM,CAAE2F,WAAY,YACzB3F,mDAjBY,IAAIkB,2CACb,6IAGD,wFAEC0E,WAAWvF,eAAe,UACjC,UAEAuF,WAAWvF,eAAe,YAC1BuF,WAAWC,QAAQC,SACnBF,WAAWC,QAAQC,QAAQxG,KACvBsG,WAAWC,QAAQC,QAAQxG,KAC3B,iBAMDsE,0BAA0B5D,UAE1BsD,cAAgBtD,IAAI8C,aAAe,GAEpC9C,IAAIK,eAAe,QAAUtC,MAAMqE,QAAQpC,IAAI3C,MACjD2C,IAAI3C,IAAI0C,QAAQyD,MAAQ9G,KAAK6G,qBAAqBC,OAGhDxD,IAAIK,eAAe,YAActC,MAAMqE,QAAQpC,IAAI2D,UACrD3D,IAAI2D,QAAQ5D,QAAQyD,MAAQ9G,KAAKgH,kBAAkBF,2CAGrCxD,IAAI+F,SAAW,qDACP/F,IAAI2F,YAAc3F,IAAIgG,iBAAmB,0CAChDhG,IAAIK,eAAe,YAAcL,IAAIiG,SAAW,GAGjEL,WAAWM,OAAO,uBAAyBxJ,sBAIrC6F,SAAW4D,MAAMhI,WAEhB,CACLmB,KAAM5C,KAAK4C,KACXhB,YAAa5B,KAAK4B,YAClByH,QAASrJ,KAAKqJ,QACdxD,SAAAA,SACAlF,IAAKX,KAAKiG,WAAWxE,KACrBwF,QAASjH,KAAK0J,SAASjI,KACvB2D,KAAMpF,KAAKoF,KACXjC,MAAOnD,KAAKmD,MACZ6B,eAAgBhF,KAAKgF,eAAelE,WACpCwE,aAActF,KAAKsH,SACnBqC,8BAAS3J,eACTsJ,sCAAiBtJ,6CAKZ2B,sCAAiB,yBAGVvB,YACTqG,QAAUrG,8BAIRJ,KAAKyG,QAGdmD,QAASC,MAAQ,aACc,IAAzBlI,qCAAcjB,OACT,GAGQ,OAAVmJ,MAAiBlI,qCAAcmI,QAAUnI,qCAAcmI,MAAM,EAAGD,OAGzEE,aAAcF,MAAQ,UACS,IAAzBlI,qCAAcjB,OACT,KAGLmJ,MAAQ,EACH7J,KAAKgK,YAAYC,KAAKC,IAAIL,SAGnCA,OAAgBlI,qCAAcjB,8EAEdmJ,OAEZlI,qCAAgBA,qCAAcjB,2CACjBiB,qCAAcjB,OAAS,GAGjCiB,2DAAc3B,eAAcmK,OAGrCH,YAAaH,MAAQ,UACU,IAAzBlI,qCAAcjB,OACT,KAGLmJ,MAAQ,EACH7J,KAAK+J,aAAaE,KAAKC,IAAIL,SAGpCA,OAAgBlI,qCAAcjB,8EAEdmJ,OACZlI,oCAAe,0CACF,GAIVA,2DAAc3B,eAAcmK,OAGrCC,QAASvE,aACHtE,UAAUb,OAAS,QACf,IAAI2E,MAAM,0EAGlBQ,SAA+B,iBAAbA,SAAwBA,SAASL,MAAM,OAASK,UAE7DxE,MAAMqE,QAAQG,WAAaA,SAASwE,OAAOC,GAAkB,iBAANA,GAAgB5J,OAAS,QAC7E,IAAI2E,MAAO,uFAAsFQ,gBAGnG0E,IAAMlJ,MAAMC,KAAKC,WAAWuI,MAAM,GAExCjE,SAASxC,QAAQN,KAAOpB,8CAAuB+E,IAAI3D,IAAIlB,QAASF,8CAAuB4E,IAAIxD,IAAIlB,SAAW,IAAImB,OAAOuH,OAGvHC,UAAW3E,aACLtE,UAAUb,OAAS,QACf,IAAI2E,MAAM,4EAGlBQ,SAA+B,iBAAbA,SAAwBA,SAASL,MAAM,OAASK,UAE7DxE,MAAMqE,QAAQG,WAAaA,SAASwE,OAAOC,GAAkB,iBAANA,GAAgB5J,OAAS,QAC7E,IAAI2E,MAAO,yFAAwFQ,gBAGrG0E,IAAMlJ,MAAMC,KAAKC,WAAWuI,MAAM,GAClCW,IAAM,IAAIlG,IAAIvE,KAAK6H,YAAYxF,IAAIC,GAAKA,EAAEoI,gBAEhD7E,SAASxC,QAAQN,MACf0H,IAAIpC,OAAOtF,SACN,MAAMuH,KAAKG,IACS,IAAnBH,EAAEvJ,QAAQgC,MACZ0H,IAAIpC,OAAOiC,UAKZF,QAAQ/I,MAAMC,KAAKmJ,QAASF,gBAGvBJ,MAAOQ,UAGbtJ,MAAMqE,QAAQyE,SAChBA,MAAQA,MAAM9H,IAAIC,GACZA,EAAEvB,QAAQ,MAAQ,IAAM,oBAAoB6J,KAAKtI,GAC3C,IAAGA,KAEJA,GAERJ,KAAK,2CAGIkC,QAAQ,CAAE+F,MAAAA,MAAOU,MAAM,IAAIC,MAAOC,mBAE5CpJ,qCAAcjB,6BAASV,6DACXQ,UAGZwK,OAASlC,gBAAgBmC,KAAKd,MAAQ,QAE3B,OAAXa,cACgC,IAA9Bb,MAAMpJ,QAAQ,aAA8C,IAAzBoJ,MAAMpJ,QAAQ,MAC5CmE,QAAQC,IAAInF,KAAKqJ,UACY,IAA3Bc,MAAMpJ,QAAQ,QAChBmE,QAAQC,IAAInF,KAAKoF,MAGnBtD,QAAQoJ,OAAOlL,KAAKoF,MAG7B4F,OAASA,OAAOX,OAAOc,WAAiBC,IAATD,YAEzBpI,IAAMiI,OAAO,GACbzK,KAAOyK,OAAOtK,OAAS,EAAIsK,OAAO,GAAK,GAGvCK,OAASrL,KAAKwG,WAAWD,IAAIxD,SAE9BsI,aACuB,YAAtBtI,IAAI2H,cACCxF,QAAQC,IAAInF,KAAKqJ,SAGnBvH,QAAQoJ,OAAOlL,KAAKoF,YAGvBkG,UAAYtL,KAAKuC,aAAagE,IAAI8E,YAEnCC,iBACIxJ,QAAQoJ,OAAO,4BAGlBK,KAAOD,UAAUE,mBAAmBjL,mBAC7BuB,QAAQ2J,YAAYF,KAAK7C,QAAQtH,IAAImK,KAAKhK,UAAWoJ,WAGpEe,qBAAsB3I,WACd4I,QAAU,UAChB5I,IAAIyC,MAAM,OAAOnC,QAAQ,CAACiH,EAAGhI,EAAGmB,WACxBmI,EAAIjK,8CAAuB4E,IAAI9C,EAAEqG,MAAM,EAAGxH,EAAI,GAAGJ,KAAK,MAC5D0J,GAAKD,QAAQ3K,KAAK4K,EAAEC,KAAKC,EAAAA,MAGpBH,QAAQE,KAAKC,EAAAA,GAGtBC,mDACkB,IAIlBC,4CACkB,IAChB9G,QAAQ8G,uJCzOG,MAAMlK,gBAAgBwC,KASnCzE,YAAayD,IAAM,OACbA,IAAIK,eAAe,aACM,iBAAhBL,IAAI2I,UACb3I,IAAI2I,QAAUlF,SAAS,WAAazD,IAAI2I,QAAQxJ,QAAQ,qBAAsB,YAAc,gBAAgByJ,KAAKhD,aAGxF,mBAAhB5F,IAAI2I,eACP,IAAI5G,MAAM,6EAId/B,kIAjBG,IAAIiB,uFAED,yCACJ,0CACD,OAeHjB,IAAIK,eAAe,QAAUtC,MAAMqE,QAAQpC,IAAI3C,MACjD2C,IAAI3C,IAAI0C,QAAQyD,MAAQ9G,KAAK6G,qBAAqBC,OAGhDxD,IAAIK,eAAe,YAActC,MAAMqE,QAAQpC,IAAI2D,UACrD3D,IAAI2D,QAAQ5D,QAAQyD,MAAQ9G,KAAKgH,kBAAkBF,YAGhDI,0BAA0B5D,oCAEpBA,IAAI2I,yCACHzC,OAASlG,IAAIV,MAAQU,IAAIH,OAAUG,IAAI6I,SAAY,gDAC/C7I,IAAI6I,SAAW,YAE3B7I,IAAIE,QAAUF,IAAIvB,UACpBuB,IAAIvB,QAA+B,iBAAduB,IAAIE,MAAqB,CAACF,IAAIE,OAAUnC,MAAMqE,QAAQpC,IAAIE,OAASF,IAAIE,MAAQnC,MAAMC,KAAKgC,IAAIE,cAC5GF,IAAIE,OAGTF,IAAIvB,QAAS,KACVV,MAAMqE,QAAQpC,IAAIvB,eACf,IAAIsD,MAAM,iFAGF,IAAId,IAAIjB,IAAIvB,aAG1BuB,IAAIF,MAAO,IACY,iBAAdE,IAAIF,YACP,IAAIiC,MAAO,oEAAmE/B,IAAIF,eAGrF,MAAO2C,IAAK3F,SAAUN,OAAOsM,QAAQ9I,IAAIF,UACxChD,MAAMuD,eAAe,SAAU,IACjCvD,MAAM2B,QAAU3B,MAAM2B,SAAW,GAE7BV,MAAMqE,QAAQtF,MAAMoD,WACtBpD,MAAM2B,QAAUV,MAAMC,KAAK,IAAIiD,OAAOnE,MAAM2B,WAAY3B,MAAMoD,QAC1DpD,MAAM2B,QAAQsI,OAAO5G,GAAkB,iBAANA,GAAkB,QAC/C,IAAI4B,MAAO,GAAEU,sDAAsD3F,MAAM2B,QAAQsI,OAAO5G,GAAkB,iBAANA,GAAgBvB,KAAK,cAE5H,CAAA,GAA2B,iBAAhB9B,MAAMoD,YAGhB,IAAI6B,MAAO,uCAAsCjF,MAAMoD,UAAUuC,cAFvE3F,MAAM2B,QAAQf,KAAKZ,MAAMoD,cAKpBpD,MAAMoD,6CAIEF,IAAIF,OAGrB/B,MAAMqE,QAAQpC,IAAIe,mBACfyB,OAAOxC,IAAIe,mBAGZgI,WAAa,IAAI9H,IAAI,CACzB,WACA,cACA,UACA,iBACA,cACA,kBACA,kBACA,yBACA,mBACA,QACA,QACA,UACA,cACA,OACA,QACA,UACA,OACA,UACA,aACA,MACA,YACA,aACA,cACA,UACA,MACA,YAGI+H,aAAexM,OAAOyM,KAAKjJ,KAAK+G,OAAOmC,YAAcH,WAAWI,IAAID,eAEtEF,aAAa5L,OAAS,QAClB,IAAI2E,MAAO,4CAA2CiH,aAAapK,KAAK,aAG1EwK,YAAcrG,iBACdA,YAAYsG,SAAWtL,MAAMqE,QAAQW,YAAYsG,SAAyC,iBAAvBtG,YAAYsG,QAAsB,OACjGA,OAAS,IAAIpI,IAAIlD,MAAMqE,QAAQW,YAAYsG,QAAUtG,YAAYsG,OAAS,CAACtG,YAAYsG,SAEvFC,KAAO5M,KAAKiC,YAAYQ,QAAQ,IAAIoK,OAAQ,IAAG7M,KAAKiF,MAAMrC,WAAY,KAAM,QAE7E,MAAMG,OAAO4J,UACZC,KAAKE,WAAW/J,KAAM,CACxBsD,YAAc,iBAMbA,aAGTvG,OAAOC,iBAAiBC,KAAM,CAC5B+M,cAAe,CACb7M,YAAY,EACZqG,UACMnD,MAAQsJ,YAAY1M,KAAK4G,eAET,OAAhB5G,KAAK8E,SACP1B,MAAQtD,OAAOkN,OAAO5J,MAAOpD,KAAK8E,OAAOiI,sBAGrC9J,OAASnD,OAAOkN,OAAO,GAAmB,OAAfhN,KAAKiF,MAAiByH,YAAY1M,KAAKiF,MAAM2B,eAAiB,GAAIxD,cAE/F/B,MAAMqE,QAAQzC,OAAO0J,SAAoC,iBAAlB1J,OAAO0J,gBACzC1J,OAAO0J,OAGT1J,SAGXd,aAAc,CACZjC,YAAY,EACZqG,YACQnD,MAAQ,IAAIoB,IAAI1E,OAAOsM,QAAQtM,OAAOkN,OAAOhN,KAAK+M,cAAepL,yCAAoB,aAC3FyB,MAAMiF,OAAO,QACNjF,QAGXoI,mBAAoB,CAClBtL,YAAY,EACZC,cAAc,EACdG,UAAU,EACVF,MAAO+J,cACC5J,KAAO4J,MAAMtI,OAAO2D,MAAM,eAC5BzC,IAAM/C,UAEHO,KAAKG,OAAS,GAAG,OAChB+E,IAAMlF,KAAK,GACXuH,OAAS/E,IAAIiF,WAAWvC,SAC1BqC,aACF/E,IAAM+E,OACNvH,KAAK2H,cAMF,CACLQ,QAAS3F,IACTxB,UAAWhB,KAAK2B,KAAK,eAMxB0E,cAAgBtD,IAAI8C,aAAe,QAEnCK,QAAyB,OAAfzG,KAAKiF,MAAiB,GAAKjF,KAAKiF,MAAMgI,YAAc,QAE9D9F,8BAICtB,SAAW4D,MAAMhI,SAEnBwK,SAAWtK,iCAAY3B,KAAKgF,gBAAgBlE,WAC5C8H,eAAegC,KAAKqB,WACtBA,QAAUA,QAAQxJ,QAAQmG,eAAeqC,KAAKgB,SAAS,GAAI,oBAGvD7I,MAAQtD,OAAOkN,OAAOhN,KAAK+M,cAAepL,yCAAoB,QAE/D,MAAOoE,IAAK3F,SAAUN,OAAOsM,QAAQhJ,OACxChD,MAAM2B,QAAU3B,MAAM2B,SAAW,GAE7B3B,MAAMuD,eAAe,UACnBvD,MAAM2B,QAAQhB,QAAQX,MAAMoD,OAAS,GACvCpD,MAAM2B,QAAQf,KAAKZ,MAAMoD,cAItBpD,MAAMoD,MAIf1D,OAAOyM,KAAKnJ,OAAOC,QAAQT,OAAUQ,MAAMR,MAAQ9C,OAAOkN,OAAOhN,KAAKkN,qBAAqBtK,MAAOQ,MAAMR,eAElGnB,KAAO,CACXmB,KAAM5C,KAAK4C,KACXhB,YAAa5B,KAAK4B,YAClBwD,KAAMpF,KAAKoF,KACXjC,MAAOnD,KAAKmD,MACZpB,QAASV,MAAMC,2BAAKtB,gBACpBoD,MAAAA,MACA6I,QAAAA,QACApG,SAAAA,SACAP,aAActF,KAAKsH,SACnB3G,IAAKX,KAAKiG,WAAWxE,KACrBwF,QAASjH,KAAK0J,SAASjI,UAGpB,MAAOsE,IAAK3F,SAAUN,OAAOsM,QAAQ3K,KAAK2B,cACtChD,MAAMoD,aAGR/B,gBAGGsB,UACNA,eAAejB,eAGX,IAAIuD,MAAO,yBAAwBrF,KAAK4C,yLAF/BG,+CAOV/C,wBAGEiF,WACJA,YACG,IAAII,MAAO,uBAAsBrF,KAAK4C,4CAE1CqC,iBAAiBtC,aAIb,IAAI0C,MAAO,+CAA8CJ,oDAHjDA,YACTwB,QAAyB,OAAfzG,KAAKiF,MAAiB,GAAKA,MAAMgI,oDAO7CjN,mCAQEA,mCAPDA,cACK2B,oCAAasD,MAGf,0BAOFnF,OAAOkN,OAAO,GAAIhN,KAAKiF,MAAMqB,QAAStG,KAAK8E,OAAS9E,KAAK8E,OAAOwB,QAAU,GAAImD,MAAMnD,wDAIvFtG,cACM,GAAE2B,oCAAaM,eAAejC,KAAK4C,OAAOf,6BAGhD7B,aACM,GAAE2B,mCAAYiB,QAAQ5C,KAAK4C,OAAOf,OAGrC7B,KAAK4C,iBAGDxC,UACNA,UAKgB,iBAAVA,aACDA,MAAMP,YAAY+C,KAAK8H,mBACxB,MACHtK,MAAQiB,MAAMC,KAAKlB,MAAMmM,kBAEtB,MACHnM,MAAQiB,MAAMC,KAAKlB,iBAEhB,SACHA,MAAQN,OAAOyM,KAAKnM,OAAOiK,OAAOc,MAAwB,iBAATA,gBAE9C,kBAEA,SACH/K,MAAQA,MAAMoF,MAAM,OAAO,uBAGrB,IAAIH,MAAM,qFAINhE,MAAMC,KAAK,IAAIiD,IAAInE,kDAzBjB,yBA6BXiB,MAAMC,2BAAKtB,iBAAkB,0CAI7BA,WAGTmN,QAASvK,KAAMU,QACO,iBAATV,KAAmB,KACvBU,IAAIK,eAAe,cAChB,IAAI0B,MAAM,2CAEhBzC,KAAOU,IAAIV,6CAIEA,MAAQU,IAG3B8J,WAAYxK,aACHjB,wCAAiBiB,MAG1BsK,qBAAsBtK,UAChBW,KAAOvD,KAAKmC,aAAaoE,IAAI3D,UAC5BW,KAAM,KACJ,MAAO8J,EAAG/J,OAAQtD,KAAKmC,gBACrBmB,IAAIvB,SAAWuB,IAAIvB,QAAQhB,QAAQ6B,OAAS,GAAOU,IAAIE,OAASF,IAAIE,QAAUD,KAAO,CACxFA,KAAOD,cAKNC,YACI,WAIJ,CACL3B,YAAa2B,KAAK3B,YAClBsC,WAAUX,KAAKI,eAAe,aAAcJ,KAAKW,SACjDnC,QAASwB,KAAKxB,SAAW,CAACwB,KAAKC,OAAO6G,OAAO/H,GAAW,OAANA,GAClDgL,UAAoBlC,IAAd7H,KAAK+J,KAAqB,SAAiC,iBAAd/J,KAAK+J,KAAoB/J,KAAK+J,KAAO/J,KAAK+J,KAAK1K,KAAK8H,cACvG7G,QAASN,KAAKI,eAAe,WAAaJ,KAAKM,QAAU,KACzDC,sBAAqBP,KAAKI,eAAe,wBAAyBJ,KAAKO,qBAI3EyJ,aAAc3K,aACLjB,wCAAiBgC,eAAef,MAGzC4K,UAAWrD,aACHtF,KAAO7E,KAAKyN,MAAMtD,UAEK,IAAzBnK,KAAKwG,WAAWpE,YACXyC,QAGwB,IAA7BA,KAAKsF,MAAMtI,OAAOnB,cACbmE,WAGHtE,KAAOsE,KAAKsF,MAAM3E,MAAM,OACxBsC,OAAS9H,KAAKwG,WAAWD,IAAIhG,KAAK2H,gBAEnCJ,OAIE9H,KAAKuC,aAAagE,IAAIuB,QAAQ0F,UAAUjN,KAAK2B,KAAK,MAHhD2C,KAMX4I,MAAOtD,aAEC1I,KAAO,CAAEiH,QAAS1I,KAAK4C,KAAMuH,MAAOA,MAAMtI,QAC1C6L,WAAa5N,OAAOkN,OAAOhN,KAAK+M,cAAepL,yCAAoB,IAEpE+L,WAAW/J,eAAe,UAC7B+J,WAAWtI,KAAO,CAChBxD,YAAc,WAAU5B,KAAK4C,aAE7BqB,SAAS,EACTqJ,KAAM,kBAIJlK,MAAQ/B,MAAMC,KAAKqH,aAAaa,OAAOmE,UAAUxD,OAAQyD,GAAKA,EAAE,IAChEC,OAAS,IAAIC,OAAO1K,MAAOsK,YAC3BK,MAAQF,OAAOpM,KACfuM,WAAa,MAEnBH,OAAOI,gBAAgB5K,QAAQE,OAAUyK,WAAWzK,MAAQwK,MAAMxK,QAClEsK,OAAOK,kBAAkB7K,QAAQoC,YAAcuI,WAAWvI,MAE1DhE,KAAK2B,MAAQ,CAAE4K,WAAAA,WAAY1B,aAAcuB,OAAOK,mBAChDzM,KAAK0M,MAAQN,OAAOM,MACpB1M,KAAK2M,WAAaP,OAAOO,WAEzB3M,KAAKuJ,OAAS,GACVlL,OAAOyM,KAAKwB,MAAMM,YAAY3N,OAAS,MACpC,MAAOqF,IAAKuI,OAAQxO,OAAOsM,QAAQ2B,MAAMM,YAC5C5M,KAAKuJ,OAAOsD,IAAI1L,MAAQ0L,IAAIC,UAIhC9M,KAAK2D,KAAO,CACVoJ,UAAWR,WAAW5I,MAGpB4I,WAAW5I,OACb3D,KAAK2D,KAAKqJ,QAAUzO,KAAKoF,YAGrB7E,KAAOc,MAAMC,KAAKtB,KAAKuB,kBAE7BzB,OAAOC,iBAAiB0B,KAAM,CAC5B8B,KAAM,CACJrD,YAAY,EACZC,cAAc,EACdG,UAAU,EACVF,MAAOwC,iBAEiB,iBAATA,KACFvB,MAAMC,KAAKuM,OAAOK,mBAAmBtL,MAExCnB,KAAK2B,MAAM4K,WAAWrK,eAAeoK,MAAMM,WAAWzL,MAAMA,MACvDnB,KAAK2B,MAAM4K,WAAWD,MAAMM,WAAWzL,MAAMA,MAE7CmL,MAAMM,WAAWzL,MAAMxC,MAGlC,MAAOsO,UACH1O,KAAKuB,UAAUkL,IAAI7J,MACdvB,MAAMC,KAAKuM,OAAOK,mBAAmB3N,KAAKQ,QAAQ6B,iBAOjE8F,QAAS,CACPxI,YAAY,EACZqG,IAAK,IAAMvG,MAEbiF,MAAO,CACL/E,YAAY,EACZqG,IAAK,IAAMvG,KAAKiF,OAElBxD,KAAM,CACJvB,YAAY,EACZqG,YACQoI,GAAKd,OAAOK,kBACZjL,OAASnD,OAAOkN,OAAO,GAAIgB,0BAC1B/K,OAAOmC,KAEd7E,KAAK8C,QAAQ,CAACT,KAAMN,WACZlC,MAAQuO,GAAGrM,OACbsM,gBAAkB9O,OAAOyM,KAAKwB,OAAO1D,OAAOtE,KAAOA,IAAI2E,gBAAkBtK,OAC7EwO,gBAAmBA,gBAAgBlO,OAAS,EAAIkO,gBAAgBpO,MAAQJ,WAEhDgL,IAApBwD,kBACFA,gBAAkBA,gBAAgB/M,OAE9BgH,oBAAoB+B,KAAKgE,mBAC3BA,gBAAkBA,gBAAgBpG,UAAU,EAAGoG,gBAAgBlO,OAAS,KAIxEuC,OAAOU,eAAef,OACxBK,OAAOL,MAAQvB,MAAMqE,QAAQzC,OAAOL,OAASK,OAAOL,MAAQ,CAACK,OAAOL,OACpEK,OAAOL,MAAM5B,KAAK4N,kBAElB3L,OAAOL,MAAQgM,kBAIfD,GAAGjO,OAASH,KAAKG,QACnBiO,GAAG7E,MAAMvJ,KAAKG,QACX2C,QAAQ,CAACE,KAAMjB,SACVM,KAAQ,WAASN,EAAI,QAClBW,OAAOU,eAAef,OAAO,OAC5BiM,OAASjM,KAAK4F,UAAU,GAC9B5F,KAAO,WAAakM,SAASD,QAAU,GAGzC5L,OAAOL,MAAQW,OAIdN,WAKbnD,OAAOiP,eAAetN,KAAK2D,KAAM,UAAW,CAC1ClF,YAAY,EACZqG,IAAK,IAAMvG,KAAKoF,OAGX3D,eAGE0I,MAAOQ,gBACVqE,IAAMrN,iCAAY3B,KAAKgF,gBAAgB7D,KAAKnB,MAC5CyB,KAAwB,iBAAV0I,MAAqBnK,KAAKyN,MAAMtD,OAASA,SAE7D5I,UAAU,GAAKvB,KAAKwN,UAAUrD,OAC9B5I,UAAU,GAAG+E,QAAUtG,KAAKsG,QAET,OAAftG,KAAKiF,MAAgB,OACjBgK,iBAAmBjP,KAAKiF,MAAMyG,qBAAqB1L,KAAKiC,YAAYQ,QAAQ,IAAIoK,OAAQ,IAAG7M,KAAKiF,MAAMrC,KAAQ,KAAM,IAAIf,QAE1HoN,iBAAiBvO,OAAS,QACvBuF,WAAWtF,OAAOsO,wBAIrBvF,SAAW1J,KAAK0J,gBAElBnI,UAAU,GAAG6D,MAAQ7D,UAAU,GAAG6D,KAAKoJ,WACzCtJ,QAAQC,IAAInF,KAAKoF,WAEbsE,SAAStH,KAAO,GAClBsH,SAAStI,IAAIG,UAAU,MAOvBvB,KAAKiG,WAAW7D,KAAO,QACpB6D,WAAW7E,IAAIG,UAAU,GAAI2N,MAAAA,YAAoBpN,QAAQ2J,MAAMuD,GAAGnK,KAAM8F,iBAEzEjB,SAAStH,KAAO,GAClBsH,SAAStI,IAAIG,UAAU,OAO3BE,KAAK6E,QAAUtG,KAAKsG,QACpBxE,QAAQ2J,MAAMuD,GAAGvN,KAAMkJ,gBAEnBjB,SAAStH,KAAO,GAClBsH,SAAStI,IAAIG,UAAU,oBAIZ4N,YACM9J,MACV,IAAI+J,QAAQ,CAACC,QAASC,SAAWA,OAAOH,MAAMI,MAAMrK,QAAQsK,oBAMzD7E,iBACL,IAAIyE,QAAQ,CAACC,QAASC,cAED,mBAAb3E,UACTA,WAGF0E,UACA,MAAOX,GACPY,OAAOZ,aC/kBTjE,IAAM,CAAE9H,MAAAA,MAAOb,QAAAA,QAASN,UAAAA,UAAWgB,MAAAA,MAAO5C,WAAAA"}
\ No newline at end of file
diff --git a/dist/shell-debug/package.json b/dist/shell-debug/package.json
new file mode 100644
index 0000000..ca0a820
--- /dev/null
+++ b/dist/shell-debug/package.json
@@ -0,0 +1,52 @@
+{
+ "name": "@author.io/shell-debug",
+ "version": "1.8.18",
+ "description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers. (Debug Mappings)",
+ "module": "./index.js",
+ "exports": {
+ "import": "./index.js",
+ "default": "./index.js"
+ },
+ "browser": "./index.js",
+ "keywords": [
+ "shell",
+ "debug",
+ "sourcemap"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/author/shell"
+ },
+ "author": {
+ "name": "Corey Butler",
+ "url": "http://coreybutler.com"
+ },
+ "license": "MIT",
+ "type": "module",
+ "files": [
+ "*.js"
+ ],
+ "engines": {
+ "node": ">=13.5.0"
+ },
+ "standard": {
+ "parser": "babel-eslint",
+ "ignore": [
+ "_*",
+ "_**/*",
+ ".**/*",
+ "node_modules",
+ "karma.conf.js",
+ "karma.conf.cjs",
+ "build.js"
+ ],
+ "globals": [
+ "window",
+ "global",
+ "globalThis"
+ ]
+ },
+ "dependencies": {
+ "source-map-support": "^0.5.16"
+ }
+}
\ No newline at end of file
diff --git a/dist/shell/LICENSE b/dist/shell/LICENSE
new file mode 100644
index 0000000..166549b
--- /dev/null
+++ b/dist/shell/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Author.io
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/dist/shell/README.md b/dist/shell/README.md
new file mode 100644
index 0000000..e9e8d43
--- /dev/null
+++ b/dist/shell/README.md
@@ -0,0 +1,972 @@
+# @author.io/shell
+
+
+This is a super-lightweight framework for building text-based programs, like [CLI](https://en.wikipedia.org/wiki/Command-line_interface) applications. See the [installation guide](#installation) to jumpstart your CLI.
+
+---
+This library is now supported by this [Chrome CLI Devtools Extension](https://chrome.google.com/webstore/detail/cli/okpglddgmnblhbdpdcmodmacgcibgfkf):
+
+
+
+You can see the library in use (in browsers and Node.js) in this [OpenJS World 2020 talk](https://youtu.be/dw7ABwvFtdM) (The Benefits of a "CLI First" Development Strategy).
+
+---
+
+## Uses
+
+There are two types of text-based apps:
+
+1. **Single Purpose** (_a_ command)
+ These are tools which may have multiple configuration options, but ultimately only do one thing. Examples include [node-tap](https://node-tap.org/), [mocha](https://mochajs.org/), [standard](https://standardjs.com/), prettier, etc.
+
+ For example, node-tap can be run on a file, using syntax like `tap [options] []`. Ultimately, this utility serves one purpose. It just runs a configured tap process.
+
+
+1. **Multipurpose** (a shell for _multiple_ commands)
+ Other tools do more than configure a script. Consider npm, which has several subcommands (like `install`, `uninstall`, `info`, etc). Subcommands often behave like their own single purpose tool, with their own unique flags, and even subcommands of their own. Docker is a good example of this, which has an entire series of management subcommands.
+
+#### Is this "framework" overkill?
+
+**tl;dr** Use this library to create multipurpose tools. Use [@author.io/arg](https://github.com/author/arg) to create single purpose tools.
+
+
+Detailed Explanation
+
+
+This framework was designed to support multipurpose CLI tools. At the core, it provides a clean, easily-understood, repeatable pattern for building maintainable multipurpose CLI applications.
+
+Multipurpose tools require a layer of organizational overhead to help isolate different commands and features. This overhead is unnecessary in single purpose tools. Single purpose tools just need argument parsing, which the [@author.io/arg](https://github.com/author/arg) does very well.
+
+`@author.io/arg` is embedded in this framework, making `@author.io/shell` _capable_ of creating single purpose tools, but it's merely unnecessary overhead for single purpose commands.
+
+
+
+**Think about how your tooling evolves...**
+
+Sometimes single purpose tools grow into multipurpose tools over time. Tools which start out using the `@author.io/arg` library can be transitioned into multipurpose tools using `@author.io/shell` (with reasonable ease). After all, they use the same code, just nicely separated by purpose.
+
+## Differentiating Features
+
+1. Supports **middleware** (express-style).
+1. Supports **postware** (middleware that runs after a command).
+1. **Customizable **help/usage** screens.
+1. Produces **introspectable** JSON. Load a JSON config, have a working CLI.
+1. Reusable **plugin** system.
+1. Dynamically add/remove commands.
+1. Track command execution **history**.
+1. Define **universal flags** once, reuse in all commands.
+
+
+Also has better source & distribution code
+
+1. Cross-runtime (browser, node, deno)
+1. Separation of Concerns: Arg parsing and text formatting are separate microlibs.
+1. Modern ES Module syntax
+1. 40+ unit tests
+
+
+
+## Basic Examples
+
+See the [Installation Guide](#installation) when you're ready to get started.
+
+There is a complete working example of a CLI app (with a mini tutorial) in the examples directory.
+
+_This example imports the library for Node. Simply swap the Node import for the appropriate browser import if you're building a web utility. Everything else is the same for both Node and browser environments._
+
+```javascript
+import { Shell, Command } from '@author.io/shell'
+
+// Define a command
+const ListCommand = new Command({
+ name: 'list',
+ description: 'List the contents of the directory.',
+ disableHelp: false, // Set to true to turn off default help messages for the entire shell (you can still provide your own). Defaults to false.
+ // arguments are listed after the command in the default help screen. Ex: "dir list path"
+ arguments: 'path', // Can be space/comma/tab/semicolon delimited or an array.
+ alias: 'ls',
+ // Any flag parsing options from the @author.io/arg library can be configured here.
+ // See https://github.com/author/arg#configuration-methods for a list.
+ flags: {
+ long: {
+ alias: 'l',
+ description: 'Long format'.
+ type: 'boolean',
+ default: false
+ },
+ rootDir: {
+ description: 'The root directory to list.',
+ aliases: ['input', 'in', 'src'],
+ single: true,
+ // validate: RegExp/Function (see github.com/author/arg)
+ }
+ },
+ handler (metadata, callback) {
+ // ... this is where your command actually does something ...
+
+ // Data comes from @author.io/arg lib. It looks like:
+ // {
+ // command: ,
+ // input: 'whatever user typed after "command"',
+ // flags: {
+ // recognized: {},
+ // unrecognized: [
+ // 'whatever',
+ // 'user',
+ // 'typed'
+ // ]
+ // },
+ // valid: false,
+ // violations: [],
+ // flag (name) { return String },
+ // data (getter)
+ // }
+ console.log(metadata)
+
+ // A single flag's value can be retrieved with this helper method.
+ console.log(metadata.flag('long'))
+
+ // Any unrecognized flags can be retrieved by index number (0-based)
+ console.log(metadata.flag(0)) // The first unrecognized flag... returns null if it doesn't exist
+
+ // Execution callbacks are optional. If a callback is passed from the
+ // execution context to this handler, it will run after the command
+ // has finished processing
+ // (kind of like "next" in Express).
+ // Promises are also supported.
+ callback && callback()
+ }
+})
+
+const shell = new Shell({
+ name: 'myapp',
+ version: '1.0.0',
+ description: 'My demo app.',
+ // This middleware runs before all command handlers.
+ use: [
+ (meta, next) => { ...; next() }
+ ],
+ // Trailers are like "post-middleware" that run after command handlers.
+ trailer: [
+ (meta, next) => { ...; next() }
+ (meta, next) => { console.log('All done!') }
+ ],
+ commands: [
+ // These can be instances of Command...
+ list,
+
+ // or just the configuration of a Command
+ {
+ name: 'find',
+ description: 'Search metadoc for all the things.',
+ alias: 'search',
+ flags: {
+ x: {
+ type: 'string',
+ required: true
+ }
+ },
+ handler: (data, cb) => {
+ console.log(data)
+ console.log(`Mirroring input: ${data.input}`)
+
+ cb && cb()
+ }
+ // Subcommands are supported
+ // , commands: [...]
+ }
+ ]
+})
+
+// Run a command
+shell.exec('find "some query"')
+
+// Run a command using a promise.
+shell.exec('find "some query"').then(() => console.log('Done!))
+
+// Run a command using a callback (the callback is passed to the command's handler function)
+shell.exec('find "some query"', () => console.log('Handled!'))
+
+// Run a command, pass a callback to the handler, and use a promise to determine when everything is done.
+shell.exec('find "some query"', () => console.log('Handled!')).then(() => console.log('Done!))
+
+// Output the shell's default messages
+console.log(shell.help)
+console.log(shell.usage)
+console.log(shell.description)
+```
+
+## Custom Handlers
+
+Each command has a handler function, which is responsible for doing something. This command receives a reference to the parsed flags.
+
+```javascript
+{
+ command: ,
+ input: 'Raw string of flags/arguments passed to the command',
+ flags: {
+ recognized: {},
+ unrecognized: [
+ 'whatever',
+ 'user',
+ 'typed'
+ ]
+ },
+ flag (name) { return },
+ valid: false,
+ violations: []
+}
+```
+
+- **command** is the command name.
+- **input** is the string typed in after the command (flags)
+- **flags** contains the parsed flags from the [@author.io/arg](https://github.com/author/arg) library.
+- **`flag()`** is a special method for retrieving the value of any flag (recognized or unrecognized). See below.
+- **valid** indicates whether the input conforms to the parsing rules.
+- **violations** is an array of strings, where each string represents a violation of the parsing rules.
+- **data** _(getter)_ returns a key/value object with all of the known flags, as well as an _attempt_ to map any unrecognized flags with known argument names. (See basic example for argument example)
+
+
+Understanding flag()
+
+
+The `flag()` method is a shortcut to help developers create more maintainable and understandable code. Consider the following example that does **not** use the flag method:
+
+```javascript
+const cmd = new Command({
+ name: 'demo',
+ flags: {
+ a: { type: String },
+ b: { type: String }
+ },
+ handler: metadata => {
+ console.log(`A is "${metadata.flags.recognized.a}"`)
+ console.log(`B is "${metadata.flags.recognized.b}"`)
+ }
+})
+```
+
+Compare the example above to this cleaner version:
+
+```javascript
+const cmd = new Command({
+ name: 'demo',
+ flags: {
+ a: { type: String },
+ b: { type: String }
+ },
+ handler: metadata => {
+ console.log(`A is "${metadata.flag('a')}"`) // <-- Here
+ console.log(`B is "${metadata.flag('b')}"`) // <-- and here
+ }
+})
+```
+
+While the differences aren't extreme, it abstracts the need to know whether a flag is recognized or not (or even exists). If a `flag()` is executed for a non-existant flag, it will return `null`.
+
+
+
+Understanding data
+The `data` attribute supplied to handlers in the metadata argument contains the values for known flags, and _**attempts to map unknown arguments** to configured argument names_.
+
+For example,
+
+```javascript
+const shell = new Shell({
+ name: 'account',
+ commands: [{
+ name: 'create',
+ arguments: 'email displayName',
+ handler (meta) {
+ console.log(meta.data)
+ }
+ }]
+})
+
+shell.exec('create me@domain.com "John Doe" test1 test2')
+```
+
+_Output:_
+
+```json
+{
+ "email": "me@domain.com",
+ "displayName": "John Doe",
+ "unknown1": "test1",
+ "unknown2": "test2
+}
+```
+
+If there is a name conflict, the output will contain an array of values. For example:
+
+```javascript
+const shell = new Shell({
+ name: 'account',
+ commands: [{
+ name: 'create',
+ arguments: 'email displayName',
+ flags: {
+ email: {
+ alias: 'e'
+ }
+ },
+ handler (meta) {
+ console.log(meta.data)
+ }
+ }]
+})
+
+shell.exec('create me@domain.com -e bob@other.com')
+```
+
+_Output:_
+
+```json
+{
+ "email": ["bob@other.com", "me@domain.com"],
+ "displayName": "John Doe",
+}
+```
+
+> Notice the values from the known flags are _first_.
+
+
+## Plugins
+
+Plugins expose functions, objects, and primitives to shell handlers.
+
+_Example:_
+
+Consider an example where information is retrieved from a remote API. To do this, an HTTP request library may be necessary to make the request and parse the results. In this example, the axios library is defined as a plugin. The plugin is accessible in the metadata passed to each handler, as shown below.
+
+
+ Why would you do this?
+
+ Remember, the shell library can produce JSON (See the Introspection/Metadata Generation section). JSON is a string format for storing data. The output will contain a stringified version of all the handler functions. This can be used as the configuration for another instance of a shell. In other words, you can maintain a runtime-agnostic configuration. You could use _mostly_ the same configuration for the browser, Node, Deno, Vert.x, or another JavaScript runtime. However; the modules/packages like the HTTP request module may or may not work in each runtime.
+
+
+ Plugins allow developers to write handlers that are completely "self contained". It is then possible to modify the plugin configuration for each runtime without modifying every handler in the shell.
+
+
+
+
+```javascript
+import axios from 'axios'
+
+const sh = new Shell({
+ name: 'info',
+ plugins: {
+ httprequest: axios // replace this with any compatible library
+ },
+ commands: [{
+ name: 'person',
+ flags: {
+ name: {
+ description: 'Name of the person you want info about.',
+ required: true
+ }
+ },
+ handler (meta) {
+ meta.plugins.httprequest({
+ method: 'get',
+ url: `http://api.com/person/${meta.flag('name')}`
+ }).then(console.log).catch(console.error)
+ }
+ }, {
+ name: 'group',
+ flags: {
+ name: {
+ description: 'Name of the group you want info about.',
+ required: true
+ }
+ },
+ handler (meta) {
+ meta.plugins.httprequest({
+ method: 'get',
+ url: `http://api.com/group/${meta.flag('name')}`
+ }).then(console.log).catch(console.error)
+ }
+ }]
+})
+```
+
+Commands will inherit plugins from the shell and any parent commands. It is possible to "override" a plugin in any specific command.
+
+
+Override Example
+
+```javascript
+const sh = new Shell({
+ name: 'test',
+ plugins: {
+ test: value => {
+ return value + 1
+ }
+ },
+ commands: [{
+ name: 'cmd',
+ plugins: {
+ test: value => {
+ return value + 10
+ }
+ },
+ handler(meta) {
+ console.log(meta.test(1)) // Outputs 11
+ }
+ }]
+})
+```
+
+
+
+## Universal Flags
+_Common flags are automatically applied to multiple commands._
+
+Sometimes a CLI app has multiple commands/subcommands that need the same flag associated with each command/subcommand. For example, if a `--note` flag were needed on every command, it would be a pain to copy/paste the config into every single command. Common flags resolve this by automatically applying to all commands from the point where the common flag is configured (i.e. the point where inheritance/nesting begins).
+
+
+Apply a common flag to ALL commands
+To include the same flag on all commands, add a common flag to the shell.
+
+```javascript
+const shell = new Shell({
+ name: 'mycli',
+ commmonflags: {
+ note: {
+ alias: 'n',
+ description: 'Save a note about the operation.'
+ }
+ },
+ commands: [{
+ name: 'create',
+ flag: {
+ writable: {
+ alias: 'w',
+ description: 'Make it writable.'
+ }
+ },
+ ...
+ }, {
+ name: 'read',
+ ...
+ }]
+})
+
+shell.exec('create --help')
+shell.exec('read --help')
+```
+
+create output:
+```sh
+mycli create
+
+Flags:
+ note [-n] Save a note about the operation.
+ writable [-w] Make it writable.
+```
+
+read` output:
+```sh
+mycli read
+
+Flags:
+ note [-n] Save a note about the operation.
+```
+
+
+
+Apply a common flag to a specific command/subcommands
+
+```javascript
+const shell = new Shell({
+ name: 'mycli',
+ commands: [{
+ name: 'create',
+ commmonflags: {
+ note: {
+ alias: 'n',
+ description: 'Save a note about the operation.'
+ }
+ },
+ flag: {
+ writable: {
+ alias: 'w',
+ description: 'Make it writable.'
+ }
+ },
+ commands: [...]
+ ...
+ }, {
+ name: 'read',
+ description: 'Read a directory.',
+ ...
+ }]
+})
+
+shell.exec('create --help')
+shell.exec('read --help')
+```
+
+_`create` output:_
+```sh
+mycli create
+
+Flags:
+ note [-n] Save a note about the operation.
+ writable [-w] Make it writable.
+```
+
+_`read` output:_
+```sh
+mycli read
+
+ Read a directory.
+
+```
+
+
+#### Filtering Universal Flags
+
+Universal/common flags accept a special attribute named `ignore`, which will prevent the flags from being applied to specific commands. This should be used sparingly.
+
+
+Cherry-picking example
+
+
+```javascript
+const shell = new Shell({
+ name: 'mycli',
+ commmonflags: {
+ ignore: 'info', // This can also be an array of string. Fully qualified subcommands will also be respected.
+ note: {
+ alias: 'n',
+ description: 'Save a note about the operation.'
+ }
+ },
+ commands: [{
+ name: 'create',
+ handler () {}
+ }, {
+ name: 'read',
+ handler () {}
+ }, {
+ name: 'update',
+ handler () {}
+ }, {
+ name: 'delete',
+ handler () {}
+ }, {
+ name: 'info',
+ handler () {}
+ }]
+})
+```
+
+Any command, except `info`, will accepts/parse the `note` flag.
+
+
+
+## Middleware
+
+When a command is called, it's handler function is executed. Sometimes it is desirable to pre-process one or more commands. The shell middleware feature supports "global" middleware and "assigned" middleware.
+
+### Global Middleware
+
+This middleware is applied to all handlers, unilaterally. It is useful for catching syntax errors in commands, preprocessing data, and anything else you may want to do before the actual handler is executed.
+
+For example, the following middleware checks the input to determine if all of the appropriate flags have been set. If not, the violations are displayed and the handler is never run. If everything is correct, the `next()` method will continue processing.
+
+```javascript
+shell.use(function (metadata, next) {
+ if (!metadata.valid) {
+ metadata.violations.forEach(violation => console.log(violation))
+ } else {
+ next()
+ }
+})
+```
+
+No matter which command the user inputs, the global middleware methods are executed.
+
+### Assigned Middleware
+
+This middleware is assigned to one or more commands. For example:
+
+```javascript
+shell.useWith('demo', function (metadata, next) {
+ if (metadata.flag('a') === null) {
+ console.log('No "a" flag specified. This may slow down processing.')
+ }
+
+ next()
+})
+```
+
+The code above would only run when the user inputs the `demo` command (or any `demo` subcommand).
+
+#### Command-Specific Assignments
+
+It is possible to assign middleware to more than one command at a time, and it is possible to target subcommands. For example:
+
+```javascript
+shell.useWith(['demo', 'command subcommand'], function (metadata, next) {
+ if (metadata.flag('a') === null) {
+ console.log('I hope you know what you are doing!')
+ }
+
+ next()
+})
+```
+
+Notice the array as the first argument of the `useWith` method. This middleware would be assigned to `demo` command, all `demo` subcommands, the `subcommand` of `command`, and all subcommands of `subcommand`. If this sounds confusing, just know that middleware is applied to commands, including nested commands.
+
+Assigned middleware can also be applied directly to a `Command` class. For example,
+
+```javascript
+const cmd = new Command({
+ name: 'demo',
+ flags: {
+ a: { type: String },
+ b: { type: String }
+ },
+ handler: metadata => {
+ console.log(metadata)
+ }
+})
+
+cmd.use(function (metadata, next) {
+ console.log(`this middleware is specific to the "${cmd.name}" command`)
+ next()
+})
+```
+
+#### Command-Exclusion Assignments
+
+Sometimes middleware needs to be applied to all but a few commands. The `useExcept` method supports these needs. It is basically the opposite of `useWith`. Middleware is applied to all commands/subcommands _except_ those specified.
+
+For example:
+
+```javascript
+const shell = new Shell({
+ ...,
+ commands: [{
+ name: 'add',
+ handler (meta) {
+ ...
+ }
+ }, {
+ name: 'subtract',
+ handler (meta) {
+ ...
+ }
+ }, {
+ name: 'info',
+ handler (meta) {
+ ...
+ }
+ }]
+})
+
+shell.useExcept(['info], function (meta, next) {
+ console.log(`this middleware is only applied to some math commands`)
+ next()
+})
+```
+
+In this example, the console statement would be displayed for all commands except the `info` command (and any info subcommands).
+
+### Built-in "Middleware"
+
+Displaying help and version information is built-in (overridable).
+
+**Help**
+
+Appending `--help` to anything will display the help content for the shell/command/subcommand. This will respect any custom usage/help configurations that may be defined.
+
+**Shell Version**
+
+A `version` command is available on the shell. For example:
+
+```sh
+$ cmd version
+1.0.0
+```
+
+The following common flag variations map to the version command, producing the same output:
+
+```sh
+$ cmd --version
+1.0.0
+
+$ cmd -v
+1.0.0
+```
+
+This can be overridden by creating a command called `version`, the same way any other command is created.
+
+```javascript
+const v = new Command({
+ name: 'version',
+ handler (meta) {
+ console.log(this.shell.version)
+ }
+})
+
+shell.add(v)
+```
+
+### Middleware Libraries
+
+One development goal of this framework is to remain as lightweight and unopinionated as possible. Another is to be as simple to use as possible. These two goals often conflict with each other (the more features you add, the heavier it becomes). In an attempt to find a comfortable balance, some additional middleware libraries are available for those who want a little extra functionality.
+
+1. [@author.io/shell-middleware](https://github.com/author/shell-middleware)
+1. Submit a PR to add yours here.
+
+### Trailers
+_(Postware/Afterware)_
+
+Trailers operate just like middleware, but they execute _after_ the command handler is executed.
+
+```javascript
+const shell = new Shell({
+ name: 'mycli',
+ trailer: [
+ function () { console.log('Done!' ) }
+ ],
+ command: [{
+ name: 'dir',
+ handler () {
+ console.log('ls -l')
+ },
+ // Subcommands
+ commands: [{
+ name: 'perm',
+ description: 'Permissions',
+ handler () {
+ console.log('Display permissions for a directory.')
+ }
+ }]
+ }]
+})
+
+// Execute the "dir" command
+shell.exec('dir')
+
+// Execute the "perm" subcommand
+shell.exec('dir perm')
+```
+
+_`dir` command output:_
+```sh
+ls -l
+Done!
+```
+
+_`dir perm` subcommand output:_
+```sh
+Display permissions for a directory.
+Done!
+```
+
+### Customized Help/Usage Messages
+
+**Customizing Flag Appearance:**
+
+The `Shell` and `Command` classes can both accept several boolean attributes to customize the description of each flag within a command. Each of these is `true` by default.
+
+1. `describeDefault`: Display the default flag value.
+1. `describeOptions`: List the valid options for a flag.
+1. `describeMultipleValues`: Appends `Can be used multiple times.` to the flag description
+1. `describeRequired`: Prepends `Required.` to the flag description whenever a flag is required.
+
+
+Example
+
+
+```javascript
+const c = new Command({
+ name: '...',
+ flags: {
+ name: {
+ alias: 'nm',
+ required: true,
+ default: 'Rad Dev',
+ allowMultipleValues: true,
+ options: ['Mr Awesome', 'Mrs Awesome', 'Rad Dev'],
+ description: 'Specify a name.'
+ }
+ }
+})
+```
+
+The help message for this flag would look like:
+
+```sh
+Flags:
+ -name ['nm'] Required. Specify a name. Options: Mr
+ Awesome, Mrs Awesome, Rad Dev. Can be
+ used multiple times. (Default Rad Dev)
+```
+
+
+
+**Customizing the Entire Message:**
+
+This library uses a vanilla dependency (i.e. no-subdependencies) called [@author.io/table](https://github.com/author/table) to format the usage and help messages of the shell. The `Table` library can be used to create your own custom screens, though most users will likely want to stick with the defaults. If you want to customize messages, the following example can be used as a starting point. The configuration options for the table can be found in the README of its repository.
+
+```javascript
+import { Shell, Command, Table } from '@author.io/shell'
+
+const shell = new Shell(...)
+shell.usage = '...'
+shell.help = () => {
+ const rows = [
+ ['Command', 'Alias Names'],
+ ['...', '...']
+ ]
+
+ const table = new Table(rows)
+
+ return shell.usage + '\n' + table.output
+}
+```
+
+**The `usage` and/or `help` attributes of an individual `Command` can also be set:**
+
+```javascript
+import { Shell, Command, Table } from '@author.io/shell'
+
+const cmd = new Command(...)
+cmd.usage = '...'
+cmd.help = () => {
+ const rows = [
+ ['Flags', 'Alias Names'],
+ ['...', '...']
+ ]
+
+ const table = new Table(rows)
+
+ return cmd.usage + '\n' + table.output
+}
+```
+
+There is also a `Formatter` class that helps combine usage/help messages internally. This class is exposed for those who want to dig into the inner workings, but it should be considered as more of an example than a supported feature. Since it is an internal class, it may change without warning (though we'll try to keep the methods consistent across releases).
+
+### Introspection/Metadata Generation
+
+A JSON metadoc can be produced from the shell:
+
+```javascript
+console.log(shell.data)
+```
+
+Simple CLI utilities can also be loaded entirely from a JSON file by passing the object into the shell constructor as the only argument. The limitation is no imports or hoisted variables/methods will be recognized in a shell which is loaded this way.
+
+### Autocompletion/Input Hints
+
+This library can use a _command hinting_ feature, i.e. a shell `hint()` method to return suggestions/hints about a partial command. This feature was part of the library through the `v1.5.x` release lifecycle. In `v.1.6.0+`, this feature is no longer a part of the core library. It is now available as the [author/shell-hints plugin](https://github.com/author/shell-hints).
+
+Consider the following shell:
+
+```javascript
+import HintPlugin from 'https://cdn.pika.dev/@author.io/browser-shell-hints'
+
+const shell = new Shell({
+ name: 'mycli',
+ command: [{
+ name: 'dir',
+ handler () {
+ console.log('ls -l')
+ },
+ // Subcommands
+ commands: [{
+ name: 'perm',
+ description: 'Permissions',
+ handler () {
+ console.log('Display permissions for a directory.')
+ }
+ }, {
+ name: 'payload',
+ description: 'Payload',
+ handler () {
+ console.log('Display payload/footprint for a directory.')
+ }
+ }]
+ }]
+})
+
+HintPlugin.apply(shell) // <-- Adds the hint method.
+
+// Help us figure out what we can do!
+console.log(shell.hint('dir p'))
+```
+
+_Output:_
+
+```sh
+{
+ commands: ['perm', 'payload'],
+ flags: []
+}
+```
+
+The hint matches "**dir p**ermission" and "**dir p**ayload", but does not match any flags.
+
+If no options/hints are available, `null` is returned.
+
+While this add-on provides input hints that could be used for suggestions/completions, it does **not** generate autocompletion files for shells like bash, zsh, fish, powershell, etc.
+
+> There are many variations of autocompletion for different shells, which are not available in browsers (see our Devtools extension for browser completion).
+
+If you wish to generate your own autocompletion capabilities, use the `shell.data` attribute to retrieve data for the shell (see prior section). For terminals, consider using the shell metadata with a module like [omlette](https://github.com/f/omelette) to produce autocompletion for your favorite terminal app. For browser-based CLI apps, consider using our devtools extension for an autocompletion experience.
+
+## Installation
+
+### Node.js
+
+
+Modern (ES Modules)
+
+
+```sh
+npm install @author.io/shell --save
+```
+
+Please note, you'll need a verison of Node that supports ES Modules. In Node 12, this feature is behind the `--experimental-modules` flag. It is available in Node 13+ without a flag, but the `package.json` file must have the `"type": "module"` attribute. This feature is generally available in [Node 14.0.0](https://nodejs.org) and above.
+
+
+
+Legacy (CommonJS/require)
+
+
+DEPRECATED
+
+If you need to use the older CommonJS format (i.e. `require`), run `npm install @author.io/shell-legacy` instead.
+
+
+### Browsers
+
+**CDN**
+
+```javascript
+import { Shell, Command } from 'https://cdn.pika.dev/@author.io/shell'
+```
+
+Also available from [jsdelivr](https://www.jsdelivr.com/package/npm/@author.io/shell/index.js) and [unpkg](https://unpkg.com/@author.io/shell/index.js).
+
+### Debugging
+
+Each distribution has a corresponding `-debug` version that should be installed _alongside_ the main module (the debugging is an add-on module). For example, `npm install @author.io/shell-debug --save-dev` would install the debugging code for Node. In the browser, appending the debug library adds sourcemaps.
+
+### Related Modules
+
+1. [@author.io/table](https://github.com/author/table) - Used to generate the default usage/help messages for the shell and subcommands.
+
+**Sponsors (as of 2020)**
+
+
+
+
+
+
+
diff --git a/dist/shell/index.js b/dist/shell/index.js
new file mode 100644
index 0000000..d887997
--- /dev/null
+++ b/dist/shell/index.js
@@ -0,0 +1,5 @@
+// @author.io/shell v1.8.18
+// Copyright (c) 2022 Corey Butler
+// Released under the MIT License.
+import{Parser}from"@author.io/arg";import Table from"@author.io/table";export{default as Table}from"@author.io/table";function _classPrivateFieldGet(receiver,privateMap){return function _classApplyDescriptorGet(receiver,descriptor){return descriptor.get?descriptor.get.call(receiver):descriptor.value}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"get"))}function _classPrivateFieldSet(receiver,privateMap,value){return function _classApplyDescriptorSet(receiver,descriptor,value){if(descriptor.set)descriptor.set.call(receiver,value);else{if(!descriptor.writable)throw new TypeError("attempted to set read only private field");descriptor.value=value}}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"set"),value),value}function _classExtractFieldDescriptor(receiver,privateMap,action){if(!privateMap.has(receiver))throw new TypeError("attempted to "+action+" private field on non-instance");return privateMap.get(receiver)}class Middleware{constructor(){Object.defineProperties(this,{_data:{enumerable:!1,configurable:!1,value:[]},go:{enumerable:!1,configurable:!1,writable:!0,value:(...args)=>{args.pop().apply(this,args)}}})}get size(){return this._data.length}get data(){return this._data}use(method){const methodBody=method.toString();methodBody.indexOf("[native code]")<0&&this._data.push(methodBody),this.go=(stack=>(...args)=>{const next=args.pop();stack(...args,()=>{method.apply(this,[...args,next.bind(null,...args)])})})(this.go)}run(){const args=Array.from(arguments);0!==args.length&&"function"==typeof args[args.length-1]||args.push(()=>{}),this.go(...args)}}var _data=new WeakMap,_tableWidth=new WeakMap,_colAlign=new WeakMap,_colWidth=new WeakMap;class Formatter{constructor(data){_data.set(this,{writable:!0,value:null}),_tableWidth.set(this,{writable:!0,value:80}),_colAlign.set(this,{writable:!0,value:[]}),_colWidth.set(this,{writable:!0,value:["20%","15%","65%"]}),_classPrivateFieldSet(this,_data,data)}set width(value){_classPrivateFieldSet(this,_tableWidth,value<20?20:value)}set columnWidths(value){_classPrivateFieldSet(this,_colWidth,value)}set columnAlignment(value){_classPrivateFieldSet(this,_colAlign,value)}get usage(){const desc=_classPrivateFieldGet(this,_data).description.trim();if(_classPrivateFieldGet(this,_data)instanceof Command){const aliases=_classPrivateFieldGet(this,_data).aliases,out=[`${_classPrivateFieldGet(this,_data).commandroot}${aliases.length>0?"|"+aliases.join("|"):""}${_classPrivateFieldGet(this,_data).__flagConfig.size>0?" [FLAGS]":""}${_classPrivateFieldGet(this,_data).arguments.size>0?" "+Array.from(_classPrivateFieldGet(this,_data).arguments).map(i=>"<"+i+">").join(" "):""}`];return _classPrivateFieldGet(this,_data).__processors.size>0&&(out[out.length-1]+=(_classPrivateFieldGet(this,_data).arguments.size>0||_classPrivateFieldGet(this,_data).__flagConfig.size>0?" |":"")+" [COMMAND]"),desc.trim().length>0&&out!==desc&&out.push(new Table([[desc.trim().replace(/\n/gi,"\n ")]],null,null,_classPrivateFieldGet(this,_tableWidth),[2,0,1,1]).output),out.join("\n")}return _classPrivateFieldGet(this,_data)instanceof Shell?`${_classPrivateFieldGet(this,_data).name}${_classPrivateFieldGet(this,_data).__processors.size>0?" [COMMAND]":""}\n${desc.trim().length>0?new Table([[desc.trim().replace(/\n/gi,"\n ")]],null,null,_classPrivateFieldGet(this,_tableWidth),[2,0,1,1]).output:""}${_classPrivateFieldGet(this,_data).arguments.size>0?" "+Array.from(_classPrivateFieldGet(this,_data).arguments).map(i=>"["+i+"]").join(" "):""}\n`.trim():""}get subcommands(){const rows=Array.from(_classPrivateFieldGet(this,_data).__processors.values()).map(cmd=>[[cmd.name].concat(cmd.aliases).join("|"),cmd.description]),result=[];if(rows.length>0){const table=new Table(rows,_classPrivateFieldGet(this,_colAlign),["25%","75%"],_classPrivateFieldGet(this,_tableWidth),[2]);result.push("\nCommands:\n"),result.push(table.output)}return result.join("\n")}get help(){const usage=this.usage.trim();if(_classPrivateFieldGet(this,_data)instanceof Command){const flags=_classPrivateFieldGet(this,_data).__flagConfig,rows=[];flags.size>0&&flags.forEach((cfg,flag)=>{let aliases=Array.from(cfg.aliases||cfg.alias||[]);aliases=0===aliases.length?"":"["+aliases.map(a=>"-"+a).join(", ")+"]";let dsc=[cfg.description||""];cfg.hasOwnProperty("options")&&_classPrivateFieldGet(this,_data).describeOptions&&dsc.push(`Options: ${cfg.options.join(", ")}.`),cfg.hasOwnProperty("allowMultipleValues")&&!0===cfg.allowMultipleValues&&_classPrivateFieldGet(this,_data).describeMultipleValues&&dsc.push("Can be used multiple times."),cfg.hasOwnProperty("default")&&_classPrivateFieldGet(this,_data).describeDefault&&dsc.push(`(Default: ${cfg.default.toString()})`),cfg.hasOwnProperty("required")&&!0===cfg.required&&_classPrivateFieldGet(this,_data).describeRequired&&dsc.unshift("Required."),dsc=dsc.join(" ").trim(),rows.push(["--"+flag,aliases||"",dsc||""])});const table=new Table(rows,_classPrivateFieldGet(this,_colAlign),_classPrivateFieldGet(this,_colWidth),_classPrivateFieldGet(this,_tableWidth),[2,0,usage.length>0?1:0,0]);let subcommands="\n"+this.subcommands;return 0===subcommands.trim().length&&(subcommands=""),usage+(flags.size>0?"\n\nFlags:\n"+table.output:"")+subcommands}return _classPrivateFieldGet(this,_data)instanceof Shell?[usage,this.subcommands].join("\n"):""}}var _plugins=new WeakMap,_url=new WeakMap,_support=new WeakMap,_formattedDefaultHelp=new WeakMap,_description=new WeakMap,_customUsage=new WeakMap,_customHelp=new WeakMap,_arguments=new WeakMap,_autohelp=new WeakMap,_processors=new WeakMap,_commands=new WeakMap,_width=new WeakMap,_name=new WeakMap,_middleware=new WeakMap,_trailer=new WeakMap,_commonflags=new WeakMap,_display=new WeakMap,_hasCustomDefaultHandler=new WeakMap,_defaultHandler=new WeakMap;class Base{constructor(cfg={}){if(_plugins.set(this,{writable:!0,value:{}}),_url.set(this,{writable:!0,value:null}),_support.set(this,{writable:!0,value:null}),_formattedDefaultHelp.set(this,{writable:!0,value:void 0}),_description.set(this,{writable:!0,value:void 0}),_customUsage.set(this,{writable:!0,value:void 0}),_customHelp.set(this,{writable:!0,value:void 0}),_arguments.set(this,{writable:!0,value:new Set}),_autohelp.set(this,{writable:!0,value:!0}),_processors.set(this,{writable:!0,value:new Map}),_commands.set(this,{writable:!0,value:new Map}),_width.set(this,{writable:!0,value:80}),_name.set(this,{writable:!0,value:"Unknown"}),_middleware.set(this,{writable:!0,value:new Middleware}),_trailer.set(this,{writable:!0,value:new Middleware}),_commonflags.set(this,{writable:!0,value:{}}),_display.set(this,{writable:!0,value:{Default:null,Options:null,MultipleValues:null,Required:null}}),_hasCustomDefaultHandler.set(this,{writable:!0,value:!1}),_defaultHandler.set(this,{writable:!0,value:function(meta){return null!==this.parent&&this.parent.hasCustomDefaultHandler?this.parent.defaultHandler(...arguments):this.shell&&null!==this.shell&&this.shell.hasCustomDefaultHandler?this.shell.defaultHandler(...arguments):void(_classPrivateFieldGet(this,_autohelp)&&console.log(this.help))}}),"object"!=typeof cfg)throw new Error("Invalid command configuration. Expected an object.");if(!cfg.hasOwnProperty("name"))throw new Error('Invalid command configuration. A "name" attribute is required.');if(cfg.hasOwnProperty("help")&&_classPrivateFieldSet(this,_customHelp,cfg.help),cfg.hasOwnProperty("usage")&&_classPrivateFieldSet(this,_customUsage,cfg.usage),cfg.hasOwnProperty("disablehelp")&&!cfg.hasOwnProperty("disableHelp")&&(cfg.disableHelp=cfg.disablehelp),cfg.hasOwnProperty("disableHelp")&&!0===cfg.disableHelp&&_classPrivateFieldSet(this,_autohelp,!1),"function"!=typeof cfg.help&&"string"!=typeof cfg.help||(this.help=cfg.help),"function"!=typeof cfg.usage&&"string"!=typeof cfg.usage||(this.usage=cfg.usage),cfg.hasOwnProperty("defaultHandler")&&cfg.defaultHandler.toString()!==_classPrivateFieldGet(this,_defaultHandler).toString()&&(this.defaultHandler=cfg.defaultHandler),"string"==typeof cfg.arguments&&(cfg.arguments=cfg.arguments.split(/\s+|\t+|\,+|\;+/).map(arg=>arg.trim())),Array.isArray(cfg.arguments)&&_classPrivateFieldSet(this,_arguments,new Set(cfg.arguments)),"string"==typeof cfg.url&&_classPrivateFieldSet(this,_url,cfg.url),"string"==typeof cfg.support&&_classPrivateFieldSet(this,_support,cfg.support),_classPrivateFieldSet(this,_name,(cfg.name||"unknown").trim().split(/\s+/)[0]),_classPrivateFieldSet(this,_description,cfg.description||null),Array.isArray(cfg.commands))cfg.commands.forEach(cmd=>this.add(cmd));else if("object"==typeof cfg.commands)for(const key in cfg.commands){const data=cfg.commands[key];data.name=key,this.add(data)}if(cfg.hasOwnProperty("middleware")&&(console.warn('The "middleware" attribute has been replaced with the "use" attribute.'),cfg.use=cfg.middleware,delete cfg.middleware),cfg.hasOwnProperty("commonflag")||(cfg.hasOwnProperty("commonFlag")?cfg.commonflag=cfg.commonFlag:cfg.hasOwnProperty("commonflags")?cfg.commonflag=cfg.commonflags:cfg.hasOwnProperty("commonFlag")?cfg.commonflag=cfg.commonFlag:cfg.hasOwnProperty("commonFlags")&&(cfg.commonflag=cfg.commonFlags)),cfg.hasOwnProperty("commonflag")&&"object"!=typeof cfg.commonflag)throw new Error('The "commonflag" configuration attribute must be an object.');"object"==typeof cfg.plugins&&_classPrivateFieldSet(this,_plugins,cfg.plugins),Object.defineProperties(this,{__processors:{enumerable:!1,get(){return _classPrivateFieldGet(this,_processors)}},__commands:{enumerable:!1,get(){return _classPrivateFieldGet(this,_commands)}},__width:{enumerable:!1,get(){return _classPrivateFieldGet(this,_width)},set(v){_classPrivateFieldSet(this,_width,v||80)}},__commonflags:{enumerable:!1,get(){return _classPrivateFieldGet(this,_commonflags)},set(value){_classPrivateFieldSet(this,_commonflags,value)}},arguments:{enumerable:!1,get(){return _classPrivateFieldGet(this,_arguments)}},initializeMiddleware:{enumerable:!1,configurable:!1,writable:!1,value:code=>{if("string"==typeof code)this.use(Function("return "+code)());else{if("function"!=typeof code)throw new Error("Invalid middleware: "+code.toString());this.use(code)}}},initializeTrailer:{enumerable:!1,configurable:!1,writable:!1,value:code=>{if("string"==typeof code)this.trailer(Function("return "+code)());else{if("function"!=typeof code)throw new Error("Invalid trailer: "+code.toString());this.trailer(code)}}},initializeHelpAnnotations:{enumerable:!1,configurable:!1,writable:!1,value:cfg=>{cfg.hasOwnProperty("describeDefault")&&"boolean"==typeof cfg.describeDefault&&(_classPrivateFieldGet(this,_display).Default=cfg.describeDefault),cfg.hasOwnProperty("describeOptions")&&"boolean"==typeof cfg.describeOptions&&(_classPrivateFieldGet(this,_display).Options=cfg.describeOptions),cfg.hasOwnProperty("describeMultipleValues")&&"boolean"==typeof cfg.describeMultipleValues&&(_classPrivateFieldGet(this,_display).MultipleValues=cfg.describeMultipleValues),cfg.hasOwnProperty("describeRequired")&&"boolean"==typeof cfg.describeRequired&&(_classPrivateFieldGet(this,_display).Required=cfg.describeRequired)}}}),this.updateHelp()}get plugins(){return _classPrivateFieldGet(this,_plugins)}get name(){return _classPrivateFieldGet(this,_name)||"Unknown"}get description(){return _classPrivateFieldGet(this,_description)||this.usage||""}get url(){return this.URL}get URL(){const uri=(_classPrivateFieldGet(this,_url)||"").trim();if(0===uri.length){if(this.hasOwnProperty("parent"))return this.parent.URL;if(this instanceof Command)return this.shell.URL}return uri}get support(){const support=(_classPrivateFieldGet(this,_support)||"").trim();if(0===support.length){if(this.hasOwnProperty("parent"))return this.parent.support;if(this instanceof Command)return this.shell.support}return support}get autohelp(){return _classPrivateFieldGet(this,_autohelp)}set autohelp(value){"boolean"==typeof value&&(_classPrivateFieldSet(this,_autohelp,value),_classPrivateFieldGet(this,_processors).forEach(cmd=>{cmd.autohelp=value}))}updateHelp(){_classPrivateFieldSet(this,_formattedDefaultHelp,new Formatter(this)),_classPrivateFieldGet(this,_formattedDefaultHelp).width=_classPrivateFieldGet(this,_width)}describeHelp(attr,prop){if(null!==_classPrivateFieldGet(this,_display)[prop])return _classPrivateFieldGet(this,_display)[prop];if(this instanceof Command){if(this.shell&&null!==this.shell&&null!==this.shell[attr])return this.shell[attr];if(null!==this.parent)return this.parent[attr]}return!0}get describeDefault(){return this.describeHelp("describeDefault","Default")}get describeOptions(){return this.describeHelp("describeOptions","Options")}get describeMultipleValues(){return this.describeHelp("describeMultipleValues","MultipleValues")}get describeRequired(){return this.describeHelp("describeRequired","Required")}get usage(){return null!==_classPrivateFieldGet(this,_customUsage)?"function"==typeof _classPrivateFieldGet(this,_customUsage)?_classPrivateFieldGet(this,_customUsage).call(this):_classPrivateFieldGet(this,_customUsage):_classPrivateFieldGet(this,_formattedDefaultHelp).usage}set usage(value){"string"==typeof value&&0===value.trim().length&&(value=null),_classPrivateFieldSet(this,_customUsage,value),this.updateHelp()}get help(){return _classPrivateFieldGet(this,_customHelp)?"function"==typeof _classPrivateFieldGet(this,_customHelp)?_classPrivateFieldGet(this,_customHelp).call(this,this):_classPrivateFieldGet(this,_customHelp):this.autohelp?_classPrivateFieldGet(this,_formattedDefaultHelp).help:""}set help(value){"string"==typeof value&&0===value.trim().length&&(value=null),_classPrivateFieldSet(this,_customHelp,value),this.updateHelp()}set defaultHandler(value){if("function"!=typeof value)throw new Error(`Invalid default method (must be a function, not "${typeof value}").`);_classPrivateFieldSet(this,_defaultHandler,value),_classPrivateFieldSet(this,_hasCustomDefaultHandler,!0),_classPrivateFieldGet(this,_processors).forEach(cmd=>{cmd.defaultProcessor=value})}get defaultHandler(){return _classPrivateFieldGet(this,_defaultHandler)}get hasCustomDefaultHandler(){return _classPrivateFieldGet(this,_hasCustomDefaultHandler)}get data(){const commands={};return Array.from(_classPrivateFieldGet(this,_processors).values()).forEach(cmd=>{const data=cmd.data,name=data.name;delete data.name,commands[name]=data}),commands}get middleware(){return _classPrivateFieldGet(this,_middleware)}get trailers(){return _classPrivateFieldGet(this,_trailer)}get commands(){return _classPrivateFieldGet(this,_processors)}get commandlist(){const list=new Set;return this.commands.forEach(cmd=>{list.add(cmd.name),cmd.commandlist.forEach(subcmd=>list.add(`${cmd.name} ${subcmd}`))}),Array.from(list).sort()}getCommand(name=null){if(!name)return null;const names=name.split(/\s+/i);let cmd=_classPrivateFieldGet(this,_commands).get(names.shift());if(cmd){cmd=_classPrivateFieldGet(this,_processors).get(cmd);for(const nm of names)cmd=cmd.getCommand(nm)}return cmd instanceof Command?cmd:null}remove(){for(const cmd of arguments)if("symbol"==typeof cmd&&(_classPrivateFieldGet(this,_processors).delete(cmd),_classPrivateFieldGet(this,_commands).forEach(oid=>oid===cmd&&_classPrivateFieldGet(this,_commands).delete(oid))),"string"==typeof cmd){const OID=_classPrivateFieldGet(this,_commands).get(cmd);OID&&this.remove(OID)}}use(){for(const arg of arguments){if("function"!=typeof arg)throw new Error(`All "use()" arguments must be valid functions.\n${arg.toString().substring(0,50)} ${arg.toString().length>50?"...":""}`);_classPrivateFieldGet(this,_middleware).use(arg)}_classPrivateFieldGet(this,_processors).forEach(subCmd=>subCmd.use(...arguments))}trailer(){_classPrivateFieldSet(this,_trailer,_classPrivateFieldGet(this,_trailer)||new Middleware);for(const arg of arguments){if("function"!=typeof arg)throw new Error(`All "trailer()" arguments must be valid functions.\n${arg.toString().substring(0,50)} ${arg.toString().length>50?"...":""}`);_classPrivateFieldGet(this,_trailer).use(arg)}_classPrivateFieldGet(this,_processors).forEach(subCmd=>subCmd.trailer(...arguments))}add(){for(let command of arguments){if(!(command instanceof Command)){if("object"!=typeof command)throw new Error('Invalid argument. Only "Command" instances may be added to the processor.');command=new Command(command)}command.autohelp=this.autohelp,this instanceof Shell?command.shell=this:this instanceof Command&&(command.parent=this),_classPrivateFieldGet(this,_processors).set(command.OID,command),_classPrivateFieldGet(this,_commands).set(command.name,command.OID),command.aliases.forEach(alias=>_classPrivateFieldGet(this,_commands).set(alias,command.OID))}}}const FLAG_PATTERN=/((?:"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|\/[^\/\\]*(?:\\[\S\s][^\/\\]*)*\/[gimy]*(?=\s|$)|(?:\\\s|\S))+)(?=\s|$)/g,METHOD_PATTERN=/^([\w]+\s?)\(.*\)\s?{/i,STRIP_QUOTE_PATTERN=/"([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'/gi,COMMAND_PATTERN=/^(\w+)\s+([\s\S]+)?/i;Object.freeze({SUBCOMMAND_PATTERN:/^([^"'][\S\b]+)[\s+]?([^-].*)$/i,FLAG_PATTERN:FLAG_PATTERN,METHOD_PATTERN:METHOD_PATTERN,STRIP_QUOTE_PATTERN:STRIP_QUOTE_PATTERN,COMMAND_PATTERN:COMMAND_PATTERN});var _middlewareGroups=new WeakMap,_history=new WeakMap,_maxHistoryItems=new WeakMap,_version=new WeakMap,_cursor=new WeakMap,_tabWidth=new WeakMap,_runtime=new WeakMap;class Shell extends Base{constructor(cfg={maxhistory:100}){super(cfg),_middlewareGroups.set(this,{writable:!0,value:new Map}),_history.set(this,{writable:!0,value:[]}),_maxHistoryItems.set(this,{writable:!0,value:void 0}),_version.set(this,{writable:!0,value:void 0}),_cursor.set(this,{writable:!0,value:0}),_tabWidth.set(this,{writable:!0,value:void 0}),_runtime.set(this,{writable:!0,value:globalThis.hasOwnProperty("window")?"browser":globalThis.hasOwnProperty("process")&&globalThis.process.release&&globalThis.process.release.name?globalThis.process.release.name:"unknown"}),this.initializeHelpAnnotations(cfg),this.__commonflags=cfg.commonflags||{},cfg.hasOwnProperty("use")&&Array.isArray(cfg.use)&&cfg.use.forEach(code=>this.initializeMiddleware(code)),cfg.hasOwnProperty("trailer")&&Array.isArray(cfg.trailer)&&cfg.trailer.forEach(code=>this.initializeTrailer(code)),_classPrivateFieldSet(this,_version,cfg.version||"1.0.0"),_classPrivateFieldSet(this,_maxHistoryItems,cfg.maxhistory||cfg.maxHistoryItems||100),_classPrivateFieldSet(this,_tabWidth,cfg.hasOwnProperty("tabWidth")?cfg.tabWidth:4),globalThis[Symbol("SHELL_INTEGRATIONS")]=this}get data(){const commands=super.data;return{name:this.name,description:this.description,version:this.version,commands:commands,use:this.middleware.data,trailer:this.trailers.data,help:this.help,usage:this.usage,defaultHandler:this.defaultHandler.toString(),disableHelp:!this.autohelp,runtime:_classPrivateFieldGet(this,_runtime),maxHistoryItems:_classPrivateFieldGet(this,_maxHistoryItems)}}get version(){return _classPrivateFieldGet(this,_version)||"Unknown"}set tableWidth(value){this.__width=value}get tableWidth(){return this.__width}history(count=null){return 0===_classPrivateFieldGet(this,_history).length?[]:null===count?_classPrivateFieldGet(this,_history).slice():_classPrivateFieldGet(this,_history).slice(0,count)}priorCommand(count=0){return 0===_classPrivateFieldGet(this,_history).length?null:count<0?this.nextCommand(Math.abs(count)):(count%=_classPrivateFieldGet(this,_history).length,_classPrivateFieldSet(this,_cursor,_classPrivateFieldGet(this,_cursor)+count),_classPrivateFieldGet(this,_cursor)>=_classPrivateFieldGet(this,_history).length&&_classPrivateFieldSet(this,_cursor,_classPrivateFieldGet(this,_history).length-1),_classPrivateFieldGet(this,_history)[_classPrivateFieldGet(this,_cursor)].input)}nextCommand(count=1){return 0===_classPrivateFieldGet(this,_history).length?null:count<0?this.priorCommand(Math.abs(count)):(count%=_classPrivateFieldGet(this,_history).length,_classPrivateFieldSet(this,_cursor,_classPrivateFieldGet(this,_cursor)-count),_classPrivateFieldGet(this,_cursor)<0?void _classPrivateFieldSet(this,_cursor,0):_classPrivateFieldGet(this,_history)[_classPrivateFieldGet(this,_cursor)].input)}useWith(commands){if(arguments.length<2)throw new Error("useWith(['command', 'command'], fn) requires two or more arguments.");if(commands="string"==typeof commands?commands.split(/\s+/):commands,!Array.isArray(commands)||commands.filter(c=>"string"!=typeof c).length>0)throw new Error("The first argument of useWith must be a string or array of strings. Received "+typeof commands);const fns=Array.from(arguments).slice(1);commands.forEach(cmd=>_classPrivateFieldGet(this,_middlewareGroups).set(cmd.trim(),(_classPrivateFieldGet(this,_middlewareGroups).get(cmd.trim())||[]).concat(fns)))}useExcept(commands){if(arguments.length<2)throw new Error("useExcept(['command', 'command'], fn) requires two or more arguments.");if(commands="string"==typeof commands?commands.split(/\s+/):commands,!Array.isArray(commands)||commands.filter(c=>"string"!=typeof c).length>0)throw new Error("The first argument of useExcept must be a string or array of strings. Received "+typeof commands);const fns=Array.from(arguments).slice(1),all=new Set(this.commandlist.map(i=>i.toLowerCase()));commands.forEach(cmd=>{all.delete(cmd);for(const c of all)0===c.indexOf(cmd)&&all.delete(c)}),this.useWith(Array.from(all),...fns)}async exec(input,callback){Array.isArray(input)&&(input=input.map(i=>i.indexOf(" ")>=0&&!/^[\"\'].+ [\"\']$/.test(i)?`"${i}"`:i).join(" ")),_classPrivateFieldGet(this,_history).unshift({input:input,time:(new Date).toLocaleString()}),_classPrivateFieldGet(this,_history).length>_classPrivateFieldGet(this,_maxHistoryItems)&&_classPrivateFieldGet(this,_history).pop();let parsed=COMMAND_PATTERN.exec(input+" ");if(null===parsed)return-1!==input.indexOf("version")||-1!==input.indexOf("-v")?console.log(this.version):-1!==input.indexOf("help")?console.log(this.help):Command.stderr(this.help);parsed=parsed.filter(item=>void 0!==item);const cmd=parsed[1],args=parsed.length>2?parsed[2]:"",action=this.__commands.get(cmd);if(!action)return"version"===cmd.toLowerCase()?console.log(this.version):Command.stderr(this.help);const processor=this.__processors.get(action);if(!processor)return Command.stderr("Command not found.");const term=processor.getTerminalCommand(args);return await Command.reply(await term.command.run(term.arguments,callback))}getCommandMiddleware(cmd){const results=[];return cmd.split(/\s+/).forEach((c,i,a)=>{const r=_classPrivateFieldGet(this,_middlewareGroups).get(a.slice(0,i+1).join(" "));r&&results.push(r.flat(1/0))}),results.flat(1/0)}clearHistory(){_classPrivateFieldSet(this,_history,[])}clear(){_classPrivateFieldSet(this,_history,[]),console.clear()}}var _pattern=new WeakMap,_oid=new WeakMap,_aliases=new WeakMap,_fn=new WeakMap,_flagConfig=new WeakMap,_parent=new WeakMap,_shell=new WeakMap;class Command extends Base{constructor(cfg={}){if(cfg.hasOwnProperty("handler")&&("string"==typeof cfg.handler&&(cfg.handler=Function("return ("+cfg.handler.replace("function anonymous","function")+").call(this)").call(globalThis)),"function"!=typeof cfg.handler))throw new Error('Invalid command configuration. A "handler" function is required.');if(super(cfg),_pattern.set(this,{writable:!0,value:void 0}),_oid.set(this,{writable:!0,value:void 0}),_aliases.set(this,{writable:!0,value:new Set}),_fn.set(this,{writable:!0,value:void 0}),_flagConfig.set(this,{writable:!0,value:{}}),_parent.set(this,{writable:!0,value:null}),_shell.set(this,{writable:!0,value:null}),cfg.hasOwnProperty("use")&&Array.isArray(cfg.use)&&cfg.use.forEach(code=>this.initializeMiddleware(code)),cfg.hasOwnProperty("trailer")&&Array.isArray(cfg.trailer)&&cfg.trailer.forEach(code=>this.initializeTrailer(code)),this.initializeHelpAnnotations(cfg),_classPrivateFieldSet(this,_fn,cfg.handler),_classPrivateFieldSet(this,_oid,Symbol(cfg.name||cfg.usage||cfg.pattern||"command")),_classPrivateFieldSet(this,_pattern,cfg.pattern||/[\s\S]+/i),cfg.alias&&!cfg.aliases&&(cfg.aliases="string"==typeof cfg.alias?[cfg.alias]:Array.isArray(cfg.alias)?cfg.alias:Array.from(cfg.alias),delete cfg.alias),cfg.aliases){if(!Array.isArray(cfg.aliases))throw new Error("The alias property only accepts an array.");_classPrivateFieldSet(this,_aliases,new Set(cfg.aliases))}if(cfg.flags){if("object"!=typeof cfg.flags)throw new Error(`Invalid flag configuration (expected and object, received ${typeof cfg.flags}).`);for(const[key,value]of Object.entries(cfg.flags))if(value.hasOwnProperty("alias")){if(value.aliases=value.aliases||[],Array.isArray(value.alias)){if(value.aliases=Array.from(new Set(...value.aliases,...value.alias)),value.aliases.filter(a=>"string"!=typeof a)>0)throw new Error(`${key} flag aliases must be strings. Type failure on: ${value.aliases.filter(a=>"string"!=typeof a).join(", ")}.`)}else{if("string"!=typeof value.alias)throw new Error(`Aliases must be strings, not ${typeof value.alias} (${key} flag).`);value.aliases.push(value.alias)}delete value.alias}_classPrivateFieldSet(this,_flagConfig,cfg.flags)}Array.isArray(cfg.subcommands)&&this.add(...cfg.subcommands);const attributes=new Set(["commands","subcommands","plugins","defaultHandler","disableHelp","describeDefault","describeOptions","describeMultipleValues","describeRequired","flags","alias","aliases","description","help","usage","pattern","name","handler","middleware","use","arguments","commonflag","commonflags","trailer","url","support"]),unrecognized=Object.keys(cfg).filter(attribute=>!attributes.has(attribute));if(unrecognized.length>0)throw new Error("Unrecognized configuration attribute(s): "+unrecognized.join(", "));const ignoreFlags=commonFlags=>{if(commonFlags.ignore&&(Array.isArray(commonFlags.ignore)||"string"==typeof commonFlags.ignore)){const ignore=new Set(Array.isArray(commonFlags.ignore)?commonFlags.ignore:[commonFlags.ignore]),root=this.commandroot.replace(new RegExp(`^${this.shell.name}\\s+`,"i"),"");for(const cmd of ignore)if(root.startsWith(cmd)){commonFlags={};break}}return commonFlags};Object.defineProperties(this,{__commonFlags:{enumerable:!1,get(){let flags=ignoreFlags(this.__commonflags);null!==this.parent&&(flags=Object.assign(flags,this.parent.__commonFlags));const result=Object.assign({},null!==this.shell?ignoreFlags(this.shell.__commonflags):{},flags);return(Array.isArray(result.ignore)||"string"==typeof result.ignore)&&delete result.ignore,result}},__flagConfig:{enumerable:!1,get(){const flags=new Map(Object.entries(Object.assign(this.__commonFlags,_classPrivateFieldGet(this,_flagConfig)||{})));return flags.delete("help"),flags}},getTerminalCommand:{enumerable:!1,configurable:!1,writable:!1,value:input=>{const args=input.trim().split(/\t+|\s+/);let cmd=this;for(;args.length>0;){const arg=args[0],subcmd=cmd.getCommand(arg);if(!subcmd)break;cmd=subcmd,args.shift()}return{command:cmd,arguments:args.join(" ")}}}}),this.__commonflags=cfg.commonflags||{},this.__width=null===this.shell?80:this.shell.tableWidth||80,this.updateHelp()}get data(){const commands=super.data;let handler=(_classPrivateFieldGet(this,_fn)||this.defaultHandler).toString();METHOD_PATTERN.test(handler)&&(handler=handler.replace(METHOD_PATTERN.exec(handler)[1],"function "));const flags=Object.assign(this.__commonFlags,_classPrivateFieldGet(this,_flagConfig)||{});for(const[key,value]of Object.entries(flags))value.aliases=value.aliases||[],value.hasOwnProperty("alias")&&value.aliases.indexOf(value.alias)<0&&value.aliases.push(value.alias),delete value.alias;Object.keys(flags).forEach(name=>{flags[name]=Object.assign(this.getFlagConfiguration(name),flags[name])});const data={name:this.name,description:this.description,help:this.help,usage:this.usage,aliases:Array.from(_classPrivateFieldGet(this,_aliases)),flags:flags,handler:handler,commands:commands,disableHelp:!this.autohelp,use:this.middleware.data,trailer:this.trailers.data};for(const[key,value]of Object.entries(data.flags))delete value.alias;return data}set parent(cmd){if(!(cmd instanceof Command))throw new Error(`Cannot set parent of "${this.name}" command to anything other than another command. To make this command a direct descendent of the main shell, use the shell attribute instead.`);_classPrivateFieldSet(this,_parent,cmd)}get parent(){return _classPrivateFieldGet(this,_parent)}set shell(shell){if(!shell)throw new Error(`Cannot set shell of ${this.name} command to a non-Shell object.`);if(!(shell instanceof Shell))throw new Error(`Expected a Shell object, received a "${typeof shell}" object.`);_classPrivateFieldSet(this,_shell,shell),this.__width=null===this.shell?80:shell.tableWidth}get shell(){return _classPrivateFieldGet(this,_shell)?_classPrivateFieldGet(this,_shell):_classPrivateFieldGet(this,_parent)?_classPrivateFieldGet(this,_parent).shell:null}get plugins(){return Object.assign({},this.shell.plugins,this.parent?this.parent.plugins:{},super.plugins)}get commandroot(){return _classPrivateFieldGet(this,_parent)?`${_classPrivateFieldGet(this,_parent).commandroot} ${this.name}`.trim():_classPrivateFieldGet(this,_shell)?`${_classPrivateFieldGet(this,_shell).name} ${this.name}`.trim():this.name}set aliases(value){if(value){if("object"==typeof value)switch(value.constructor.name.toLowerCase()){case"map":value=Array.from(value.keys());break;case"set":value=Array.from(value);break;case"object":value=Object.keys(value).filter(item=>"string"==typeof item);break;case"array":break;case"string":value=value.split(/\s+/)[0];break;default:throw new Error("Invalid alias value. Use an array of strings.")}_classPrivateFieldSet(this,_aliases,Array.from(new Set(value)))}else _classPrivateFieldSet(this,_aliases,[])}get aliases(){return Array.from(_classPrivateFieldGet(this,_aliases))||[]}get OID(){return _classPrivateFieldGet(this,_oid)}addFlag(name,cfg){if("string"!=typeof name){if(!cfg.hasOwnProperty("name"))throw new Error("Invalid flag name (should be a string).");name=cfg.name}_classPrivateFieldGet(this,_flagConfig)[name]=cfg}removeFlag(name){delete _classPrivateFieldGet(this,_flagConfig)[name]}getFlagConfiguration(name){let flag=this.__flagConfig.get(name);if(!flag){for(const[f,cfg]of this.__flagConfig)if(cfg.aliases&&cfg.aliases.indexOf(name)>=0||cfg.alias&&cfg.alias===flag){flag=cfg;break}if(!flag)return null}return{description:flag.description,required:!!flag.hasOwnProperty("required")&&flag.required,aliases:flag.aliases||[flag.alias].filter(i=>null!==i),type:void 0===flag.type?"string":"string"==typeof flag.type?flag.type:flag.type.name.toLowerCase(),options:flag.hasOwnProperty("options")?flag.options:null,allowMultipleValues:!!flag.hasOwnProperty("allowMultipleValues")&&flag.allowMultipleValues}}supportsFlag(name){return _classPrivateFieldGet(this,_flagConfig).hasOwnProperty(name)}deepParse(input){const meta=this.parse(input);if(0===this.__commands.size)return meta;if(0===meta.input.trim().length)return meta;const args=meta.input.split(/\s+/),subcmd=this.__commands.get(args.shift());return subcmd?this.__processors.get(subcmd).deepParse(args.join(" ")):meta}parse(input){const data={command:this.name,input:input.trim()},flagConfig=Object.assign(this.__commonFlags,_classPrivateFieldGet(this,_flagConfig)||{});flagConfig.hasOwnProperty("help")||(flagConfig.help={description:`Display ${this.name} help.`,default:!1,type:"boolean"});const flags=Array.from(FLAG_PATTERN[Symbol.matchAll](input),x=>x[0]),parser=new Parser(flags,flagConfig),pdata=parser.data,recognized={};if(parser.recognizedFlags.forEach(flag=>{recognized[flag]=pdata[flag]}),parser.unrecognizedFlags.forEach(arg=>delete recognized[arg]),data.flags={recognized:recognized,unrecognized:parser.unrecognizedFlags},data.valid=parser.valid,data.violations=parser.violations,data.parsed={},Object.keys(pdata.flagSource).length>0)for(const[key,src]of Object.entries(pdata.flagSource))data.parsed[src.name]=src.inputName;data.help={requested:recognized.help},recognized.help&&(data.help.message=this.help);const args=Array.from(this.arguments);return Object.defineProperties(data,{flag:{enumerable:!0,configurable:!1,writable:!1,value:name=>{try{return"number"==typeof name?Array.from(parser.unrecognizedFlags)[name]:data.flags.recognized.hasOwnProperty(pdata.flagSource[name].name)?data.flags.recognized[pdata.flagSource[name].name]:pdata.flagSource[name].value}catch(e){return this.arguments.has(name)?Array.from(parser.unrecognizedFlags)[args.indexOf(name)]:void 0}}},command:{enumerable:!0,get:()=>this},shell:{enumerable:!0,get:()=>this.shell},data:{enumerable:!0,get(){const uf=parser.unrecognizedFlags,result=Object.assign({},recognized);return delete result.help,args.forEach((name,i)=>{const value=uf[i];let normalizedValue=Object.keys(pdata).filter(key=>key.toLowerCase()===value);normalizedValue=normalizedValue.length>0?normalizedValue.pop():value,void 0!==normalizedValue&&(normalizedValue=normalizedValue.trim(),STRIP_QUOTE_PATTERN.test(normalizedValue)&&(normalizedValue=normalizedValue.substring(1,normalizedValue.length-1))),result.hasOwnProperty(name)?(result[name]=Array.isArray(result[name])?result[name]:[result[name]],result[name].push(normalizedValue)):result[name]=normalizedValue}),uf.length>args.length&&uf.slice(args.length).forEach((flag,i)=>{let name="unknown"+(i+1);for(;result.hasOwnProperty(name);){const number=name.substring(7);name="unknown"+(parseInt(number)+1)}result[name]=flag}),result}}}),Object.defineProperty(data.help,"default",{enumerable:!0,get:()=>this.help}),data}async run(input,callback){const fn=(_classPrivateFieldGet(this,_fn)||this.defaultHandler).bind(this),data="string"==typeof input?this.parse(input):input;if(arguments[0]=this.deepParse(input),arguments[0].plugins=this.plugins,null!==this.shell){const parentMiddleware=this.shell.getCommandMiddleware(this.commandroot.replace(new RegExp("^"+this.shell.name,"i"),"").trim());parentMiddleware.length>0&&this.middleware.use(...parentMiddleware)}const trailers=this.trailers;return arguments[0].help&&arguments[0].help.requested?(console.log(this.help),void(trailers.size>0&&trailers.run(arguments[0]))):this.middleware.size>0?(this.middleware.run(arguments[0],async meta=>await Command.reply(fn(meta,callback))),void(trailers.size>0&&trailers.run(arguments[0]))):(data.plugins=this.plugins,Command.reply(fn(data,callback)),void(trailers.size>0&&trailers.run(arguments[0])))}static stderr(err){return Error,new Promise((resolve,reject)=>reject(err)).catch(console.error)}static reply(callback){return new Promise((resolve,reject)=>{try{"function"==typeof callback&&callback(),resolve()}catch(e){reject(e)}})}}const all={Shell:Shell,Command:Command,Formatter:Formatter,Table:Table,Middleware:Middleware};export default all;export{Command,Formatter,Middleware,Shell};
+//# sourceMappingURL=../shell-debug/index.js.map
diff --git a/dist/shell/package.json b/dist/shell/package.json
new file mode 100644
index 0000000..ec4d962
--- /dev/null
+++ b/dist/shell/package.json
@@ -0,0 +1,84 @@
+{
+ "name": "@author.io/shell",
+ "version": "1.8.18",
+ "description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
+ "main": "./src/index.js",
+ "module": "./index.js",
+ "exports": {
+ "import": "./index.js",
+ "default": "./index.js"
+ },
+ "browser": "./index.js",
+ "keywords": [
+ "cli",
+ "args",
+ "arg",
+ "shell"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/author/shell"
+ },
+ "dev": {
+ "ignorecircular": [
+ "src/command.js",
+ "src/shell.js"
+ ],
+ "replace": {
+ "<#REPLACE_VERSION#>": "package.version"
+ },
+ "volume": [
+ "./node_modules/@author.io/arg:/node_modules/@author.io/arg",
+ "./node_modules/@author.io/table:/node_modules/@author.io/table"
+ ],
+ "alias": {
+ "@author.io/shell": "/app/.dist/@author.io/shell/index.js",
+ "@author.io/arg": "/node_modules/@author.io/arg/index.js",
+ "@author.io/table": "/node_modules/@author.io/table/index.js"
+ },
+ "ci": {
+ "verbose": true,
+ "peer": true,
+ "embed": [
+ "@author.io/arg",
+ "@author.io/table"
+ ]
+ }
+ },
+ "author": {
+ "name": "Corey Butler",
+ "url": "http://coreybutler.com"
+ },
+ "license": "MIT",
+ "type": "module",
+ "files": [
+ "*.js"
+ ],
+ "engines": {
+ "node": ">=13.5.0"
+ },
+ "standard": {
+ "parser": "babel-eslint",
+ "ignore": [
+ "_*",
+ "_**/*",
+ ".**/*",
+ "node_modules",
+ "karma.conf.js",
+ "karma.conf.cjs",
+ "build.js"
+ ],
+ "globals": [
+ "window",
+ "global",
+ "globalThis"
+ ]
+ },
+ "devDependencies": {
+ "@author.io/arg": "^1.3.23",
+ "@author.io/dev": "^1.1.5",
+ "@author.io/table": "^1.0.3",
+ "@author.io/shell-debug": "1.8.18"
+ },
+ "dependencies": {}
+}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 528fac1..4176ef3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,15 +1,15 @@
{
"name": "@author.io/shell",
- "version": "1.8.13",
+ "version": "1.8.18",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@author.io/shell",
- "version": "1.8.13",
+ "version": "1.8.18",
"license": "MIT",
"devDependencies": {
- "@author.io/arg": "^1.3.19",
+ "@author.io/arg": "^1.3.23",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
},
@@ -18,9 +18,9 @@
}
},
"node_modules/@author.io/arg": {
- "version": "1.3.19",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.19.tgz",
- "integrity": "sha512-3EyWe8ZXMwD18GdBkFZYJugY4v+iS9m0TbjzGH2p1yi9XKrlnPlOkyU11I6wlcd/CQGeL4nu8n1QAHrUSsxmuw==",
+ "version": "1.3.23",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.23.tgz",
+ "integrity": "sha512-J3Ia2+HHf4rNpgz0YK6UzRqVZHZt0JXRocMCfh7tPOTK8WPbu0aLXwGHLLH4L6ySFs09V+/Zbke3rLQDzYltDw==",
"dev": true,
"engines": {
"node": ">=12.0.0"
@@ -277,9 +277,9 @@
},
"dependencies": {
"@author.io/arg": {
- "version": "1.3.19",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.19.tgz",
- "integrity": "sha512-3EyWe8ZXMwD18GdBkFZYJugY4v+iS9m0TbjzGH2p1yi9XKrlnPlOkyU11I6wlcd/CQGeL4nu8n1QAHrUSsxmuw==",
+ "version": "1.3.23",
+ "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.23.tgz",
+ "integrity": "sha512-J3Ia2+HHf4rNpgz0YK6UzRqVZHZt0JXRocMCfh7tPOTK8WPbu0aLXwGHLLH4L6ySFs09V+/Zbke3rLQDzYltDw==",
"dev": true
},
"@author.io/dev": {
diff --git a/package.json b/package.json
index d631aa3..281da23 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.17",
+ "version": "1.8.18",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "./src/index.js",
"module": "./index.js",
@@ -28,7 +28,8 @@
"report:size": "dev report size ./.dist/**/*.js ./.dist/**/*.js.map",
"report:compat": "dev report compatibility ./src/**/*.js",
"report:preview": "npm pack --dry-run && echo \"==============================\" && echo \"This report shows what will be published to the module registry. Pay attention to the tarball contents and assure no sensitive files will be published.\"",
- "ci": "dev test --verbose --mode ci --peer -rt node tests/*.js && dev test --mode ci -rt deno tests/*.js && dev test --mode ci -rt browser tests/*.js"
+ "ci": "dev test --verbose --mode ci --peer -rt node tests/*.js && dev test --mode ci -rt deno tests/*.js && dev test --mode ci -rt browser tests/*.js",
+ "x": "dev build --verbose --mode ci --peer"
},
"keywords": [
"cli",
@@ -53,7 +54,7 @@
"./node_modules/@author.io/table:/node_modules/@author.io/table"
],
"alias": {
- "@author.io/shell": "/app/.dist/@author.io/shell/index.js",
+ "@author.io/shell": "/app/.dist/shell/index.js",
"@author.io/arg": "/node_modules/@author.io/arg/index.js",
"@author.io/table": "/node_modules/@author.io/table/index.js"
},
@@ -96,8 +97,8 @@
]
},
"devDependencies": {
- "@author.io/arg": "^1.3.21",
+ "@author.io/arg": "^1.3.23",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
}
-}
\ No newline at end of file
+}
diff --git a/src/command.js b/src/command.js
index e4c711e..38f61b4 100644
--- a/src/command.js
+++ b/src/command.js
@@ -569,11 +569,13 @@ export default class Command extends Base {
// Command.reply(fn(arguments[0], callback))
data.plugins = this.plugins
- Command.reply(fn(data, callback))
+ const result = await Command.reply(fn(data, callback))
if (trailers.size > 0) {
trailers.run(arguments[0])
}
+
+ return result
}
static stderr (err) {
@@ -585,13 +587,15 @@ export default class Command extends Base {
}
static reply (callback) {
- return new Promise((resolve, reject) => {
+ return new Promise(async (resolve, reject) => { // eslint-disable-line no-async-promise-executor
try {
if (typeof callback === 'function') {
- callback()
+ resolve(callback())
+ } else if (callback instanceof Promise) {
+ callback.then(resolve).catch(reject)
+ } else {
+ resolve(...arguments)
}
-
- resolve()
} catch (e) {
reject(e)
}
diff --git a/src/shell.js b/src/shell.js
index c5bad75..5f5de96 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -168,7 +168,7 @@ export default class Shell extends Base {
// method, often forgetting to join the values into a string.
if (Array.isArray(input)) {
input = input.map(i => {
- if (i.indexOf(' ') >= 0 && !/^[\"\'].+ [\"\']$/.test(i)) {
+ if (i.indexOf(' ') >= 0 && !/^[\"\'].+ [\"\']$/.test(i)) { // eslint-disable-line no-useless-escape
return `"${i}"`
} else {
return i
@@ -217,6 +217,11 @@ export default class Shell extends Base {
}
const term = processor.getTerminalCommand(args)
+
+ if (typeof callback === 'function') {
+ return callback(await Command.reply(await term.command.run(term.arguments, callback))) // eslint-disable-line standard/no-callback-literal
+ }
+
return await Command.reply(await term.command.run(term.arguments, callback))
}
diff --git a/tests/100-regression.js b/tests/100-regression.js
index 762f27c..f3d916f 100644
--- a/tests/100-regression.js
+++ b/tests/100-regression.js
@@ -119,3 +119,39 @@ test('Accept arrays with values containing spaces', t => {
const argv = ["run", "-c", "a connection", "--save"]
sh.exec(argv).catch(t.fail)
})
+
+test('Exec method should return promise value', async t => {
+ const sh = new Shell({
+ name: 'test',
+ commands: [{
+ name: 'run',
+ async handler(meta) {
+ return meta.input
+ }
+ }]
+ })
+
+ const argv = ['run', 'example']
+ const result = await sh.exec(argv).catch(t.fail)
+
+ t.expect(result, 'example', 'returns command promise results')
+ t.end()
+})
+
+test('Exec method should return callback value', async t => {
+ const sh = new Shell({
+ name: 'test',
+ commands: [{
+ name: 'run',
+ async handler(meta) {
+ return meta.input
+ }
+ }]
+ })
+
+ const argv = ['run', 'other']
+ sh.exec(argv, data => {
+ t.expect(data, 'other', 'returns command callback results')
+ t.end()
+ })
+})
From 96e3811c75265b979170aac7f8b331838dd8f5d6 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Thu, 10 Feb 2022 19:43:52 -0600
Subject: [PATCH 145/152] Added data references.
---
README.md | 34 ++++++++++++++++++++++++++++++++++
package.json | 3 ++-
src/command.js | 10 +++++-----
src/shell.js | 15 +++++++++++++--
tests/04-metadata.js | 27 +++++++++++++++++++++++++++
5 files changed, 81 insertions(+), 8 deletions(-)
diff --git a/README.md b/README.md
index e9e8d43..2f7208b 100644
--- a/README.md
+++ b/README.md
@@ -331,6 +331,40 @@ _Output:_
> Notice the values from the known flags are _first_.
+### Custom Handler Data References
+
+When building JavaScript applications, it may be desirable to pass data references to the `exec` method, making them available to handlers. For example:
+
+```javascript
+const sh = new Shell({
+ name: 'test',
+ commands: [{
+ name: 'run',
+ async handler (meta) {
+ return meta.reference.test // reference data
+ }
+ }]
+})
+
+const ref = { test: true }
+const result = await sh.exec('run', ref)
+```
+
+In the command above, the data object (line 1) is passed to the `exec()` method using a special object as the second argument. This object is made available in the handler using the `meta.reference` attribute.
+
+If a callback needs to be defined, the second argument of the `exec` method must have an attribute called `callback`, i.e.:
+
+```javascript
+const ref = {
+ test: true,
+ callback: function() {...}
+}
+
+const result = await sh.exec('run', ref)
+```
+
+The callback method is _not_ available in the `meta.reference`, but the callback will be executed when `exec()` is executed.
+
## Plugins
Plugins expose functions, objects, and primitives to shell handlers.
diff --git a/package.json b/package.json
index 281da23..ddd00c3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.18",
+ "version": "1.9.0",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "./src/index.js",
"module": "./index.js",
@@ -16,6 +16,7 @@
"test:node:sanity": "dev test -rt node tests/01-sanity.js",
"test:node:base": "dev test -rt node tests/02-base.js",
"test:node:relationships": "dev test -rt node tests/06-relationships.js",
+ "test:node:metadata": "dev test -rt node tests/04-metadata.js",
"test:node:regression": "dev test -rt node tests/100-regression.js",
"test:browser": "dev test -rt browser tests/*.js",
"test:browser:sanity": "dev test -rt browser tests/01-sanity.js",
diff --git a/src/command.js b/src/command.js
index 38f61b4..78872b3 100644
--- a/src/command.js
+++ b/src/command.js
@@ -529,9 +529,9 @@ export default class Command extends Base {
return data
}
- async run (input, callback) {
+ async run (input, callback, reference = undefined) {
const fn = (this.#fn || this.defaultHandler).bind(this)
- const data = typeof input === 'string' ? this.parse(input) : input
+ const metadata = typeof input === 'string' ? this.parse(input) : input
arguments[0] = this.deepParse(input)
arguments[0].plugins = this.plugins
@@ -558,7 +558,7 @@ export default class Command extends Base {
// No subcommand was recognized
if (this.middleware.size > 0) {
- this.middleware.run(arguments[0], async meta => await Command.reply(fn(meta, callback)))
+ this.middleware.run(arguments[0], async meta => await Command.reply(fn(Object.assign(meta, { reference }), callback)))
if (trailers.size > 0) {
trailers.run(arguments[0])
@@ -568,8 +568,8 @@ export default class Command extends Base {
}
// Command.reply(fn(arguments[0], callback))
- data.plugins = this.plugins
- const result = await Command.reply(fn(data, callback))
+ metadata.plugins = this.plugins
+ const result = await Command.reply(fn(Object.assign(metadata, { reference }), callback))
if (trailers.size > 0) {
trailers.run(arguments[0])
diff --git a/src/shell.js b/src/shell.js
index 5f5de96..d127e16 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -164,6 +164,17 @@ export default class Shell extends Base {
}
async exec (input, callback) {
+ // Optionally apply reference data. Only for advanced use
+ // in applications (not strict CLIs).
+ let reference
+ if (typeof callback === 'object') {
+ if (!callback.hasOwnProperty('reference') && !callback.hasOwnProperty('callback')) { // eslint-disable-line no-prototype-builtins
+ throw new Error('exec method data references require a reference and/or callback attribute - recognized: ' + Object.keys(callback).join(', '))
+ }
+ reference = callback.reference
+ callback = callback.callback
+ }
+
// The array check exists because people are passing process.argv.slice(2) into this
// method, often forgetting to join the values into a string.
if (Array.isArray(input)) {
@@ -219,10 +230,10 @@ export default class Shell extends Base {
const term = processor.getTerminalCommand(args)
if (typeof callback === 'function') {
- return callback(await Command.reply(await term.command.run(term.arguments, callback))) // eslint-disable-line standard/no-callback-literal
+ return callback(await Command.reply(await term.command.run(term.arguments, callback, reference))) // eslint-disable-line standard/no-callback-literal
}
- return await Command.reply(await term.command.run(term.arguments, callback))
+ return await Command.reply(await term.command.run(term.arguments, callback, reference))
}
getCommandMiddleware (cmd) {
diff --git a/tests/04-metadata.js b/tests/04-metadata.js
index 925ec13..c44d624 100644
--- a/tests/04-metadata.js
+++ b/tests/04-metadata.js
@@ -159,3 +159,30 @@ test('Ordered Named Arguments', t => {
shell.exec('account create test@domain.com pwd')
})
+
+
+test('Application reference data', async t => {
+ const data = { test: true }
+ const sh = new Shell({
+ name: 'test',
+ commands: [{
+ name: 'run',
+ async handler (meta) {
+ return meta.reference.test
+ }
+ }]
+ })
+
+ const result = await sh.exec('run', { reference: data })
+
+ t.expect(result, true, 'reference data detected in handler')
+
+ try {
+ await sh.exec('run', { demo: data })
+ t.fail('failure to provide reference and callback throws error')
+ } catch (e) {
+ t.pass('failure to provide reference and callback throws error')
+ }
+
+ t.end()
+})
From 6b04c0a4726b1525b8effd43345852a49dbd29cd Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Thu, 10 Feb 2022 19:52:48 -0600
Subject: [PATCH 146/152] Removed unnecessary dist directory
---
dist/shell-debug/LICENSE | 21 -
dist/shell-debug/README.md | 5 -
dist/shell-debug/index.js.map | 1 -
dist/shell-debug/package.json | 52 --
dist/shell/LICENSE | 21 -
dist/shell/README.md | 972 ----------------------------------
dist/shell/index.js | 5 -
dist/shell/package.json | 84 ---
8 files changed, 1161 deletions(-)
delete mode 100644 dist/shell-debug/LICENSE
delete mode 100644 dist/shell-debug/README.md
delete mode 100644 dist/shell-debug/index.js.map
delete mode 100644 dist/shell-debug/package.json
delete mode 100644 dist/shell/LICENSE
delete mode 100644 dist/shell/README.md
delete mode 100644 dist/shell/index.js
delete mode 100644 dist/shell/package.json
diff --git a/dist/shell-debug/LICENSE b/dist/shell-debug/LICENSE
deleted file mode 100644
index 166549b..0000000
--- a/dist/shell-debug/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2020 Author.io
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/dist/shell-debug/README.md b/dist/shell-debug/README.md
deleted file mode 100644
index c26e24d..0000000
--- a/dist/shell-debug/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# shell 1.8.18
-
-Please see [https://github.com/author/shell](https://github.com/author/shell).
-
-Generated on Tue Jan 04 2022 23:59:11 GMT+0000 (Coordinated Universal Time).
\ No newline at end of file
diff --git a/dist/shell-debug/index.js.map b/dist/shell-debug/index.js.map
deleted file mode 100644
index 828db20..0000000
--- a/dist/shell-debug/index.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"file":"index.js","sources":["../../src/middleware.js","../../src/format.js","../../src/base.js","../../src/utility.js","../../src/shell.js","../../src/command.js","../../src/index.js"],"sourcesContent":["export default class Middleware {\n constructor () {\n Object.defineProperties(this, {\n _data: { enumerable: false, configurable: false, value: [] },\n go: { enumerable: false, configurable: false, writable: true, value: (...args) => { args.pop().apply(this, args) } }\n })\n }\n\n get size () { return this._data.length }\n\n get data () { return this._data }\n\n use (method) {\n const methodBody = method.toString()\n if (methodBody.indexOf('[native code]') < 0) {\n this._data.push(methodBody)\n }\n\n this.go = (stack => (...args) => {\n const next = args.pop()\n stack(...args, () => {\n method.apply(this, [...args, next.bind(null, ...args)])\n })\n })(this.go)\n }\n\n run () {\n const args = Array.from(arguments)\n if (args.length === 0 || typeof args[args.length - 1] !== 'function') {\n args.push(() => {})\n }\n\n this.go(...args)\n }\n}\n","import Table from '@author.io/table'\nimport Command from './command.js'\nimport Shell from './shell.js'\n\nclass Formatter {\n #data = null\n #tableWidth = 80\n #colAlign = [] // Defaults to ['l', 'l', 'l']\n #colWidth = ['20%', '15%', '65%']\n\n constructor (data) {\n this.#data = data\n }\n\n set width (value) {\n this.#tableWidth = value < 20 ? 20 : value\n }\n\n set columnWidths (value) {\n this.#colWidth = value\n }\n\n set columnAlignment (value) {\n this.#colAlign = value\n }\n\n get usage () {\n const desc = this.#data.description.trim()\n\n if (this.#data instanceof Command) {\n const aliases = this.#data.aliases\n const out = [`${this.#data.commandroot}${aliases.length > 0 ? '|' + aliases.join('|') : ''}${this.#data.__flagConfig.size > 0 ? ' [FLAGS]' : ''}${this.#data.arguments.size > 0 ? ' ' + Array.from(this.#data.arguments).map(i => '<' + i + '>').join(' ') : ''}`]\n\n if (this.#data.__processors.size > 0) {\n out[out.length - 1] += (this.#data.arguments.size > 0 || this.#data.__flagConfig.size > 0 ? ' |' : '') + ' [COMMAND]'\n }\n\n if (desc.trim().length > 0 && out !== desc) {\n out.push(new Table([[desc.trim().replace(/\\n/gi, '\\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output)\n }\n\n return out.join('\\n')\n } else if (this.#data instanceof Shell) {\n return `${this.#data.name}${this.#data.__processors.size > 0 ? ' [COMMAND]' : ''}\\n${desc.trim().length > 0 ? new Table([[desc.trim().replace(/\\n/gi, '\\n ')]], null, null, this.#tableWidth, [2, 0, 1, 1]).output : ''}${this.#data.arguments.size > 0 ? ' ' + Array.from(this.#data.arguments).map(i => '[' + i + ']').join(' ') : ''}\\n`.trim()\n }\n\n return ''\n }\n\n get subcommands () {\n const rows = Array.from(this.#data.__processors.values()).map(cmd => {\n const nm = [cmd.name].concat(cmd.aliases)\n return [nm.join('|'), cmd.description]\n })\n\n const result = []\n\n if (rows.length > 0) {\n const table = new Table(rows, this.#colAlign, ['25%', '75%'], this.#tableWidth, [2])\n result.push('\\nCommands:\\n')\n result.push(table.output)\n }\n\n return result.join('\\n')\n }\n\n get help () {\n const usage = this.usage.trim()\n\n if (this.#data instanceof Command) {\n const flags = this.#data.__flagConfig\n const rows = []\n\n if (flags.size > 0) {\n flags.forEach((cfg, flag) => {\n let aliases = Array.from(cfg.aliases || cfg.alias || [])\n aliases = aliases.length === 0 ? '' : '[' + aliases.map(a => `-${a}`).join(', ') + ']'\n\n let dsc = [cfg.description || '']\n\n if (cfg.hasOwnProperty('options') && this.#data.describeOptions) { // eslint-disable-line no-prototype-builtins\n dsc.push(`Options: ${cfg.options.join(', ')}.`)\n }\n\n if (cfg.hasOwnProperty('allowMultipleValues') && cfg.allowMultipleValues === true && this.#data.describeMultipleValues) { // eslint-disable-line no-prototype-builtins\n dsc.push('Can be used multiple times.')\n }\n\n if (cfg.hasOwnProperty('default') && this.#data.describeDefault) { // eslint-disable-line no-prototype-builtins\n dsc.push(`(Default: ${cfg.default.toString()})`)\n }\n\n if (cfg.hasOwnProperty('required') && cfg.required === true && this.#data.describeRequired) { // eslint-disable-line no-prototype-builtins\n dsc.unshift('Required.')\n }\n\n dsc = dsc.join(' ').trim()\n\n rows.push(['--' + flag, aliases || '', dsc || ''])\n })\n }\n\n const table = new Table(rows, this.#colAlign, this.#colWidth, this.#tableWidth, [2, 0, usage.length > 0 ? 1 : 0, 0])\n\n let subcommands = '\\n' + this.subcommands\n if (subcommands.trim().length === 0) {\n subcommands = ''\n }\n return usage + (flags.size > 0 ? '\\n\\nFlags:\\n' + table.output : '') + subcommands\n } else if (this.#data instanceof Shell) {\n return [usage, this.subcommands].join('\\n')\n }\n\n return ''\n }\n}\n\nexport { Formatter as default, Formatter, Table }\n","import Middleware from './middleware.js'\nimport Formatter from './format.js'\nimport Shell from './shell.js'\nimport Command from './command.js'\n\nexport default class Base {\n #plugins = {}\n #url = null\n #support = null\n #formattedDefaultHelp\n #description\n #customUsage\n #customHelp\n #arguments = new Set()\n #autohelp = true\n #processors = new Map()\n #commands = new Map()\n #width = 80\n #name = 'Unknown'\n #middleware = new Middleware()\n #trailer = new Middleware()\n #commonflags = {}\n #display = {\n // These are all null, representing they're NOT configured.\n Default: null,\n Options: null,\n MultipleValues: null,\n Required: null\n }\n\n #hasCustomDefaultHandler = false\n\n #defaultHandler = function (meta) {\n if (this.parent !== null && this.parent.hasCustomDefaultHandler) {\n return this.parent.defaultHandler(...arguments)\n } else if (this.shell && this.shell !== null && this.shell.hasCustomDefaultHandler) {\n return this.shell.defaultHandler(...arguments)\n }\n\n if (this.#autohelp) {\n console.log(this.help)\n }\n }\n\n constructor (cfg = {}) {\n if (typeof cfg !== 'object') {\n throw new Error('Invalid command configuration. Expected an object.')\n }\n\n if (!cfg.hasOwnProperty('name')) { // eslint-disable-line no-prototype-builtins\n throw new Error('Invalid command configuration. A \"name\" attribute is required.')\n }\n\n if (cfg.hasOwnProperty('help')) { // eslint-disable-line no-prototype-builtins\n this.#customHelp = cfg.help\n }\n\n if (cfg.hasOwnProperty('usage')) { // eslint-disable-line no-prototype-builtins\n this.#customUsage = cfg.usage\n }\n\n if (cfg.hasOwnProperty('disablehelp') && !cfg.hasOwnProperty('disableHelp')) { // eslint-disable-line no-prototype-builtins\n cfg.disableHelp = cfg.disablehelp\n }\n\n if (cfg.hasOwnProperty('disableHelp') && cfg.disableHelp === true) { // eslint-disable-line no-prototype-builtins\n this.#autohelp = false\n }\n\n if (typeof cfg.help === 'function' || typeof cfg.help === 'string') {\n this.help = cfg.help\n }\n\n if (typeof cfg.usage === 'function' || typeof cfg.usage === 'string') {\n this.usage = cfg.usage\n }\n\n if (cfg.hasOwnProperty('defaultHandler') && cfg.defaultHandler.toString() !== this.#defaultHandler.toString()) { // eslint-disable-line no-prototype-builtins\n this.defaultHandler = cfg.defaultHandler\n }\n\n if (typeof cfg.arguments === 'string') {\n cfg.arguments = cfg.arguments.split(/\\s+|\\t+|\\,+|\\;+/).map(arg => arg.trim()) // eslint-disable-line no-useless-escape\n }\n\n if (Array.isArray(cfg.arguments)) {\n this.#arguments = new Set(cfg.arguments)\n }\n\n if (typeof cfg.url === 'string') {\n this.#url = cfg.url\n }\n\n if (typeof cfg.support === 'string') {\n this.#support = cfg.support\n }\n\n this.#name = (cfg.name || 'unknown').trim().split(/\\s+/)[0]\n this.#description = cfg.description || null\n\n if (Array.isArray(cfg.commands)) {\n cfg.commands.forEach(cmd => this.add(cmd))\n } else if (typeof cfg.commands === 'object') {\n for (const key in cfg.commands) {\n const data = cfg.commands[key]\n data.name = key\n this.add(data)\n }\n }\n\n if (cfg.hasOwnProperty('middleware')) { // eslint-disable-line no-prototype-builtins\n console.warn('The \"middleware\" attribute has been replaced with the \"use\" attribute.')\n cfg.use = cfg.middleware\n delete cfg.middleware\n }\n\n if (!cfg.hasOwnProperty('commonflag')) { // eslint-disable-line no-prototype-builtins\n if (cfg.hasOwnProperty('commonFlag')) { // eslint-disable-line no-prototype-builtins\n cfg.commonflag = cfg.commonFlag\n } else if (cfg.hasOwnProperty('commonflags')) { // eslint-disable-line no-prototype-builtins\n cfg.commonflag = cfg.commonflags\n } else if (cfg.hasOwnProperty('commonFlag')) { // eslint-disable-line no-prototype-builtins\n cfg.commonflag = cfg.commonFlag\n } else if (cfg.hasOwnProperty('commonFlags')) { // eslint-disable-line no-prototype-builtins\n cfg.commonflag = cfg.commonFlags\n }\n }\n\n if (cfg.hasOwnProperty('commonflag')) { // eslint-disable-line no-prototype-builtins\n if (typeof cfg.commonflag !== 'object') {\n throw new Error('The \"commonflag\" configuration attribute must be an object.')\n }\n }\n\n if (typeof cfg.plugins === 'object') {\n this.#plugins = cfg.plugins\n }\n\n Object.defineProperties(this, {\n __processors: {\n enumerable: false,\n get () {\n return this.#processors\n }\n },\n __commands: {\n enumerable: false,\n get () {\n return this.#commands\n }\n },\n __width: {\n enumerable: false,\n get () {\n return this.#width\n },\n set (v) {\n this.#width = v || 80\n }\n },\n __commonflags: {\n enumerable: false,\n get () {\n return this.#commonflags\n },\n set (value) {\n this.#commonflags = value\n }\n },\n arguments: {\n enumerable: false,\n get () {\n return this.#arguments\n }\n },\n initializeMiddleware: {\n enumerable: false,\n configurable: false,\n writable: false,\n value: code => {\n if (typeof code === 'string') {\n this.use(Function('return ' + code)()) // eslint-disable-line no-new-func\n } else if (typeof code === 'function') {\n this.use(code)\n } else {\n throw new Error('Invalid middleware: ' + code.toString())\n }\n }\n },\n initializeTrailer: {\n enumerable: false,\n configurable: false,\n writable: false,\n value: code => {\n if (typeof code === 'string') {\n this.trailer(Function('return ' + code)()) // eslint-disable-line no-new-func\n } else if (typeof code === 'function') {\n this.trailer(code)\n } else {\n throw new Error('Invalid trailer: ' + code.toString())\n }\n }\n },\n initializeHelpAnnotations: {\n enumerable: false,\n configurable: false,\n writable: false,\n value: cfg => {\n if (cfg.hasOwnProperty('describeDefault') && typeof cfg.describeDefault === 'boolean') { // eslint-disable-line no-prototype-builtins\n this.#display.Default = cfg.describeDefault\n }\n if (cfg.hasOwnProperty('describeOptions') && typeof cfg.describeOptions === 'boolean') { // eslint-disable-line no-prototype-builtins\n this.#display.Options = cfg.describeOptions\n }\n if (cfg.hasOwnProperty('describeMultipleValues') && typeof cfg.describeMultipleValues === 'boolean') { // eslint-disable-line no-prototype-builtins\n this.#display.MultipleValues = cfg.describeMultipleValues\n }\n if (cfg.hasOwnProperty('describeRequired') && typeof cfg.describeRequired === 'boolean') { // eslint-disable-line no-prototype-builtins\n this.#display.Required = cfg.describeRequired\n }\n }\n }\n })\n\n this.updateHelp()\n }\n\n get plugins () {\n return this.#plugins\n }\n\n // @readonly\n get name () {\n return this.#name || 'Unknown'\n }\n\n // @readonly\n get description () {\n return this.#description || this.usage || ''\n }\n\n // @readonly\n get url () {\n return this.URL\n }\n\n // @readonly\n get URL () {\n const uri = (this.#url || '').trim()\n\n if (uri.length === 0) {\n if (this.hasOwnProperty('parent')) { // eslint-disable-line no-prototype-builtins\n return this.parent.URL\n } else if (this instanceof Command) {\n return this.shell.URL\n }\n }\n\n return uri\n }\n\n // @readonly\n get support () {\n const support = (this.#support || '').trim()\n\n if (support.length === 0) {\n if (this.hasOwnProperty('parent')) { // eslint-disable-line no-prototype-builtins\n return this.parent.support\n } else if (this instanceof Command) {\n return this.shell.support\n }\n }\n\n return support\n }\n\n get autohelp () {\n return this.#autohelp\n }\n\n set autohelp (value) {\n if (typeof value !== 'boolean') {\n return\n }\n this.#autohelp = value\n this.#processors.forEach(cmd => { cmd.autohelp = value })\n }\n\n updateHelp () {\n this.#formattedDefaultHelp = new Formatter(this)\n this.#formattedDefaultHelp.width = this.#width\n }\n\n describeHelp (attr, prop) {\n if (this.#display[prop] !== null) {\n return this.#display[prop]\n }\n\n if (this instanceof Command) {\n if (this.shell && this.shell !== null && this.shell[attr] !== null) {\n return this.shell[attr]\n }\n\n if (this.parent !== null) {\n return this.parent[attr]\n }\n }\n\n return true\n }\n\n get describeDefault () {\n return this.describeHelp('describeDefault', 'Default')\n }\n\n get describeOptions () {\n return this.describeHelp('describeOptions', 'Options')\n }\n\n get describeMultipleValues () {\n return this.describeHelp('describeMultipleValues', 'MultipleValues')\n }\n\n get describeRequired () {\n return this.describeHelp('describeRequired', 'Required')\n }\n\n get usage () {\n if (this.#customUsage !== null) {\n return typeof this.#customUsage === 'function' ? this.#customUsage() : this.#customUsage\n }\n\n return this.#formattedDefaultHelp.usage\n }\n\n set usage (value) {\n if (typeof value === 'string' && value.trim().length === 0) {\n value = null\n }\n\n this.#customUsage = value\n\n this.updateHelp()\n }\n\n get help () {\n if (this.#customHelp) {\n return typeof this.#customHelp === 'function' ? this.#customHelp(this) : this.#customHelp\n }\n\n if (!this.autohelp) {\n return ''\n }\n\n return this.#formattedDefaultHelp.help\n }\n\n set help (value) {\n if (typeof value === 'string' && value.trim().length === 0) {\n value = null\n }\n\n this.#customHelp = value\n\n this.updateHelp()\n }\n\n // @private\n set defaultHandler (value) {\n if (typeof value === 'function') {\n this.#defaultHandler = value\n this.#hasCustomDefaultHandler = true\n this.#processors.forEach(cmd => { cmd.defaultProcessor = value })\n } else {\n throw new Error(`Invalid default method (must be a function, not \"${typeof value}\").`)\n }\n }\n\n get defaultHandler () {\n return this.#defaultHandler\n }\n\n // @private\n get hasCustomDefaultHandler () {\n return this.#hasCustomDefaultHandler\n }\n\n get data () {\n const commands = {}\n\n Array.from(this.#processors.values()).forEach(cmd => {\n const data = cmd.data\n const name = data.name\n delete data.name\n commands[name] = data\n })\n\n return commands\n }\n\n get middleware () {\n return this.#middleware\n }\n\n get trailers () {\n return this.#trailer\n }\n\n get commands () {\n return this.#processors\n }\n\n get commandlist () {\n const list = new Set()\n this.commands.forEach(cmd => {\n list.add(cmd.name)\n cmd.commandlist.forEach(subcmd => list.add(`${cmd.name} ${subcmd}`))\n })\n\n return Array.from(list).sort()\n }\n\n getCommand (name = null) {\n if (!name) {\n return null\n }\n\n const names = name.split(/\\s+/i)\n let cmd = this.#commands.get(names.shift())\n if (cmd) {\n cmd = this.#processors.get(cmd)\n for (const nm of names) {\n cmd = cmd.getCommand(nm)\n }\n }\n\n return cmd instanceof Command ? cmd : null\n }\n\n remove () {\n for (const cmd of arguments) {\n if (typeof cmd === 'symbol') {\n this.#processors.delete(cmd)\n this.#commands.forEach(oid => oid === cmd && this.#commands.delete(oid))\n }\n\n if (typeof cmd === 'string') {\n const OID = this.#commands.get(cmd)\n if (OID) {\n this.remove(OID)\n }\n }\n }\n }\n\n use () {\n for (const arg of arguments) {\n if (typeof arg !== 'function') {\n throw new Error(`All \"use()\" arguments must be valid functions.\\n${arg.toString().substring(0, 50)} ${arg.toString().length > 50 ? '...' : ''}`)\n }\n\n this.#middleware.use(arg)\n }\n\n this.#processors.forEach(subCmd => subCmd.use(...arguments))\n }\n\n trailer () {\n this.#trailer = this.#trailer || new Middleware()\n\n for (const arg of arguments) {\n if (typeof arg !== 'function') {\n throw new Error(`All \"trailer()\" arguments must be valid functions.\\n${arg.toString().substring(0, 50)} ${arg.toString().length > 50 ? '...' : ''}`)\n }\n\n this.#trailer.use(arg)\n }\n\n this.#processors.forEach(subCmd => subCmd.trailer(...arguments))\n }\n\n add () {\n for (let command of arguments) {\n if (!(command instanceof Command)) {\n if (typeof command === 'object') {\n command = new Command(command)\n } else {\n throw new Error('Invalid argument. Only \"Command\" instances may be added to the processor.')\n }\n }\n\n command.autohelp = this.autohelp\n\n if (this instanceof Shell) {\n command.shell = this\n } else if (this instanceof Command) {\n command.parent = this\n }\n\n this.#processors.set(command.OID, command)\n this.#commands.set(command.name, command.OID)\n\n command.aliases.forEach(alias => this.#commands.set(alias, command.OID))\n }\n }\n}\n","// const STRIP_EQUAL_SIGNS = /(\\=+)(?=([^'\"\\\\]*(\\\\.|['\"]([^'\"\\\\]*\\\\.)*[^'\"\\\\]*['\"]))*[^'\"]*$)/g\n\nconst SUBCOMMAND_PATTERN = /^([^\"'][\\S\\b]+)[\\s+]?([^-].*)$/i // eslint-disable-line no-useless-escape\nconst FLAG_PATTERN = /((?:\"[^\"\\\\]*(?:\\\\[\\S\\s][^\"\\\\]*)*\"|'[^'\\\\]*(?:\\\\[\\S\\s][^'\\\\]*)*'|\\/[^\\/\\\\]*(?:\\\\[\\S\\s][^\\/\\\\]*)*\\/[gimy]*(?=\\s|$)|(?:\\\\\\s|\\S))+)(?=\\s|$)/g // eslint-disable-line no-useless-escape\nconst METHOD_PATTERN = /^([\\w]+\\s?)\\(.*\\)\\s?{/i // eslint-disable-line no-useless-escape\nconst STRIP_QUOTE_PATTERN = /\"([^\"\\\\]*(\\\\.[^\"\\\\]*)*)\"|\\'([^\\'\\\\]*(\\\\.[^\\'\\\\]*)*)\\'/ig // eslint-disable-line no-useless-escape\nconst COMMAND_PATTERN = /^(\\w+)\\s+([\\s\\S]+)?/i // eslint-disable-line no-useless-escape\nconst CONSTANTS = Object.freeze({\n SUBCOMMAND_PATTERN,\n FLAG_PATTERN,\n METHOD_PATTERN,\n STRIP_QUOTE_PATTERN,\n COMMAND_PATTERN\n})\n\nexport {\n CONSTANTS as default,\n CONSTANTS,\n SUBCOMMAND_PATTERN,\n FLAG_PATTERN,\n METHOD_PATTERN,\n STRIP_QUOTE_PATTERN,\n COMMAND_PATTERN\n}\n","import Command from './command.js'\nimport Base from './base.js'\nimport { COMMAND_PATTERN } from './utility.js'\n\nexport default class Shell extends Base {\n #middlewareGroups = new Map()\n #history = []\n #maxHistoryItems\n #version\n #cursor = 0\n #tabWidth\n #runtime = globalThis.hasOwnProperty('window') // eslint-disable-line no-prototype-builtins\n ? 'browser'\n : (\n globalThis.hasOwnProperty('process') && // eslint-disable-line no-prototype-builtins\n globalThis.process.release &&\n globalThis.process.release.name\n ? globalThis.process.release.name\n : 'unknown'\n )\n\n constructor (cfg = { maxhistory: 100 }) {\n super(cfg)\n\n this.initializeHelpAnnotations(cfg)\n\n this.__commonflags = cfg.commonflags || {}\n\n if (cfg.hasOwnProperty('use') && Array.isArray(cfg.use)) { // eslint-disable-line no-prototype-builtins\n cfg.use.forEach(code => this.initializeMiddleware(code))\n }\n\n if (cfg.hasOwnProperty('trailer') && Array.isArray(cfg.trailer)) { // eslint-disable-line no-prototype-builtins\n cfg.trailer.forEach(code => this.initializeTrailer(code))\n }\n\n this.#version = cfg.version || '1.0.0'\n this.#maxHistoryItems = cfg.maxhistory || cfg.maxHistoryItems || 100\n this.#tabWidth = cfg.hasOwnProperty('tabWidth') ? cfg.tabWidth : 4 // eslint-disable-line no-prototype-builtins\n\n // This sets a global symbol that dev tools can find.\n globalThis[Symbol('SHELL_INTEGRATIONS')] = this\n }\n\n get data () {\n const commands = super.data\n\n return {\n name: this.name,\n description: this.description,\n version: this.version,\n commands,\n use: this.middleware.data,\n trailer: this.trailers.data,\n help: this.help,\n usage: this.usage,\n defaultHandler: this.defaultHandler.toString(),\n disableHelp: !this.autohelp,\n runtime: this.#runtime,\n maxHistoryItems: this.#maxHistoryItems\n }\n }\n\n get version () {\n return this.#version || 'Unknown'\n }\n\n set tableWidth (value) {\n this.__width = value\n }\n\n get tableWidth () {\n return this.__width\n }\n\n history (count = null) {\n if (this.#history.length === 0) {\n return []\n }\n\n return count === null ? this.#history.slice() : this.#history.slice(0, count)\n }\n\n priorCommand (count = 0) {\n if (this.#history.length === 0) {\n return null\n }\n\n if (count < 0) {\n return this.nextCommand(Math.abs(count))\n }\n\n count = count % this.#history.length\n\n this.#cursor += count\n\n if (this.#cursor >= this.#history.length) {\n this.#cursor = this.#history.length - 1\n }\n\n return this.#history[this.#cursor].input\n }\n\n nextCommand (count = 1) {\n if (this.#history.length === 0) {\n return null\n }\n\n if (count < 0) {\n return this.priorCommand(Math.abs(count))\n }\n\n count = count % this.#history.length\n\n this.#cursor -= count\n if (this.#cursor < 0) {\n this.#cursor = 0\n return undefined\n }\n\n return this.#history[this.#cursor].input\n }\n\n useWith (commands) {\n if (arguments.length < 2) {\n throw new Error('useWith([\\'command\\', \\'command\\'], fn) requires two or more arguments.')\n }\n\n commands = typeof commands === 'string' ? commands.split(/\\s+/) : commands\n\n if (!Array.isArray(commands) || commands.filter(c => typeof c !== 'string').length > 0) {\n throw new Error(`The first argument of useWith must be a string or array of strings. Received ${typeof commands}`)\n }\n\n const fns = Array.from(arguments).slice(1)\n\n commands.forEach(cmd => this.#middlewareGroups.set(cmd.trim(), (this.#middlewareGroups.get(cmd.trim()) || []).concat(fns)))\n }\n\n useExcept (commands) {\n if (arguments.length < 2) {\n throw new Error('useExcept([\\'command\\', \\'command\\'], fn) requires two or more arguments.')\n }\n\n commands = typeof commands === 'string' ? commands.split(/\\s+/) : commands\n\n if (!Array.isArray(commands) || commands.filter(c => typeof c !== 'string').length > 0) {\n throw new Error(`The first argument of useExcept must be a string or array of strings. Received ${typeof commands}`)\n }\n\n const fns = Array.from(arguments).slice(1)\n const all = new Set(this.commandlist.map(i => i.toLowerCase()))\n\n commands.forEach(cmd => {\n all.delete(cmd)\n for (const c of all) {\n if (c.indexOf(cmd) === 0) {\n all.delete(c)\n }\n }\n })\n\n this.useWith(Array.from(all), ...fns)\n }\n\n async exec (input, callback) {\n // The array check exists because people are passing process.argv.slice(2) into this\n // method, often forgetting to join the values into a string.\n if (Array.isArray(input)) {\n input = input.map(i => {\n if (i.indexOf(' ') >= 0 && !/^[\\\"\\'].+ [\\\"\\']$/.test(i)) {\n return `\"${i}\"`\n } else {\n return i\n }\n }).join(' ')\n }\n\n this.#history.unshift({ input, time: new Date().toLocaleString() })\n\n if (this.#history.length > this.#maxHistoryItems) {\n this.#history.pop()\n }\n\n let parsed = COMMAND_PATTERN.exec(input + ' ')\n\n if (parsed === null) {\n if (input.indexOf('version') !== -1 || input.indexOf('-v') !== -1) {\n return console.log(this.version)\n } else if (input.indexOf('help') !== -1) {\n return console.log(this.help)\n }\n\n return Command.stderr(this.help)\n }\n\n parsed = parsed.filter(item => item !== undefined)\n\n const cmd = parsed[1]\n const args = parsed.length > 2 ? parsed[2] : ''\n // const command = null\n\n const action = this.__commands.get(cmd)\n\n if (!action) {\n if (cmd.toLowerCase() === 'version') {\n return console.log(this.version)\n }\n\n return Command.stderr(this.help)\n }\n\n const processor = this.__processors.get(action)\n\n if (!processor) {\n return Command.stderr('Command not found.')\n }\n\n const term = processor.getTerminalCommand(args)\n return await Command.reply(await term.command.run(term.arguments, callback))\n }\n\n getCommandMiddleware (cmd) {\n const results = []\n cmd.split(/\\s+/).forEach((c, i, a) => {\n const r = this.#middlewareGroups.get(a.slice(0, i + 1).join(' '))\n r && results.push(r.flat(Infinity))\n })\n\n return results.flat(Infinity)\n }\n\n clearHistory () {\n this.#history = []\n }\n\n // Clear the terminal\n clear () {\n this.#history = []\n console.clear()\n // .write('\\x1b[0f') // regular clear\n // .write('\\x1b[2J') // full clear\n // .write('\\033[0;0f') //ubuntu\n }\n}\n","// import { Parser } from '../../../@author.io/arg/index.js'\nimport { Parser } from '@author.io/arg'\nimport Shell from './shell.js'\nimport Base from './base.js'\nimport { METHOD_PATTERN, FLAG_PATTERN, STRIP_QUOTE_PATTERN } from './utility.js'\n\nexport default class Command extends Base {\n #pattern\n #oid\n #aliases = new Set()\n #fn\n #flagConfig = {}\n #parent = null\n #shell = null\n\n constructor (cfg = {}) {\n if (cfg.hasOwnProperty('handler')) { // eslint-disable-line no-prototype-builtins\n if (typeof cfg.handler === 'string') {\n cfg.handler = Function('return (' + cfg.handler.replace('function anonymous', 'function') + ').call(this)').call(globalThis) // eslint-disable-line no-new-func\n }\n\n if (typeof cfg.handler !== 'function') {\n throw new Error('Invalid command configuration. A \"handler\" function is required.')\n }\n }\n\n super(cfg)\n\n if (cfg.hasOwnProperty('use') && Array.isArray(cfg.use)) { // eslint-disable-line no-prototype-builtins\n cfg.use.forEach(code => this.initializeMiddleware(code))\n }\n\n if (cfg.hasOwnProperty('trailer') && Array.isArray(cfg.trailer)) { // eslint-disable-line no-prototype-builtins\n cfg.trailer.forEach(code => this.initializeTrailer(code))\n }\n\n this.initializeHelpAnnotations(cfg)\n\n this.#fn = cfg.handler\n this.#oid = Symbol(((cfg.name || cfg.usage) || cfg.pattern) || 'command')\n this.#pattern = cfg.pattern || /[\\s\\S]+/i\n\n if (cfg.alias && !cfg.aliases) {\n cfg.aliases = typeof cfg.alias === 'string' ? [cfg.alias] : (Array.isArray(cfg.alias) ? cfg.alias : Array.from(cfg.alias))\n delete cfg.alias\n }\n\n if (cfg.aliases) {\n if (!Array.isArray(cfg.aliases)) {\n throw new Error('The alias property only accepts an array.')\n }\n\n this.#aliases = new Set(cfg.aliases)\n }\n\n if (cfg.flags) {\n if (typeof cfg.flags !== 'object') {\n throw new Error(`Invalid flag configuration (expected and object, received ${typeof cfg.flags}).`)\n }\n\n for (const [key, value] of Object.entries(cfg.flags)) {\n if (value.hasOwnProperty('alias')) { // eslint-disable-line no-prototype-builtins\n value.aliases = value.aliases || []\n\n if (Array.isArray(value.alias)) {\n value.aliases = Array.from(new Set(...value.aliases, ...value.alias))\n if (value.aliases.filter(a => typeof a !== 'string') > 0) {\n throw new Error(`${key} flag aliases must be strings. Type failure on: ${value.aliases.filter(a => typeof a !== 'string').join(', ')}.`)\n }\n } else if (typeof value.alias === 'string') {\n value.aliases.push(value.alias)\n } else {\n throw new Error(`Aliases must be strings, not ${typeof value.alias} (${key} flag).`)\n }\n\n delete value.alias\n }\n }\n\n this.#flagConfig = cfg.flags\n }\n\n if (Array.isArray(cfg.subcommands)) {\n this.add(...cfg.subcommands)\n }\n\n const attributes = new Set([\n 'commands',\n 'subcommands',\n 'plugins',\n 'defaultHandler',\n 'disableHelp',\n 'describeDefault',\n 'describeOptions',\n 'describeMultipleValues',\n 'describeRequired',\n 'flags',\n 'alias',\n 'aliases',\n 'description',\n 'help',\n 'usage',\n 'pattern',\n 'name',\n 'handler',\n 'middleware',\n 'use',\n 'arguments',\n 'commonflag',\n 'commonflags',\n 'trailer',\n 'url',\n 'support'\n ])\n\n const unrecognized = Object.keys(cfg).filter(attribute => !attributes.has(attribute))\n\n if (unrecognized.length > 0) {\n throw new Error(`Unrecognized configuration attribute(s): ${unrecognized.join(', ')}`)\n }\n\n const ignoreFlags = commonFlags => {\n if (commonFlags.ignore && (Array.isArray(commonFlags.ignore) || typeof commonFlags.ignore === 'string')) {\n const ignore = new Set(Array.isArray(commonFlags.ignore) ? commonFlags.ignore : [commonFlags.ignore])\n // delete commonFlags.ignore\n const root = this.commandroot.replace(new RegExp(`^${this.shell.name}\\\\s+`, 'i'), '')\n\n for (const cmd of ignore) {\n if (root.startsWith(cmd)) {\n commonFlags = {}\n break\n }\n }\n }\n\n return commonFlags\n }\n\n Object.defineProperties(this, {\n __commonFlags: {\n enumerable: false,\n get () {\n let flags = ignoreFlags(this.__commonflags) // Object.assign({}, this.__commonflags, this.#flagConfig)\n\n if (this.parent !== null) {\n flags = Object.assign(flags, this.parent.__commonFlags)\n }\n\n const result = Object.assign({}, this.shell !== null ? ignoreFlags(this.shell.__commonflags) : {}, flags)\n\n if (Array.isArray(result.ignore) || typeof result.ignore === 'string') {\n delete result.ignore\n }\n\n return result\n }\n },\n __flagConfig: {\n enumerable: false,\n get () {\n const flags = new Map(Object.entries(Object.assign(this.__commonFlags, this.#flagConfig || {})))\n flags.delete('help')\n return flags\n }\n },\n getTerminalCommand: {\n enumerable: false,\n configurable: false,\n writable: false,\n value: input => {\n const args = input.trim().split(/\\t+|\\s+/)\n let cmd = this\n\n while (args.length > 0) {\n const arg = args[0]\n const subcmd = cmd.getCommand(arg)\n if (subcmd) {\n cmd = subcmd\n args.shift()\n } else {\n break\n }\n }\n\n return {\n command: cmd,\n arguments: args.join(' ')\n }\n }\n }\n })\n\n this.__commonflags = cfg.commonflags || {}\n\n this.__width = this.shell === null ? 80 : this.shell.tableWidth || 80\n\n this.updateHelp()\n }\n\n get data () {\n const commands = super.data\n\n let handler = (this.#fn || this.defaultHandler).toString()\n if (METHOD_PATTERN.test(handler)) {\n handler = handler.replace(METHOD_PATTERN.exec(handler)[1], 'function ')\n }\n\n const flags = Object.assign(this.__commonFlags, this.#flagConfig || {})\n\n for (const [key, value] of Object.entries(flags)) { // eslint-disable-line no-unused-vars\n value.aliases = value.aliases || []\n\n if (value.hasOwnProperty('alias')) { // eslint-disable-line no-prototype-builtins\n if (value.aliases.indexOf(value.alias) < 0) {\n value.aliases.push(value.alias)\n }\n }\n\n delete value.alias\n }\n\n // Apply any missing default values to flags.\n Object.keys(flags).forEach(name => { flags[name] = Object.assign(this.getFlagConfiguration(name), flags[name]) })\n\n const data = {\n name: this.name,\n description: this.description,\n help: this.help,\n usage: this.usage,\n aliases: Array.from(this.#aliases),\n flags,\n handler,\n commands,\n disableHelp: !this.autohelp,\n use: this.middleware.data,\n trailer: this.trailers.data\n }\n\n for (const [key, value] of Object.entries(data.flags)) { // eslint-disable-line no-unused-vars\n delete value.alias\n }\n\n return data\n }\n\n set parent (cmd) {\n if (cmd instanceof Command) {\n this.#parent = cmd\n } else {\n throw new Error(`Cannot set parent of \"${this.name}\" command to anything other than another command. To make this command a direct descendent of the main shell, use the shell attribute instead.`)\n }\n }\n\n get parent () {\n return this.#parent\n }\n\n set shell (shell) {\n if (!shell) {\n throw new Error(`Cannot set shell of ${this.name} command to a non-Shell object.`)\n }\n if (shell instanceof Shell) {\n this.#shell = shell\n this.__width = this.shell === null ? 80 : shell.tableWidth\n } else {\n throw new Error(`Expected a Shell object, received a \"${typeof shell}\" object.`)\n }\n }\n\n get shell () {\n if (!this.#shell) {\n if (this.#parent) {\n return this.#parent.shell\n }\n\n return null\n }\n\n return this.#shell\n }\n\n get plugins () {\n return Object.assign({}, this.shell.plugins, this.parent ? this.parent.plugins : {}, super.plugins)\n }\n\n get commandroot () {\n if (this.#parent) {\n return `${this.#parent.commandroot} ${this.name}`.trim()\n }\n\n if (this.#shell) {\n return `${this.#shell.name} ${this.name}`.trim()\n }\n\n return this.name\n }\n\n set aliases (value) {\n if (!value) {\n this.#aliases = []\n return\n }\n\n if (typeof value === 'object') {\n switch (value.constructor.name.toLowerCase()) {\n case 'map':\n value = Array.from(value.keys())\n break\n case 'set':\n value = Array.from(value)\n break\n case 'object':\n value = Object.keys(value).filter(item => typeof item === 'string')\n break\n case 'array':\n break\n case 'string':\n value = value.split(/\\s+/)[0]\n break\n default:\n throw new Error('Invalid alias value. Use an array of strings.')\n }\n }\n\n this.#aliases = Array.from(new Set(value)) // This conversion deduplicates the value\n }\n\n get aliases () {\n return Array.from(this.#aliases) || []\n }\n\n get OID () {\n return this.#oid\n }\n\n addFlag (name, cfg) {\n if (typeof name !== 'string') {\n if (!cfg.hasOwnProperty('name')) { // eslint-disable-line no-prototype-builtins\n throw new Error('Invalid flag name (should be a string).')\n } else {\n name = cfg.name\n }\n }\n\n this.#flagConfig[name] = cfg\n }\n\n removeFlag (name) {\n delete this.#flagConfig[name]\n }\n\n getFlagConfiguration (name) {\n let flag = this.__flagConfig.get(name)\n if (!flag) {\n for (const [f, cfg] of this.__flagConfig) { // eslint-disable-line no-unused-vars\n if ((cfg.aliases && cfg.aliases.indexOf(name) >= 0) || (cfg.alias && cfg.alias === flag)) {\n flag = cfg\n break\n }\n }\n\n if (!flag) {\n return null\n }\n }\n\n return {\n description: flag.description,\n required: flag.hasOwnProperty('required') ? flag.required : false, // eslint-disable-line no-prototype-builtins\n aliases: flag.aliases || [flag.alias].filter(i => i !== null),\n type: flag.type === undefined ? 'string' : (typeof flag.type === 'string' ? flag.type : flag.type.name.toLowerCase()),\n options: flag.hasOwnProperty('options') ? flag.options : null, // eslint-disable-line no-prototype-builtins\n allowMultipleValues: flag.hasOwnProperty('allowMultipleValues') ? flag.allowMultipleValues : false // eslint-disable-line no-prototype-builtins\n }\n }\n\n supportsFlag (name) {\n return this.#flagConfig.hasOwnProperty(name) // eslint-disable-line no-prototype-builtins\n }\n\n deepParse (input) {\n const meta = this.parse(input)\n\n if (this.__commands.size === 0) {\n return meta\n }\n\n if (meta.input.trim().length === 0) {\n return meta\n }\n\n const args = meta.input.split(/\\s+/)\n const subcmd = this.__commands.get(args.shift())\n\n if (!subcmd) {\n return meta\n }\n\n return this.__processors.get(subcmd).deepParse(args.join(' '))\n }\n\n parse (input) {\n // Parse the command input for flags\n const data = { command: this.name, input: input.trim() }\n const flagConfig = Object.assign(this.__commonFlags, this.#flagConfig || {})\n\n if (!flagConfig.hasOwnProperty('help')) { // eslint-disable-line no-prototype-builtins\n flagConfig.help = {\n description: `Display ${this.name} help.`,\n // aliases: ['h'],\n default: false,\n type: 'boolean'\n }\n }\n\n const flags = Array.from(FLAG_PATTERN[Symbol.matchAll](input), x => x[0])\n const parser = new Parser(flags, flagConfig)\n const pdata = parser.data\n const recognized = {}\n\n parser.recognizedFlags.forEach(flag => { recognized[flag] = pdata[flag] })\n parser.unrecognizedFlags.forEach(arg => delete recognized[arg])\n\n data.flags = { recognized, unrecognized: parser.unrecognizedFlags }\n data.valid = parser.valid\n data.violations = parser.violations\n\n data.parsed = {}\n if (Object.keys(pdata.flagSource).length > 0) {\n for (const [key, src] of Object.entries(pdata.flagSource)) { // eslint-disable-line no-unused-vars\n data.parsed[src.name] = src.inputName\n }\n }\n\n data.help = {\n requested: recognized.help\n }\n\n if (recognized.help) {\n data.help.message = this.help\n }\n\n const args = Array.from(this.arguments)\n\n Object.defineProperties(data, {\n flag: {\n enumerable: true,\n configurable: false,\n writable: false,\n value: name => {\n try {\n if (typeof name === 'number') {\n return Array.from(parser.unrecognizedFlags)[name]\n } else {\n if (data.flags.recognized.hasOwnProperty(pdata.flagSource[name].name)) { // eslint-disable-line no-prototype-builtins\n return data.flags.recognized[pdata.flagSource[name].name]\n } else {\n return pdata.flagSource[name].value\n }\n }\n } catch (e) {\n if (this.arguments.has(name)) {\n return Array.from(parser.unrecognizedFlags)[args.indexOf(name)]\n }\n\n return undefined\n }\n }\n },\n command: {\n enumerable: true,\n get: () => this\n },\n shell: {\n enumerable: true,\n get: () => this.shell\n },\n data: {\n enumerable: true,\n get () {\n const uf = parser.unrecognizedFlags\n const result = Object.assign({}, recognized)\n delete result.help\n\n args.forEach((name, i) => {\n const value = uf[i]\n let normalizedValue = Object.keys(pdata).filter(key => key.toLowerCase() === value)\n normalizedValue = (normalizedValue.length > 0 ? normalizedValue.pop() : value)\n\n if (normalizedValue !== undefined) {\n normalizedValue = normalizedValue.trim()\n\n if (STRIP_QUOTE_PATTERN.test(normalizedValue)) {\n normalizedValue = normalizedValue.substring(1, normalizedValue.length - 1)\n }\n }\n\n if (result.hasOwnProperty(name)) { // eslint-disable-line no-prototype-builtins\n result[name] = Array.isArray(result[name]) ? result[name] : [result[name]]\n result[name].push(normalizedValue)\n } else {\n result[name] = normalizedValue\n }\n })\n\n if (uf.length > args.length) {\n uf.slice(args.length)\n .forEach((flag, i) => {\n let name = `unknown${i + 1}`\n while (result.hasOwnProperty(name)) { // eslint-disable-line no-prototype-builtins\n const number = name.substring(7)\n name = 'unknown' + (parseInt(number) + 1)\n }\n\n result[name] = flag\n })\n }\n\n return result\n }\n }\n })\n\n Object.defineProperty(data.help, 'default', {\n enumerable: true,\n get: () => this.help\n })\n\n return data\n }\n\n async run (input, callback) {\n const fn = (this.#fn || this.defaultHandler).bind(this)\n const data = typeof input === 'string' ? this.parse(input) : input\n\n arguments[0] = this.deepParse(input)\n arguments[0].plugins = this.plugins\n\n if (this.shell !== null) {\n const parentMiddleware = this.shell.getCommandMiddleware(this.commandroot.replace(new RegExp(`^${this.shell.name}`, 'i'), '').trim())\n\n if (parentMiddleware.length > 0) {\n this.middleware.use(...parentMiddleware)\n }\n }\n\n const trailers = this.trailers\n\n if (arguments[0].help && arguments[0].help.requested) {\n console.log(this.help)\n\n if (trailers.size > 0) {\n trailers.run(arguments[0])\n }\n\n return\n }\n\n // No subcommand was recognized\n if (this.middleware.size > 0) {\n this.middleware.run(arguments[0], async meta => await Command.reply(fn(meta, callback)))\n\n if (trailers.size > 0) {\n trailers.run(arguments[0])\n }\n\n return\n }\n\n // Command.reply(fn(arguments[0], callback))\n data.plugins = this.plugins\n Command.reply(fn(data, callback))\n\n if (trailers.size > 0) {\n trailers.run(arguments[0])\n }\n }\n\n static stderr (err) {\n if (err instanceof Error) {\n return new Promise((resolve, reject) => reject(err)).catch(console.error)\n }\n\n return new Promise((resolve, reject) => reject(err)).catch(console.error)\n }\n\n static reply (callback) {\n return new Promise((resolve, reject) => {\n try {\n if (typeof callback === 'function') {\n callback()\n }\n\n resolve()\n } catch (e) {\n reject(e)\n }\n })\n }\n}\n","import Command from './command.js'\nimport Shell from './shell.js'\nimport Middleware from './middleware.js'\nimport { Formatter, Table } from './format.js'\nconst all = { Shell, Command, Formatter, Table, Middleware }\nexport { Command, Shell, Formatter, Table, Middleware, all as default }\n"],"names":["Middleware","constructor","Object","defineProperties","this","_data","enumerable","configurable","value","go","writable","args","pop","apply","length","use","method","methodBody","toString","indexOf","push","stack","next","bind","run","Array","from","arguments","Formatter","data","desc","_classPrivateFieldGet","description","trim","Command","aliases","out","commandroot","join","__flagConfig","size","map","i","__processors","Table","replace","output","Shell","name","rows","values","cmd","concat","result","table","usage","flags","forEach","cfg","flag","alias","a","dsc","hasOwnProperty","describeOptions","options","allowMultipleValues","describeMultipleValues","describeDefault","default","required","describeRequired","unshift","subcommands","Base","Set","Map","Default","Options","MultipleValues","Required","meta","parent","hasCustomDefaultHandler","defaultHandler","shell","console","log","help","Error","disableHelp","disablehelp","split","arg","isArray","url","support","commands","add","key","warn","middleware","commonflag","commonFlag","commonflags","commonFlags","plugins","get","__commands","__width","set","v","__commonflags","initializeMiddleware","code","Function","initializeTrailer","trailer","initializeHelpAnnotations","updateHelp","URL","uri","autohelp","width","describeHelp","attr","prop","defaultProcessor","list","commandlist","subcmd","sort","getCommand","names","shift","nm","remove","delete","oid","OID","substring","subCmd","command","FLAG_PATTERN","METHOD_PATTERN","STRIP_QUOTE_PATTERN","COMMAND_PATTERN","freeze","SUBCOMMAND_PATTERN","maxhistory","globalThis","process","release","version","maxHistoryItems","tabWidth","Symbol","super","trailers","runtime","history","count","slice","priorCommand","nextCommand","Math","abs","input","useWith","filter","c","fns","useExcept","all","toLowerCase","callback","test","time","Date","toLocaleString","parsed","exec","stderr","item","undefined","action","processor","term","getTerminalCommand","reply","getCommandMiddleware","results","r","flat","Infinity","clearHistory","clear","handler","call","pattern","entries","attributes","unrecognized","keys","attribute","has","ignoreFlags","ignore","root","RegExp","startsWith","__commonFlags","assign","tableWidth","getFlagConfiguration","addFlag","removeFlag","f","type","supportsFlag","deepParse","parse","flagConfig","matchAll","x","parser","Parser","pdata","recognized","recognizedFlags","unrecognizedFlags","valid","violations","flagSource","src","inputName","requested","message","e","uf","normalizedValue","number","parseInt","defineProperty","fn","parentMiddleware","async","err","Promise","resolve","reject","catch","error"],"mappings":";;;o7BAAe,MAAMA,WACnBC,cACEC,OAAOC,iBAAiBC,KAAM,CAC5BC,MAAO,CAAEC,YAAY,EAAOC,cAAc,EAAOC,MAAO,IACxDC,GAAI,CAAEH,YAAY,EAAOC,cAAc,EAAOG,UAAU,EAAMF,MAAO,IAAIG,QAAWA,KAAKC,MAAMC,MAAMT,KAAMO,4BAI1FP,KAAKC,MAAMS,yBAEXV,KAAKC,MAE1BU,IAAKC,cACGC,WAAaD,OAAOE,WACtBD,WAAWE,QAAQ,iBAAmB,QACnCd,MAAMe,KAAKH,iBAGbR,GAAK,CAACY,OAAS,IAAIV,cAChBW,KAAOX,KAAKC,MAClBS,SAASV,KAAM,KACbK,OAAOH,MAAMT,KAAM,IAAIO,KAAMW,KAAKC,KAAK,QAASZ,WAH1C,CAKPP,KAAKK,IAGVe,YACQb,KAAOc,MAAMC,KAAKC,WACJ,IAAhBhB,KAAKG,QAAiD,mBAA1BH,KAAKA,KAAKG,OAAS,IACjDH,KAAKS,KAAK,aAGPX,MAAME,iGC5Bf,MAAMiB,UAMJ3B,YAAa4B,wCALL,+CACM,2CACF,2CACA,CAAC,MAAO,MAAO,0CAGZA,gBAGJrB,8CACUA,MAAQ,GAAK,GAAKA,wBAGrBA,4CACCA,2BAGEA,4CACFA,yBAIXsB,KAAOC,kCAAWC,YAAYC,UAEhCF,4CAAsBG,QAAS,OAC3BC,QAAUJ,kCAAWI,QACrBC,IAAM,CAAE,GAAEL,kCAAWM,cAAcF,QAAQrB,OAAS,EAAI,IAAMqB,QAAQG,KAAK,KAAO,KAAKP,kCAAWQ,aAAaC,KAAO,EAAI,WAAa,KAAKT,kCAAWJ,UAAUa,KAAO,EAAI,IAAMf,MAAMC,KAAKK,kCAAWJ,WAAWc,IAAIC,GAAK,IAAMA,EAAI,KAAKJ,KAAK,KAAO,aAEzPP,kCAAWY,aAAaH,KAAO,IACjCJ,IAAIA,IAAItB,OAAS,KAAOiB,kCAAWJ,UAAUa,KAAO,GAAKT,kCAAWQ,aAAaC,KAAO,EAAI,KAAO,IAAM,cAGvGV,KAAKG,OAAOnB,OAAS,GAAKsB,MAAQN,MACpCM,IAAIhB,KAAK,IAAIwB,MAAM,CAAC,CAACd,KAAKG,OAAOY,QAAQ,OAAQ,UAAW,KAAM,2BAAMzC,kBAAkB,CAAC,EAAG,EAAG,EAAG,IAAI0C,QAGnGV,IAAIE,KAAK,MACX,OAAIP,4CAAsBgB,MACvB,GAAEhB,kCAAWiB,OAAOjB,kCAAWY,aAAaH,KAAO,EAAI,aAAe,OAAOV,KAAKG,OAAOnB,OAAS,EAAI,IAAI8B,MAAM,CAAC,CAACd,KAAKG,OAAOY,QAAQ,OAAQ,UAAW,KAAM,2BAAMzC,kBAAkB,CAAC,EAAG,EAAG,EAAG,IAAI0C,OAAS,KAAKf,kCAAWJ,UAAUa,KAAO,EAAI,IAAMf,MAAMC,KAAKK,kCAAWJ,WAAWc,IAAIC,GAAK,IAAMA,EAAI,KAAKJ,KAAK,KAAO,OAAOL,OAGxU,2BAIDgB,KAAOxB,MAAMC,KAAKK,kCAAWY,aAAaO,UAAUT,IAAIU,KAErD,CADI,CAACA,IAAIH,MAAMI,OAAOD,IAAIhB,SACtBG,KAAK,KAAMa,IAAInB,cAGtBqB,OAAS,MAEXJ,KAAKnC,OAAS,EAAG,OACbwC,MAAQ,IAAIV,MAAMK,2BAAM7C,gBAAgB,CAAC,MAAO,6BAAQA,kBAAkB,CAAC,IACjFiD,OAAOjC,KAAK,iBACZiC,OAAOjC,KAAKkC,MAAMR,eAGbO,OAAOf,KAAK,uBAIbiB,MAAQnD,KAAKmD,MAAMtB,UAErBF,4CAAsBG,QAAS,OAC3BsB,MAAQzB,kCAAWQ,aACnBU,KAAO,GAETO,MAAMhB,KAAO,GACfgB,MAAMC,QAAQ,CAACC,IAAKC,YACdxB,QAAUV,MAAMC,KAAKgC,IAAIvB,SAAWuB,IAAIE,OAAS,IACrDzB,QAA6B,IAAnBA,QAAQrB,OAAe,GAAK,IAAMqB,QAAQM,IAAIoB,GAAM,IAAGA,GAAKvB,KAAK,MAAQ,QAE/EwB,IAAM,CAACJ,IAAI1B,aAAe,IAE1B0B,IAAIK,eAAe,YAAchC,kCAAWiC,iBAC9CF,IAAI1C,KAAM,YAAWsC,IAAIO,QAAQ3B,KAAK,UAGpCoB,IAAIK,eAAe,yBAAsD,IAA5BL,IAAIQ,qBAAgCnC,kCAAWoC,wBAC9FL,IAAI1C,KAAK,+BAGPsC,IAAIK,eAAe,YAAchC,kCAAWqC,iBAC9CN,IAAI1C,KAAM,aAAYsC,IAAIW,QAAQnD,eAGhCwC,IAAIK,eAAe,cAAgC,IAAjBL,IAAIY,UAAqBvC,kCAAWwC,kBACxET,IAAIU,QAAQ,aAGdV,IAAMA,IAAIxB,KAAK,KAAKL,OAEpBgB,KAAK7B,KAAK,CAAC,KAAOuC,KAAMxB,SAAW,GAAI2B,KAAO,aAI5CR,MAAQ,IAAIV,MAAMK,2BAAM7C,sCAAgBA,sCAAgBA,kBAAkB,CAAC,EAAG,EAAGmD,MAAMzC,OAAS,EAAI,EAAI,EAAG,QAE7G2D,YAAc,KAAOrE,KAAKqE,mBACI,IAA9BA,YAAYxC,OAAOnB,SACrB2D,YAAc,IAETlB,OAASC,MAAMhB,KAAO,EAAI,eAAiBc,MAAMR,OAAS,IAAM2B,YAClE,OAAI1C,4CAAsBgB,MACxB,CAACQ,MAAOnD,KAAKqE,aAAanC,KAAK,MAGjC,2cC5GI,MAAMoC,KAuCnBzE,YAAayD,IAAM,4CAtCR,sCACJ,4CACI,8PAKE,IAAIiB,6CACL,4CACE,IAAIC,4CACN,IAAIA,yCACP,uCACD,oDACM,IAAI5E,kDACP,IAAIA,sDACA,0CACJ,CAET6E,QAAS,KACTC,QAAS,KACTC,eAAgB,KAChBC,SAAU,8DAGe,gDAET,SAAUC,aACN,OAAhB7E,KAAK8E,QAAmB9E,KAAK8E,OAAOC,wBAC/B/E,KAAK8E,OAAOE,kBAAkBzD,WAC5BvB,KAAKiF,OAAwB,OAAfjF,KAAKiF,OAAkBjF,KAAKiF,MAAMF,wBAClD/E,KAAKiF,MAAMD,kBAAkBzD,sCAGlCvB,iBACFkF,QAAQC,IAAInF,KAAKoF,UAKA,iBAAR9B,UACH,IAAI+B,MAAM,0DAGb/B,IAAIK,eAAe,cAChB,IAAI0B,MAAM,qEAGd/B,IAAIK,eAAe,gDACFL,IAAI8B,MAGrB9B,IAAIK,eAAe,kDACDL,IAAIH,OAGtBG,IAAIK,eAAe,iBAAmBL,IAAIK,eAAe,iBAC3DL,IAAIgC,YAAchC,IAAIiC,aAGpBjC,IAAIK,eAAe,iBAAsC,IAApBL,IAAIgC,mDAC1B,GAGK,mBAAbhC,IAAI8B,MAA2C,iBAAb9B,IAAI8B,YAC1CA,KAAO9B,IAAI8B,MAGO,mBAAd9B,IAAIH,OAA6C,iBAAdG,IAAIH,aAC3CA,MAAQG,IAAIH,OAGfG,IAAIK,eAAe,mBAAqBL,IAAI0B,eAAelE,aAAea,4CAAqBb,kBAC5FkE,eAAiB1B,IAAI0B,gBAGC,iBAAlB1B,IAAI/B,YACb+B,IAAI/B,UAAY+B,IAAI/B,UAAUiE,MAAM,mBAAmBnD,IAAIoD,KAAOA,IAAI5D,SAGpER,MAAMqE,QAAQpC,IAAI/B,kDACF,IAAIgD,IAAIjB,IAAI/B,YAGT,iBAAZ+B,IAAIqC,qCACDrC,IAAIqC,KAGS,iBAAhBrC,IAAIsC,6CACGtC,IAAIsC,2CAGRtC,IAAIV,MAAQ,WAAWf,OAAO2D,MAAM,OAAO,4CACrClC,IAAI1B,aAAe,MAEnCP,MAAMqE,QAAQpC,IAAIuC,UACpBvC,IAAIuC,SAASxC,QAAQN,KAAO/C,KAAK8F,IAAI/C,WAChC,GAA4B,iBAAjBO,IAAIuC,aACf,MAAME,OAAOzC,IAAIuC,SAAU,OACxBpE,KAAO6B,IAAIuC,SAASE,KAC1BtE,KAAKmB,KAAOmD,SACPD,IAAIrE,SAIT6B,IAAIK,eAAe,gBACrBuB,QAAQc,KAAK,0EACb1C,IAAI3C,IAAM2C,IAAI2C,kBACP3C,IAAI2C,YAGR3C,IAAIK,eAAe,gBAClBL,IAAIK,eAAe,cACrBL,IAAI4C,WAAa5C,IAAI6C,WACZ7C,IAAIK,eAAe,eAC5BL,IAAI4C,WAAa5C,IAAI8C,YACZ9C,IAAIK,eAAe,cAC5BL,IAAI4C,WAAa5C,IAAI6C,WACZ7C,IAAIK,eAAe,iBAC5BL,IAAI4C,WAAa5C,IAAI+C,cAIrB/C,IAAIK,eAAe,eACS,iBAAnBL,IAAI4C,iBACP,IAAIb,MAAM,+DAIO,iBAAhB/B,IAAIgD,6CACGhD,IAAIgD,SAGtBxG,OAAOC,iBAAiBC,KAAM,CAC5BuC,aAAc,CACZrC,YAAY,EACZqG,mCACSvG,oBAGXwG,WAAY,CACVtG,YAAY,EACZqG,mCACSvG,kBAGXyG,QAAS,CACPvG,YAAY,EACZqG,mCACSvG,cAET0G,IAAKC,qCACWA,GAAK,MAGvBC,cAAe,CACb1G,YAAY,EACZqG,mCACSvG,oBAET0G,IAAKtG,+CACiBA,SAGxBmB,UAAW,CACTrB,YAAY,EACZqG,mCACSvG,mBAGX6G,qBAAsB,CACpB3G,YAAY,EACZC,cAAc,EACdG,UAAU,EACVF,MAAO0G,UACe,iBAATA,UACJnG,IAAIoG,SAAS,UAAYD,KAArBC,QACJ,CAAA,GAAoB,mBAATD,WAGV,IAAIzB,MAAM,uBAAyByB,KAAKhG,iBAFzCH,IAAImG,SAMfE,kBAAmB,CACjB9G,YAAY,EACZC,cAAc,EACdG,UAAU,EACVF,MAAO0G,UACe,iBAATA,UACJG,QAAQF,SAAS,UAAYD,KAArBC,QACR,CAAA,GAAoB,mBAATD,WAGV,IAAIzB,MAAM,oBAAsByB,KAAKhG,iBAFtCmG,QAAQH,SAMnBI,0BAA2B,CACzBhH,YAAY,EACZC,cAAc,EACdG,UAAU,EACVF,MAAOkD,MACDA,IAAIK,eAAe,oBAAqD,kBAAxBL,IAAIU,uDACxCS,QAAUnB,IAAIU,iBAE1BV,IAAIK,eAAe,oBAAqD,kBAAxBL,IAAIM,uDACxCc,QAAUpB,IAAIM,iBAE1BN,IAAIK,eAAe,2BAAmE,kBAA/BL,IAAIS,8DAC/CY,eAAiBrB,IAAIS,wBAEjCT,IAAIK,eAAe,qBAAuD,kBAAzBL,IAAIa,wDACzCS,SAAWtB,IAAIa,2BAMhCgD,wDAIEnH,iCAKA2B,mCAAc,mCAKdA,0CAAqB3B,KAAKmD,OAAS,oBAKnCnD,KAAKoH,oBAKNC,KAAO1F,kCAAa,IAAIE,UAEX,IAAfwF,IAAI3G,OAAc,IAChBV,KAAK2D,eAAe,iBACf3D,KAAK8E,OAAOsC,IACd,GAAIpH,gBAAgB8B,eAClB9B,KAAKiF,MAAMmC,WAIfC,wBAKDzB,SAAWjE,sCAAiB,IAAIE,UAEf,IAAnB+D,QAAQlF,OAAc,IACpBV,KAAK2D,eAAe,iBACf3D,KAAK8E,OAAOc,QACd,GAAI5F,gBAAgB8B,eAClB9B,KAAKiF,MAAMW,eAIfA,oDAIA5F,6BAGKI,OACS,kBAAVA,6CAGMA,+CACAiD,QAAQN,MAASA,IAAIuE,SAAWlH,SAGnD+G,8DAC+B,IAAI3F,UAAUxB,yDAChBuH,4BAAQvH,aAGrCwH,aAAcC,KAAMC,SACU,OAAxB/F,qCAAc+F,aACT/F,qCAAc+F,SAGnB1H,gBAAgB8B,QAAS,IACvB9B,KAAKiF,OAAwB,OAAfjF,KAAKiF,OAAuC,OAArBjF,KAAKiF,MAAMwC,aAC3CzH,KAAKiF,MAAMwC,SAGA,OAAhBzH,KAAK8E,cACA9E,KAAK8E,OAAO2C,aAIhB,+BAIAzH,KAAKwH,aAAa,kBAAmB,wCAIrCxH,KAAKwH,aAAa,kBAAmB,+CAIrCxH,KAAKwH,aAAa,yBAA0B,gDAI5CxH,KAAKwH,aAAa,mBAAoB,+BAInB,OAAtB7F,yCACkC,yCAAtB3B,yCAAmCA,wBAAAA,4BAAsBA,mBAGlE2B,kDAA2BwB,gBAGzB/C,OACY,iBAAVA,OAA8C,IAAxBA,MAAMyB,OAAOnB,SAC5CN,MAAQ,8CAGUA,YAEf+G,qDAIDnH,kBACiC,yCAArBA,wCAAkCA,uBAAAA,KAAiBA,4BAAQA,kBAGtEA,KAAKsH,SAIH3F,kDAA2ByD,KAHzB,YAMDhF,OACa,iBAAVA,OAA8C,IAAxBA,MAAMyB,OAAOnB,SAC5CN,MAAQ,6CAGSA,YAEd+G,gCAIa/G,UACG,mBAAVA,YAKH,IAAIiF,MAAO,2DAA0DjF,uDAJpDA,4DACS,2CACfiD,QAAQN,MAASA,IAAI4E,iBAAmBvH,0DAOpDJ,iFAKAA,gDAID6F,SAAW,UAEjBxE,MAAMC,KAAKK,wCAAiBmB,UAAUO,QAAQN,YACtCtB,KAAOsB,IAAItB,KACXmB,KAAOnB,KAAKmB,YACXnB,KAAKmB,KACZiD,SAASjD,MAAQnB,OAGZoE,uDAIA7F,8DAIAA,2DAIAA,0CAID4H,KAAO,IAAIrD,gBACZsB,SAASxC,QAAQN,MACpB6E,KAAK9B,IAAI/C,IAAIH,MACbG,IAAI8E,YAAYxE,QAAQyE,QAAUF,KAAK9B,IAAK,GAAE/C,IAAIH,QAAQkF,aAGrDzG,MAAMC,KAAKsG,MAAMG,OAG1BC,WAAYpF,KAAO,UACZA,YACI,WAGHqF,MAAQrF,KAAK4C,MAAM,YACrBzC,IAAMpB,sCAAe4E,IAAI0B,MAAMC,YAC/BnF,IAAK,CACPA,IAAMpB,wCAAiB4E,IAAIxD,SACtB,MAAMoF,MAAMF,MACflF,IAAMA,IAAIiF,WAAWG,WAIlBpF,eAAejB,QAAUiB,IAAM,KAGxCqF,aACO,MAAMrF,OAAOxB,aACG,iBAARwB,8CACQsF,OAAOtF,2CACTM,QAAQiF,KAAOA,MAAQvF,KAAOpB,sCAAe0G,OAAOC,OAGlD,iBAARvF,IAAkB,OACrBwF,IAAM5G,sCAAe4E,IAAIxD,KAC3BwF,UACGH,OAAOG,MAMpB5H,UACO,MAAM8E,OAAOlE,UAAW,IACR,mBAARkE,UACH,IAAIJ,MAAO,mDAAkDI,IAAI3E,WAAW0H,UAAU,EAAG,OAAO/C,IAAI3E,WAAWJ,OAAS,GAAK,MAAQ,8CAG5HC,IAAI8E,6CAGNpC,QAAQoF,QAAUA,OAAO9H,OAAOY,YAGnD0F,8CACkBtF,sCAAiB,IAAI/B,gBAEhC,MAAM6F,OAAOlE,UAAW,IACR,mBAARkE,UACH,IAAIJ,MAAO,uDAAsDI,IAAI3E,WAAW0H,UAAU,EAAG,OAAO/C,IAAI3E,WAAWJ,OAAS,GAAK,MAAQ,2CAGnIC,IAAI8E,6CAGHpC,QAAQoF,QAAUA,OAAOxB,WAAW1F,YAGvDuE,UACO,IAAI4C,WAAWnH,UAAW,MACvBmH,mBAAmB5G,SAAU,IACV,iBAAZ4G,cAGH,IAAIrD,MAAM,6EAFhBqD,QAAU,IAAI5G,QAAQ4G,SAM1BA,QAAQpB,SAAWtH,KAAKsH,SAEpBtH,gBAAgB2C,MAClB+F,QAAQzD,MAAQjF,KACPA,gBAAgB8B,UACzB4G,QAAQ5D,OAAS9E,8CAGF0G,IAAIgC,QAAQH,IAAKG,+CACnBhC,IAAIgC,QAAQ9F,KAAM8F,QAAQH,KAEzCG,QAAQ3G,QAAQsB,QAAQG,OAAS7B,sCAAe+E,IAAIlD,MAAOkF,QAAQH,QCpfzE,MACMI,aAAe,2IACfC,eAAiB,yBACjBC,oBAAsB,0DACtBC,gBAAkB,uBACNhJ,OAAOiJ,OAAO,CAC9BC,mBANyB,kCAOzBL,aAAAA,aACAC,eAAAA,eACAC,oBAAAA,oBACAC,gBAAAA,0LCRa,MAAMnG,cAAc2B,KAiBjCzE,YAAayD,IAAM,CAAE2F,WAAY,YACzB3F,mDAjBY,IAAIkB,2CACb,6IAGD,wFAEC0E,WAAWvF,eAAe,UACjC,UAEAuF,WAAWvF,eAAe,YAC1BuF,WAAWC,QAAQC,SACnBF,WAAWC,QAAQC,QAAQxG,KACvBsG,WAAWC,QAAQC,QAAQxG,KAC3B,iBAMDsE,0BAA0B5D,UAE1BsD,cAAgBtD,IAAI8C,aAAe,GAEpC9C,IAAIK,eAAe,QAAUtC,MAAMqE,QAAQpC,IAAI3C,MACjD2C,IAAI3C,IAAI0C,QAAQyD,MAAQ9G,KAAK6G,qBAAqBC,OAGhDxD,IAAIK,eAAe,YAActC,MAAMqE,QAAQpC,IAAI2D,UACrD3D,IAAI2D,QAAQ5D,QAAQyD,MAAQ9G,KAAKgH,kBAAkBF,2CAGrCxD,IAAI+F,SAAW,qDACP/F,IAAI2F,YAAc3F,IAAIgG,iBAAmB,0CAChDhG,IAAIK,eAAe,YAAcL,IAAIiG,SAAW,GAGjEL,WAAWM,OAAO,uBAAyBxJ,sBAIrC6F,SAAW4D,MAAMhI,WAEhB,CACLmB,KAAM5C,KAAK4C,KACXhB,YAAa5B,KAAK4B,YAClByH,QAASrJ,KAAKqJ,QACdxD,SAAAA,SACAlF,IAAKX,KAAKiG,WAAWxE,KACrBwF,QAASjH,KAAK0J,SAASjI,KACvB2D,KAAMpF,KAAKoF,KACXjC,MAAOnD,KAAKmD,MACZ6B,eAAgBhF,KAAKgF,eAAelE,WACpCwE,aAActF,KAAKsH,SACnBqC,8BAAS3J,eACTsJ,sCAAiBtJ,6CAKZ2B,sCAAiB,yBAGVvB,YACTqG,QAAUrG,8BAIRJ,KAAKyG,QAGdmD,QAASC,MAAQ,aACc,IAAzBlI,qCAAcjB,OACT,GAGQ,OAAVmJ,MAAiBlI,qCAAcmI,QAAUnI,qCAAcmI,MAAM,EAAGD,OAGzEE,aAAcF,MAAQ,UACS,IAAzBlI,qCAAcjB,OACT,KAGLmJ,MAAQ,EACH7J,KAAKgK,YAAYC,KAAKC,IAAIL,SAGnCA,OAAgBlI,qCAAcjB,8EAEdmJ,OAEZlI,qCAAgBA,qCAAcjB,2CACjBiB,qCAAcjB,OAAS,GAGjCiB,2DAAc3B,eAAcmK,OAGrCH,YAAaH,MAAQ,UACU,IAAzBlI,qCAAcjB,OACT,KAGLmJ,MAAQ,EACH7J,KAAK+J,aAAaE,KAAKC,IAAIL,SAGpCA,OAAgBlI,qCAAcjB,8EAEdmJ,OACZlI,oCAAe,0CACF,GAIVA,2DAAc3B,eAAcmK,OAGrCC,QAASvE,aACHtE,UAAUb,OAAS,QACf,IAAI2E,MAAM,0EAGlBQ,SAA+B,iBAAbA,SAAwBA,SAASL,MAAM,OAASK,UAE7DxE,MAAMqE,QAAQG,WAAaA,SAASwE,OAAOC,GAAkB,iBAANA,GAAgB5J,OAAS,QAC7E,IAAI2E,MAAO,uFAAsFQ,gBAGnG0E,IAAMlJ,MAAMC,KAAKC,WAAWuI,MAAM,GAExCjE,SAASxC,QAAQN,KAAOpB,8CAAuB+E,IAAI3D,IAAIlB,QAASF,8CAAuB4E,IAAIxD,IAAIlB,SAAW,IAAImB,OAAOuH,OAGvHC,UAAW3E,aACLtE,UAAUb,OAAS,QACf,IAAI2E,MAAM,4EAGlBQ,SAA+B,iBAAbA,SAAwBA,SAASL,MAAM,OAASK,UAE7DxE,MAAMqE,QAAQG,WAAaA,SAASwE,OAAOC,GAAkB,iBAANA,GAAgB5J,OAAS,QAC7E,IAAI2E,MAAO,yFAAwFQ,gBAGrG0E,IAAMlJ,MAAMC,KAAKC,WAAWuI,MAAM,GAClCW,IAAM,IAAIlG,IAAIvE,KAAK6H,YAAYxF,IAAIC,GAAKA,EAAEoI,gBAEhD7E,SAASxC,QAAQN,MACf0H,IAAIpC,OAAOtF,SACN,MAAMuH,KAAKG,IACS,IAAnBH,EAAEvJ,QAAQgC,MACZ0H,IAAIpC,OAAOiC,UAKZF,QAAQ/I,MAAMC,KAAKmJ,QAASF,gBAGvBJ,MAAOQ,UAGbtJ,MAAMqE,QAAQyE,SAChBA,MAAQA,MAAM9H,IAAIC,GACZA,EAAEvB,QAAQ,MAAQ,IAAM,oBAAoB6J,KAAKtI,GAC3C,IAAGA,KAEJA,GAERJ,KAAK,2CAGIkC,QAAQ,CAAE+F,MAAAA,MAAOU,MAAM,IAAIC,MAAOC,mBAE5CpJ,qCAAcjB,6BAASV,6DACXQ,UAGZwK,OAASlC,gBAAgBmC,KAAKd,MAAQ,QAE3B,OAAXa,cACgC,IAA9Bb,MAAMpJ,QAAQ,aAA8C,IAAzBoJ,MAAMpJ,QAAQ,MAC5CmE,QAAQC,IAAInF,KAAKqJ,UACY,IAA3Bc,MAAMpJ,QAAQ,QAChBmE,QAAQC,IAAInF,KAAKoF,MAGnBtD,QAAQoJ,OAAOlL,KAAKoF,MAG7B4F,OAASA,OAAOX,OAAOc,WAAiBC,IAATD,YAEzBpI,IAAMiI,OAAO,GACbzK,KAAOyK,OAAOtK,OAAS,EAAIsK,OAAO,GAAK,GAGvCK,OAASrL,KAAKwG,WAAWD,IAAIxD,SAE9BsI,aACuB,YAAtBtI,IAAI2H,cACCxF,QAAQC,IAAInF,KAAKqJ,SAGnBvH,QAAQoJ,OAAOlL,KAAKoF,YAGvBkG,UAAYtL,KAAKuC,aAAagE,IAAI8E,YAEnCC,iBACIxJ,QAAQoJ,OAAO,4BAGlBK,KAAOD,UAAUE,mBAAmBjL,mBAC7BuB,QAAQ2J,YAAYF,KAAK7C,QAAQtH,IAAImK,KAAKhK,UAAWoJ,WAGpEe,qBAAsB3I,WACd4I,QAAU,UAChB5I,IAAIyC,MAAM,OAAOnC,QAAQ,CAACiH,EAAGhI,EAAGmB,WACxBmI,EAAIjK,8CAAuB4E,IAAI9C,EAAEqG,MAAM,EAAGxH,EAAI,GAAGJ,KAAK,MAC5D0J,GAAKD,QAAQ3K,KAAK4K,EAAEC,KAAKC,EAAAA,MAGpBH,QAAQE,KAAKC,EAAAA,GAGtBC,mDACkB,IAIlBC,4CACkB,IAChB9G,QAAQ8G,uJCzOG,MAAMlK,gBAAgBwC,KASnCzE,YAAayD,IAAM,OACbA,IAAIK,eAAe,aACM,iBAAhBL,IAAI2I,UACb3I,IAAI2I,QAAUlF,SAAS,WAAazD,IAAI2I,QAAQxJ,QAAQ,qBAAsB,YAAc,gBAAgByJ,KAAKhD,aAGxF,mBAAhB5F,IAAI2I,eACP,IAAI5G,MAAM,6EAId/B,kIAjBG,IAAIiB,uFAED,yCACJ,0CACD,OAeHjB,IAAIK,eAAe,QAAUtC,MAAMqE,QAAQpC,IAAI3C,MACjD2C,IAAI3C,IAAI0C,QAAQyD,MAAQ9G,KAAK6G,qBAAqBC,OAGhDxD,IAAIK,eAAe,YAActC,MAAMqE,QAAQpC,IAAI2D,UACrD3D,IAAI2D,QAAQ5D,QAAQyD,MAAQ9G,KAAKgH,kBAAkBF,YAGhDI,0BAA0B5D,oCAEpBA,IAAI2I,yCACHzC,OAASlG,IAAIV,MAAQU,IAAIH,OAAUG,IAAI6I,SAAY,gDAC/C7I,IAAI6I,SAAW,YAE3B7I,IAAIE,QAAUF,IAAIvB,UACpBuB,IAAIvB,QAA+B,iBAAduB,IAAIE,MAAqB,CAACF,IAAIE,OAAUnC,MAAMqE,QAAQpC,IAAIE,OAASF,IAAIE,MAAQnC,MAAMC,KAAKgC,IAAIE,cAC5GF,IAAIE,OAGTF,IAAIvB,QAAS,KACVV,MAAMqE,QAAQpC,IAAIvB,eACf,IAAIsD,MAAM,iFAGF,IAAId,IAAIjB,IAAIvB,aAG1BuB,IAAIF,MAAO,IACY,iBAAdE,IAAIF,YACP,IAAIiC,MAAO,oEAAmE/B,IAAIF,eAGrF,MAAO2C,IAAK3F,SAAUN,OAAOsM,QAAQ9I,IAAIF,UACxChD,MAAMuD,eAAe,SAAU,IACjCvD,MAAM2B,QAAU3B,MAAM2B,SAAW,GAE7BV,MAAMqE,QAAQtF,MAAMoD,WACtBpD,MAAM2B,QAAUV,MAAMC,KAAK,IAAIiD,OAAOnE,MAAM2B,WAAY3B,MAAMoD,QAC1DpD,MAAM2B,QAAQsI,OAAO5G,GAAkB,iBAANA,GAAkB,QAC/C,IAAI4B,MAAO,GAAEU,sDAAsD3F,MAAM2B,QAAQsI,OAAO5G,GAAkB,iBAANA,GAAgBvB,KAAK,cAE5H,CAAA,GAA2B,iBAAhB9B,MAAMoD,YAGhB,IAAI6B,MAAO,uCAAsCjF,MAAMoD,UAAUuC,cAFvE3F,MAAM2B,QAAQf,KAAKZ,MAAMoD,cAKpBpD,MAAMoD,6CAIEF,IAAIF,OAGrB/B,MAAMqE,QAAQpC,IAAIe,mBACfyB,OAAOxC,IAAIe,mBAGZgI,WAAa,IAAI9H,IAAI,CACzB,WACA,cACA,UACA,iBACA,cACA,kBACA,kBACA,yBACA,mBACA,QACA,QACA,UACA,cACA,OACA,QACA,UACA,OACA,UACA,aACA,MACA,YACA,aACA,cACA,UACA,MACA,YAGI+H,aAAexM,OAAOyM,KAAKjJ,KAAK+G,OAAOmC,YAAcH,WAAWI,IAAID,eAEtEF,aAAa5L,OAAS,QAClB,IAAI2E,MAAO,4CAA2CiH,aAAapK,KAAK,aAG1EwK,YAAcrG,iBACdA,YAAYsG,SAAWtL,MAAMqE,QAAQW,YAAYsG,SAAyC,iBAAvBtG,YAAYsG,QAAsB,OACjGA,OAAS,IAAIpI,IAAIlD,MAAMqE,QAAQW,YAAYsG,QAAUtG,YAAYsG,OAAS,CAACtG,YAAYsG,SAEvFC,KAAO5M,KAAKiC,YAAYQ,QAAQ,IAAIoK,OAAQ,IAAG7M,KAAKiF,MAAMrC,WAAY,KAAM,QAE7E,MAAMG,OAAO4J,UACZC,KAAKE,WAAW/J,KAAM,CACxBsD,YAAc,iBAMbA,aAGTvG,OAAOC,iBAAiBC,KAAM,CAC5B+M,cAAe,CACb7M,YAAY,EACZqG,UACMnD,MAAQsJ,YAAY1M,KAAK4G,eAET,OAAhB5G,KAAK8E,SACP1B,MAAQtD,OAAOkN,OAAO5J,MAAOpD,KAAK8E,OAAOiI,sBAGrC9J,OAASnD,OAAOkN,OAAO,GAAmB,OAAfhN,KAAKiF,MAAiByH,YAAY1M,KAAKiF,MAAM2B,eAAiB,GAAIxD,cAE/F/B,MAAMqE,QAAQzC,OAAO0J,SAAoC,iBAAlB1J,OAAO0J,gBACzC1J,OAAO0J,OAGT1J,SAGXd,aAAc,CACZjC,YAAY,EACZqG,YACQnD,MAAQ,IAAIoB,IAAI1E,OAAOsM,QAAQtM,OAAOkN,OAAOhN,KAAK+M,cAAepL,yCAAoB,aAC3FyB,MAAMiF,OAAO,QACNjF,QAGXoI,mBAAoB,CAClBtL,YAAY,EACZC,cAAc,EACdG,UAAU,EACVF,MAAO+J,cACC5J,KAAO4J,MAAMtI,OAAO2D,MAAM,eAC5BzC,IAAM/C,UAEHO,KAAKG,OAAS,GAAG,OAChB+E,IAAMlF,KAAK,GACXuH,OAAS/E,IAAIiF,WAAWvC,SAC1BqC,aACF/E,IAAM+E,OACNvH,KAAK2H,cAMF,CACLQ,QAAS3F,IACTxB,UAAWhB,KAAK2B,KAAK,eAMxB0E,cAAgBtD,IAAI8C,aAAe,QAEnCK,QAAyB,OAAfzG,KAAKiF,MAAiB,GAAKjF,KAAKiF,MAAMgI,YAAc,QAE9D9F,8BAICtB,SAAW4D,MAAMhI,SAEnBwK,SAAWtK,iCAAY3B,KAAKgF,gBAAgBlE,WAC5C8H,eAAegC,KAAKqB,WACtBA,QAAUA,QAAQxJ,QAAQmG,eAAeqC,KAAKgB,SAAS,GAAI,oBAGvD7I,MAAQtD,OAAOkN,OAAOhN,KAAK+M,cAAepL,yCAAoB,QAE/D,MAAOoE,IAAK3F,SAAUN,OAAOsM,QAAQhJ,OACxChD,MAAM2B,QAAU3B,MAAM2B,SAAW,GAE7B3B,MAAMuD,eAAe,UACnBvD,MAAM2B,QAAQhB,QAAQX,MAAMoD,OAAS,GACvCpD,MAAM2B,QAAQf,KAAKZ,MAAMoD,cAItBpD,MAAMoD,MAIf1D,OAAOyM,KAAKnJ,OAAOC,QAAQT,OAAUQ,MAAMR,MAAQ9C,OAAOkN,OAAOhN,KAAKkN,qBAAqBtK,MAAOQ,MAAMR,eAElGnB,KAAO,CACXmB,KAAM5C,KAAK4C,KACXhB,YAAa5B,KAAK4B,YAClBwD,KAAMpF,KAAKoF,KACXjC,MAAOnD,KAAKmD,MACZpB,QAASV,MAAMC,2BAAKtB,gBACpBoD,MAAAA,MACA6I,QAAAA,QACApG,SAAAA,SACAP,aAActF,KAAKsH,SACnB3G,IAAKX,KAAKiG,WAAWxE,KACrBwF,QAASjH,KAAK0J,SAASjI,UAGpB,MAAOsE,IAAK3F,SAAUN,OAAOsM,QAAQ3K,KAAK2B,cACtChD,MAAMoD,aAGR/B,gBAGGsB,UACNA,eAAejB,eAGX,IAAIuD,MAAO,yBAAwBrF,KAAK4C,yLAF/BG,+CAOV/C,wBAGEiF,WACJA,YACG,IAAII,MAAO,uBAAsBrF,KAAK4C,4CAE1CqC,iBAAiBtC,aAIb,IAAI0C,MAAO,+CAA8CJ,oDAHjDA,YACTwB,QAAyB,OAAfzG,KAAKiF,MAAiB,GAAKA,MAAMgI,oDAO7CjN,mCAQEA,mCAPDA,cACK2B,oCAAasD,MAGf,0BAOFnF,OAAOkN,OAAO,GAAIhN,KAAKiF,MAAMqB,QAAStG,KAAK8E,OAAS9E,KAAK8E,OAAOwB,QAAU,GAAImD,MAAMnD,wDAIvFtG,cACM,GAAE2B,oCAAaM,eAAejC,KAAK4C,OAAOf,6BAGhD7B,aACM,GAAE2B,mCAAYiB,QAAQ5C,KAAK4C,OAAOf,OAGrC7B,KAAK4C,iBAGDxC,UACNA,UAKgB,iBAAVA,aACDA,MAAMP,YAAY+C,KAAK8H,mBACxB,MACHtK,MAAQiB,MAAMC,KAAKlB,MAAMmM,kBAEtB,MACHnM,MAAQiB,MAAMC,KAAKlB,iBAEhB,SACHA,MAAQN,OAAOyM,KAAKnM,OAAOiK,OAAOc,MAAwB,iBAATA,gBAE9C,kBAEA,SACH/K,MAAQA,MAAMoF,MAAM,OAAO,uBAGrB,IAAIH,MAAM,qFAINhE,MAAMC,KAAK,IAAIiD,IAAInE,kDAzBjB,yBA6BXiB,MAAMC,2BAAKtB,iBAAkB,0CAI7BA,WAGTmN,QAASvK,KAAMU,QACO,iBAATV,KAAmB,KACvBU,IAAIK,eAAe,cAChB,IAAI0B,MAAM,2CAEhBzC,KAAOU,IAAIV,6CAIEA,MAAQU,IAG3B8J,WAAYxK,aACHjB,wCAAiBiB,MAG1BsK,qBAAsBtK,UAChBW,KAAOvD,KAAKmC,aAAaoE,IAAI3D,UAC5BW,KAAM,KACJ,MAAO8J,EAAG/J,OAAQtD,KAAKmC,gBACrBmB,IAAIvB,SAAWuB,IAAIvB,QAAQhB,QAAQ6B,OAAS,GAAOU,IAAIE,OAASF,IAAIE,QAAUD,KAAO,CACxFA,KAAOD,cAKNC,YACI,WAIJ,CACL3B,YAAa2B,KAAK3B,YAClBsC,WAAUX,KAAKI,eAAe,aAAcJ,KAAKW,SACjDnC,QAASwB,KAAKxB,SAAW,CAACwB,KAAKC,OAAO6G,OAAO/H,GAAW,OAANA,GAClDgL,UAAoBlC,IAAd7H,KAAK+J,KAAqB,SAAiC,iBAAd/J,KAAK+J,KAAoB/J,KAAK+J,KAAO/J,KAAK+J,KAAK1K,KAAK8H,cACvG7G,QAASN,KAAKI,eAAe,WAAaJ,KAAKM,QAAU,KACzDC,sBAAqBP,KAAKI,eAAe,wBAAyBJ,KAAKO,qBAI3EyJ,aAAc3K,aACLjB,wCAAiBgC,eAAef,MAGzC4K,UAAWrD,aACHtF,KAAO7E,KAAKyN,MAAMtD,UAEK,IAAzBnK,KAAKwG,WAAWpE,YACXyC,QAGwB,IAA7BA,KAAKsF,MAAMtI,OAAOnB,cACbmE,WAGHtE,KAAOsE,KAAKsF,MAAM3E,MAAM,OACxBsC,OAAS9H,KAAKwG,WAAWD,IAAIhG,KAAK2H,gBAEnCJ,OAIE9H,KAAKuC,aAAagE,IAAIuB,QAAQ0F,UAAUjN,KAAK2B,KAAK,MAHhD2C,KAMX4I,MAAOtD,aAEC1I,KAAO,CAAEiH,QAAS1I,KAAK4C,KAAMuH,MAAOA,MAAMtI,QAC1C6L,WAAa5N,OAAOkN,OAAOhN,KAAK+M,cAAepL,yCAAoB,IAEpE+L,WAAW/J,eAAe,UAC7B+J,WAAWtI,KAAO,CAChBxD,YAAc,WAAU5B,KAAK4C,aAE7BqB,SAAS,EACTqJ,KAAM,kBAIJlK,MAAQ/B,MAAMC,KAAKqH,aAAaa,OAAOmE,UAAUxD,OAAQyD,GAAKA,EAAE,IAChEC,OAAS,IAAIC,OAAO1K,MAAOsK,YAC3BK,MAAQF,OAAOpM,KACfuM,WAAa,MAEnBH,OAAOI,gBAAgB5K,QAAQE,OAAUyK,WAAWzK,MAAQwK,MAAMxK,QAClEsK,OAAOK,kBAAkB7K,QAAQoC,YAAcuI,WAAWvI,MAE1DhE,KAAK2B,MAAQ,CAAE4K,WAAAA,WAAY1B,aAAcuB,OAAOK,mBAChDzM,KAAK0M,MAAQN,OAAOM,MACpB1M,KAAK2M,WAAaP,OAAOO,WAEzB3M,KAAKuJ,OAAS,GACVlL,OAAOyM,KAAKwB,MAAMM,YAAY3N,OAAS,MACpC,MAAOqF,IAAKuI,OAAQxO,OAAOsM,QAAQ2B,MAAMM,YAC5C5M,KAAKuJ,OAAOsD,IAAI1L,MAAQ0L,IAAIC,UAIhC9M,KAAK2D,KAAO,CACVoJ,UAAWR,WAAW5I,MAGpB4I,WAAW5I,OACb3D,KAAK2D,KAAKqJ,QAAUzO,KAAKoF,YAGrB7E,KAAOc,MAAMC,KAAKtB,KAAKuB,kBAE7BzB,OAAOC,iBAAiB0B,KAAM,CAC5B8B,KAAM,CACJrD,YAAY,EACZC,cAAc,EACdG,UAAU,EACVF,MAAOwC,iBAEiB,iBAATA,KACFvB,MAAMC,KAAKuM,OAAOK,mBAAmBtL,MAExCnB,KAAK2B,MAAM4K,WAAWrK,eAAeoK,MAAMM,WAAWzL,MAAMA,MACvDnB,KAAK2B,MAAM4K,WAAWD,MAAMM,WAAWzL,MAAMA,MAE7CmL,MAAMM,WAAWzL,MAAMxC,MAGlC,MAAOsO,UACH1O,KAAKuB,UAAUkL,IAAI7J,MACdvB,MAAMC,KAAKuM,OAAOK,mBAAmB3N,KAAKQ,QAAQ6B,iBAOjE8F,QAAS,CACPxI,YAAY,EACZqG,IAAK,IAAMvG,MAEbiF,MAAO,CACL/E,YAAY,EACZqG,IAAK,IAAMvG,KAAKiF,OAElBxD,KAAM,CACJvB,YAAY,EACZqG,YACQoI,GAAKd,OAAOK,kBACZjL,OAASnD,OAAOkN,OAAO,GAAIgB,0BAC1B/K,OAAOmC,KAEd7E,KAAK8C,QAAQ,CAACT,KAAMN,WACZlC,MAAQuO,GAAGrM,OACbsM,gBAAkB9O,OAAOyM,KAAKwB,OAAO1D,OAAOtE,KAAOA,IAAI2E,gBAAkBtK,OAC7EwO,gBAAmBA,gBAAgBlO,OAAS,EAAIkO,gBAAgBpO,MAAQJ,WAEhDgL,IAApBwD,kBACFA,gBAAkBA,gBAAgB/M,OAE9BgH,oBAAoB+B,KAAKgE,mBAC3BA,gBAAkBA,gBAAgBpG,UAAU,EAAGoG,gBAAgBlO,OAAS,KAIxEuC,OAAOU,eAAef,OACxBK,OAAOL,MAAQvB,MAAMqE,QAAQzC,OAAOL,OAASK,OAAOL,MAAQ,CAACK,OAAOL,OACpEK,OAAOL,MAAM5B,KAAK4N,kBAElB3L,OAAOL,MAAQgM,kBAIfD,GAAGjO,OAASH,KAAKG,QACnBiO,GAAG7E,MAAMvJ,KAAKG,QACX2C,QAAQ,CAACE,KAAMjB,SACVM,KAAQ,WAASN,EAAI,QAClBW,OAAOU,eAAef,OAAO,OAC5BiM,OAASjM,KAAK4F,UAAU,GAC9B5F,KAAO,WAAakM,SAASD,QAAU,GAGzC5L,OAAOL,MAAQW,OAIdN,WAKbnD,OAAOiP,eAAetN,KAAK2D,KAAM,UAAW,CAC1ClF,YAAY,EACZqG,IAAK,IAAMvG,KAAKoF,OAGX3D,eAGE0I,MAAOQ,gBACVqE,IAAMrN,iCAAY3B,KAAKgF,gBAAgB7D,KAAKnB,MAC5CyB,KAAwB,iBAAV0I,MAAqBnK,KAAKyN,MAAMtD,OAASA,SAE7D5I,UAAU,GAAKvB,KAAKwN,UAAUrD,OAC9B5I,UAAU,GAAG+E,QAAUtG,KAAKsG,QAET,OAAftG,KAAKiF,MAAgB,OACjBgK,iBAAmBjP,KAAKiF,MAAMyG,qBAAqB1L,KAAKiC,YAAYQ,QAAQ,IAAIoK,OAAQ,IAAG7M,KAAKiF,MAAMrC,KAAQ,KAAM,IAAIf,QAE1HoN,iBAAiBvO,OAAS,QACvBuF,WAAWtF,OAAOsO,wBAIrBvF,SAAW1J,KAAK0J,gBAElBnI,UAAU,GAAG6D,MAAQ7D,UAAU,GAAG6D,KAAKoJ,WACzCtJ,QAAQC,IAAInF,KAAKoF,WAEbsE,SAAStH,KAAO,GAClBsH,SAAStI,IAAIG,UAAU,MAOvBvB,KAAKiG,WAAW7D,KAAO,QACpB6D,WAAW7E,IAAIG,UAAU,GAAI2N,MAAAA,YAAoBpN,QAAQ2J,MAAMuD,GAAGnK,KAAM8F,iBAEzEjB,SAAStH,KAAO,GAClBsH,SAAStI,IAAIG,UAAU,OAO3BE,KAAK6E,QAAUtG,KAAKsG,QACpBxE,QAAQ2J,MAAMuD,GAAGvN,KAAMkJ,gBAEnBjB,SAAStH,KAAO,GAClBsH,SAAStI,IAAIG,UAAU,oBAIZ4N,YACM9J,MACV,IAAI+J,QAAQ,CAACC,QAASC,SAAWA,OAAOH,MAAMI,MAAMrK,QAAQsK,oBAMzD7E,iBACL,IAAIyE,QAAQ,CAACC,QAASC,cAED,mBAAb3E,UACTA,WAGF0E,UACA,MAAOX,GACPY,OAAOZ,aC/kBTjE,IAAM,CAAE9H,MAAAA,MAAOb,QAAAA,QAASN,UAAAA,UAAWgB,MAAAA,MAAO5C,WAAAA"}
\ No newline at end of file
diff --git a/dist/shell-debug/package.json b/dist/shell-debug/package.json
deleted file mode 100644
index ca0a820..0000000
--- a/dist/shell-debug/package.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "name": "@author.io/shell-debug",
- "version": "1.8.18",
- "description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers. (Debug Mappings)",
- "module": "./index.js",
- "exports": {
- "import": "./index.js",
- "default": "./index.js"
- },
- "browser": "./index.js",
- "keywords": [
- "shell",
- "debug",
- "sourcemap"
- ],
- "repository": {
- "type": "git",
- "url": "https://github.com/author/shell"
- },
- "author": {
- "name": "Corey Butler",
- "url": "http://coreybutler.com"
- },
- "license": "MIT",
- "type": "module",
- "files": [
- "*.js"
- ],
- "engines": {
- "node": ">=13.5.0"
- },
- "standard": {
- "parser": "babel-eslint",
- "ignore": [
- "_*",
- "_**/*",
- ".**/*",
- "node_modules",
- "karma.conf.js",
- "karma.conf.cjs",
- "build.js"
- ],
- "globals": [
- "window",
- "global",
- "globalThis"
- ]
- },
- "dependencies": {
- "source-map-support": "^0.5.16"
- }
-}
\ No newline at end of file
diff --git a/dist/shell/LICENSE b/dist/shell/LICENSE
deleted file mode 100644
index 166549b..0000000
--- a/dist/shell/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2020 Author.io
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/dist/shell/README.md b/dist/shell/README.md
deleted file mode 100644
index e9e8d43..0000000
--- a/dist/shell/README.md
+++ /dev/null
@@ -1,972 +0,0 @@
-# @author.io/shell
-
-
-This is a super-lightweight framework for building text-based programs, like [CLI](https://en.wikipedia.org/wiki/Command-line_interface) applications. See the [installation guide](#installation) to jumpstart your CLI.
-
----
-This library is now supported by this [Chrome CLI Devtools Extension](https://chrome.google.com/webstore/detail/cli/okpglddgmnblhbdpdcmodmacgcibgfkf):
-
-
-
-You can see the library in use (in browsers and Node.js) in this [OpenJS World 2020 talk](https://youtu.be/dw7ABwvFtdM) (The Benefits of a "CLI First" Development Strategy).
-
----
-
-## Uses
-
-There are two types of text-based apps:
-
-1. **Single Purpose** (_a_ command)
- These are tools which may have multiple configuration options, but ultimately only do one thing. Examples include [node-tap](https://node-tap.org/), [mocha](https://mochajs.org/), [standard](https://standardjs.com/), prettier, etc.
-
- For example, node-tap can be run on a file, using syntax like `tap [options] []`. Ultimately, this utility serves one purpose. It just runs a configured tap process.
-
-
-1. **Multipurpose** (a shell for _multiple_ commands)
- Other tools do more than configure a script. Consider npm, which has several subcommands (like `install`, `uninstall`, `info`, etc). Subcommands often behave like their own single purpose tool, with their own unique flags, and even subcommands of their own. Docker is a good example of this, which has an entire series of management subcommands.
-
-#### Is this "framework" overkill?
-
-**tl;dr** Use this library to create multipurpose tools. Use [@author.io/arg](https://github.com/author/arg) to create single purpose tools.
-
-
-Detailed Explanation
-
-
-This framework was designed to support multipurpose CLI tools. At the core, it provides a clean, easily-understood, repeatable pattern for building maintainable multipurpose CLI applications.
-
-Multipurpose tools require a layer of organizational overhead to help isolate different commands and features. This overhead is unnecessary in single purpose tools. Single purpose tools just need argument parsing, which the [@author.io/arg](https://github.com/author/arg) does very well.
-
-`@author.io/arg` is embedded in this framework, making `@author.io/shell` _capable_ of creating single purpose tools, but it's merely unnecessary overhead for single purpose commands.
-
-
-
-**Think about how your tooling evolves...**
-
-Sometimes single purpose tools grow into multipurpose tools over time. Tools which start out using the `@author.io/arg` library can be transitioned into multipurpose tools using `@author.io/shell` (with reasonable ease). After all, they use the same code, just nicely separated by purpose.
-
-## Differentiating Features
-
-1. Supports **middleware** (express-style).
-1. Supports **postware** (middleware that runs after a command).
-1. **Customizable **help/usage** screens.
-1. Produces **introspectable** JSON. Load a JSON config, have a working CLI.
-1. Reusable **plugin** system.
-1. Dynamically add/remove commands.
-1. Track command execution **history**.
-1. Define **universal flags** once, reuse in all commands.
-
-
-Also has better source & distribution code
-
-1. Cross-runtime (browser, node, deno)
-1. Separation of Concerns: Arg parsing and text formatting are separate microlibs.
-1. Modern ES Module syntax
-1. 40+ unit tests
-
-
-
-## Basic Examples
-
-See the [Installation Guide](#installation) when you're ready to get started.
-
-There is a complete working example of a CLI app (with a mini tutorial) in the examples directory.
-
-_This example imports the library for Node. Simply swap the Node import for the appropriate browser import if you're building a web utility. Everything else is the same for both Node and browser environments._
-
-```javascript
-import { Shell, Command } from '@author.io/shell'
-
-// Define a command
-const ListCommand = new Command({
- name: 'list',
- description: 'List the contents of the directory.',
- disableHelp: false, // Set to true to turn off default help messages for the entire shell (you can still provide your own). Defaults to false.
- // arguments are listed after the command in the default help screen. Ex: "dir list path"
- arguments: 'path', // Can be space/comma/tab/semicolon delimited or an array.
- alias: 'ls',
- // Any flag parsing options from the @author.io/arg library can be configured here.
- // See https://github.com/author/arg#configuration-methods for a list.
- flags: {
- long: {
- alias: 'l',
- description: 'Long format'.
- type: 'boolean',
- default: false
- },
- rootDir: {
- description: 'The root directory to list.',
- aliases: ['input', 'in', 'src'],
- single: true,
- // validate: RegExp/Function (see github.com/author/arg)
- }
- },
- handler (metadata, callback) {
- // ... this is where your command actually does something ...
-
- // Data comes from @author.io/arg lib. It looks like:
- // {
- // command: ,
- // input: 'whatever user typed after "command"',
- // flags: {
- // recognized: {},
- // unrecognized: [
- // 'whatever',
- // 'user',
- // 'typed'
- // ]
- // },
- // valid: false,
- // violations: [],
- // flag (name) { return String },
- // data (getter)
- // }
- console.log(metadata)
-
- // A single flag's value can be retrieved with this helper method.
- console.log(metadata.flag('long'))
-
- // Any unrecognized flags can be retrieved by index number (0-based)
- console.log(metadata.flag(0)) // The first unrecognized flag... returns null if it doesn't exist
-
- // Execution callbacks are optional. If a callback is passed from the
- // execution context to this handler, it will run after the command
- // has finished processing
- // (kind of like "next" in Express).
- // Promises are also supported.
- callback && callback()
- }
-})
-
-const shell = new Shell({
- name: 'myapp',
- version: '1.0.0',
- description: 'My demo app.',
- // This middleware runs before all command handlers.
- use: [
- (meta, next) => { ...; next() }
- ],
- // Trailers are like "post-middleware" that run after command handlers.
- trailer: [
- (meta, next) => { ...; next() }
- (meta, next) => { console.log('All done!') }
- ],
- commands: [
- // These can be instances of Command...
- list,
-
- // or just the configuration of a Command
- {
- name: 'find',
- description: 'Search metadoc for all the things.',
- alias: 'search',
- flags: {
- x: {
- type: 'string',
- required: true
- }
- },
- handler: (data, cb) => {
- console.log(data)
- console.log(`Mirroring input: ${data.input}`)
-
- cb && cb()
- }
- // Subcommands are supported
- // , commands: [...]
- }
- ]
-})
-
-// Run a command
-shell.exec('find "some query"')
-
-// Run a command using a promise.
-shell.exec('find "some query"').then(() => console.log('Done!))
-
-// Run a command using a callback (the callback is passed to the command's handler function)
-shell.exec('find "some query"', () => console.log('Handled!'))
-
-// Run a command, pass a callback to the handler, and use a promise to determine when everything is done.
-shell.exec('find "some query"', () => console.log('Handled!')).then(() => console.log('Done!))
-
-// Output the shell's default messages
-console.log(shell.help)
-console.log(shell.usage)
-console.log(shell.description)
-```
-
-## Custom Handlers
-
-Each command has a handler function, which is responsible for doing something. This command receives a reference to the parsed flags.
-
-```javascript
-{
- command: ,
- input: 'Raw string of flags/arguments passed to the command',
- flags: {
- recognized: {},
- unrecognized: [
- 'whatever',
- 'user',
- 'typed'
- ]
- },
- flag (name) { return },
- valid: false,
- violations: []
-}
-```
-
-- **command** is the command name.
-- **input** is the string typed in after the command (flags)
-- **flags** contains the parsed flags from the [@author.io/arg](https://github.com/author/arg) library.
-- **`flag()`** is a special method for retrieving the value of any flag (recognized or unrecognized). See below.
-- **valid** indicates whether the input conforms to the parsing rules.
-- **violations** is an array of strings, where each string represents a violation of the parsing rules.
-- **data** _(getter)_ returns a key/value object with all of the known flags, as well as an _attempt_ to map any unrecognized flags with known argument names. (See basic example for argument example)
-
-
-Understanding flag()
-
-
-The `flag()` method is a shortcut to help developers create more maintainable and understandable code. Consider the following example that does **not** use the flag method:
-
-```javascript
-const cmd = new Command({
- name: 'demo',
- flags: {
- a: { type: String },
- b: { type: String }
- },
- handler: metadata => {
- console.log(`A is "${metadata.flags.recognized.a}"`)
- console.log(`B is "${metadata.flags.recognized.b}"`)
- }
-})
-```
-
-Compare the example above to this cleaner version:
-
-```javascript
-const cmd = new Command({
- name: 'demo',
- flags: {
- a: { type: String },
- b: { type: String }
- },
- handler: metadata => {
- console.log(`A is "${metadata.flag('a')}"`) // <-- Here
- console.log(`B is "${metadata.flag('b')}"`) // <-- and here
- }
-})
-```
-
-While the differences aren't extreme, it abstracts the need to know whether a flag is recognized or not (or even exists). If a `flag()` is executed for a non-existant flag, it will return `null`.
-
-
-
-Understanding data
-The `data` attribute supplied to handlers in the metadata argument contains the values for known flags, and _**attempts to map unknown arguments** to configured argument names_.
-
-For example,
-
-```javascript
-const shell = new Shell({
- name: 'account',
- commands: [{
- name: 'create',
- arguments: 'email displayName',
- handler (meta) {
- console.log(meta.data)
- }
- }]
-})
-
-shell.exec('create me@domain.com "John Doe" test1 test2')
-```
-
-_Output:_
-
-```json
-{
- "email": "me@domain.com",
- "displayName": "John Doe",
- "unknown1": "test1",
- "unknown2": "test2
-}
-```
-
-If there is a name conflict, the output will contain an array of values. For example:
-
-```javascript
-const shell = new Shell({
- name: 'account',
- commands: [{
- name: 'create',
- arguments: 'email displayName',
- flags: {
- email: {
- alias: 'e'
- }
- },
- handler (meta) {
- console.log(meta.data)
- }
- }]
-})
-
-shell.exec('create me@domain.com -e bob@other.com')
-```
-
-_Output:_
-
-```json
-{
- "email": ["bob@other.com", "me@domain.com"],
- "displayName": "John Doe",
-}
-```
-
-> Notice the values from the known flags are _first_.
-
-
-## Plugins
-
-Plugins expose functions, objects, and primitives to shell handlers.
-
-_Example:_
-
-Consider an example where information is retrieved from a remote API. To do this, an HTTP request library may be necessary to make the request and parse the results. In this example, the axios library is defined as a plugin. The plugin is accessible in the metadata passed to each handler, as shown below.
-
-
- Why would you do this?
-
- Remember, the shell library can produce JSON (See the Introspection/Metadata Generation section). JSON is a string format for storing data. The output will contain a stringified version of all the handler functions. This can be used as the configuration for another instance of a shell. In other words, you can maintain a runtime-agnostic configuration. You could use _mostly_ the same configuration for the browser, Node, Deno, Vert.x, or another JavaScript runtime. However; the modules/packages like the HTTP request module may or may not work in each runtime.
-
-
- Plugins allow developers to write handlers that are completely "self contained". It is then possible to modify the plugin configuration for each runtime without modifying every handler in the shell.
-
-
-
-
-```javascript
-import axios from 'axios'
-
-const sh = new Shell({
- name: 'info',
- plugins: {
- httprequest: axios // replace this with any compatible library
- },
- commands: [{
- name: 'person',
- flags: {
- name: {
- description: 'Name of the person you want info about.',
- required: true
- }
- },
- handler (meta) {
- meta.plugins.httprequest({
- method: 'get',
- url: `http://api.com/person/${meta.flag('name')}`
- }).then(console.log).catch(console.error)
- }
- }, {
- name: 'group',
- flags: {
- name: {
- description: 'Name of the group you want info about.',
- required: true
- }
- },
- handler (meta) {
- meta.plugins.httprequest({
- method: 'get',
- url: `http://api.com/group/${meta.flag('name')}`
- }).then(console.log).catch(console.error)
- }
- }]
-})
-```
-
-Commands will inherit plugins from the shell and any parent commands. It is possible to "override" a plugin in any specific command.
-
-
-Override Example
-
-```javascript
-const sh = new Shell({
- name: 'test',
- plugins: {
- test: value => {
- return value + 1
- }
- },
- commands: [{
- name: 'cmd',
- plugins: {
- test: value => {
- return value + 10
- }
- },
- handler(meta) {
- console.log(meta.test(1)) // Outputs 11
- }
- }]
-})
-```
-
-
-
-## Universal Flags
-_Common flags are automatically applied to multiple commands._
-
-Sometimes a CLI app has multiple commands/subcommands that need the same flag associated with each command/subcommand. For example, if a `--note` flag were needed on every command, it would be a pain to copy/paste the config into every single command. Common flags resolve this by automatically applying to all commands from the point where the common flag is configured (i.e. the point where inheritance/nesting begins).
-
-
-Apply a common flag to ALL commands
-To include the same flag on all commands, add a common flag to the shell.
-
-```javascript
-const shell = new Shell({
- name: 'mycli',
- commmonflags: {
- note: {
- alias: 'n',
- description: 'Save a note about the operation.'
- }
- },
- commands: [{
- name: 'create',
- flag: {
- writable: {
- alias: 'w',
- description: 'Make it writable.'
- }
- },
- ...
- }, {
- name: 'read',
- ...
- }]
-})
-
-shell.exec('create --help')
-shell.exec('read --help')
-```
-
-create output:
-```sh
-mycli create
-
-Flags:
- note [-n] Save a note about the operation.
- writable [-w] Make it writable.
-```
-
-read` output:
-```sh
-mycli read
-
-Flags:
- note [-n] Save a note about the operation.
-```
-
-
-
-Apply a common flag to a specific command/subcommands
-
-```javascript
-const shell = new Shell({
- name: 'mycli',
- commands: [{
- name: 'create',
- commmonflags: {
- note: {
- alias: 'n',
- description: 'Save a note about the operation.'
- }
- },
- flag: {
- writable: {
- alias: 'w',
- description: 'Make it writable.'
- }
- },
- commands: [...]
- ...
- }, {
- name: 'read',
- description: 'Read a directory.',
- ...
- }]
-})
-
-shell.exec('create --help')
-shell.exec('read --help')
-```
-
-_`create` output:_
-```sh
-mycli create
-
-Flags:
- note [-n] Save a note about the operation.
- writable [-w] Make it writable.
-```
-
-_`read` output:_
-```sh
-mycli read
-
- Read a directory.
-
-```
-
-
-#### Filtering Universal Flags
-
-Universal/common flags accept a special attribute named `ignore`, which will prevent the flags from being applied to specific commands. This should be used sparingly.
-
-
-Cherry-picking example
-
-
-```javascript
-const shell = new Shell({
- name: 'mycli',
- commmonflags: {
- ignore: 'info', // This can also be an array of string. Fully qualified subcommands will also be respected.
- note: {
- alias: 'n',
- description: 'Save a note about the operation.'
- }
- },
- commands: [{
- name: 'create',
- handler () {}
- }, {
- name: 'read',
- handler () {}
- }, {
- name: 'update',
- handler () {}
- }, {
- name: 'delete',
- handler () {}
- }, {
- name: 'info',
- handler () {}
- }]
-})
-```
-
-Any command, except `info`, will accepts/parse the `note` flag.
-
-
-
-## Middleware
-
-When a command is called, it's handler function is executed. Sometimes it is desirable to pre-process one or more commands. The shell middleware feature supports "global" middleware and "assigned" middleware.
-
-### Global Middleware
-
-This middleware is applied to all handlers, unilaterally. It is useful for catching syntax errors in commands, preprocessing data, and anything else you may want to do before the actual handler is executed.
-
-For example, the following middleware checks the input to determine if all of the appropriate flags have been set. If not, the violations are displayed and the handler is never run. If everything is correct, the `next()` method will continue processing.
-
-```javascript
-shell.use(function (metadata, next) {
- if (!metadata.valid) {
- metadata.violations.forEach(violation => console.log(violation))
- } else {
- next()
- }
-})
-```
-
-No matter which command the user inputs, the global middleware methods are executed.
-
-### Assigned Middleware
-
-This middleware is assigned to one or more commands. For example:
-
-```javascript
-shell.useWith('demo', function (metadata, next) {
- if (metadata.flag('a') === null) {
- console.log('No "a" flag specified. This may slow down processing.')
- }
-
- next()
-})
-```
-
-The code above would only run when the user inputs the `demo` command (or any `demo` subcommand).
-
-#### Command-Specific Assignments
-
-It is possible to assign middleware to more than one command at a time, and it is possible to target subcommands. For example:
-
-```javascript
-shell.useWith(['demo', 'command subcommand'], function (metadata, next) {
- if (metadata.flag('a') === null) {
- console.log('I hope you know what you are doing!')
- }
-
- next()
-})
-```
-
-Notice the array as the first argument of the `useWith` method. This middleware would be assigned to `demo` command, all `demo` subcommands, the `subcommand` of `command`, and all subcommands of `subcommand`. If this sounds confusing, just know that middleware is applied to commands, including nested commands.
-
-Assigned middleware can also be applied directly to a `Command` class. For example,
-
-```javascript
-const cmd = new Command({
- name: 'demo',
- flags: {
- a: { type: String },
- b: { type: String }
- },
- handler: metadata => {
- console.log(metadata)
- }
-})
-
-cmd.use(function (metadata, next) {
- console.log(`this middleware is specific to the "${cmd.name}" command`)
- next()
-})
-```
-
-#### Command-Exclusion Assignments
-
-Sometimes middleware needs to be applied to all but a few commands. The `useExcept` method supports these needs. It is basically the opposite of `useWith`. Middleware is applied to all commands/subcommands _except_ those specified.
-
-For example:
-
-```javascript
-const shell = new Shell({
- ...,
- commands: [{
- name: 'add',
- handler (meta) {
- ...
- }
- }, {
- name: 'subtract',
- handler (meta) {
- ...
- }
- }, {
- name: 'info',
- handler (meta) {
- ...
- }
- }]
-})
-
-shell.useExcept(['info], function (meta, next) {
- console.log(`this middleware is only applied to some math commands`)
- next()
-})
-```
-
-In this example, the console statement would be displayed for all commands except the `info` command (and any info subcommands).
-
-### Built-in "Middleware"
-
-Displaying help and version information is built-in (overridable).
-
-**Help**
-
-Appending `--help` to anything will display the help content for the shell/command/subcommand. This will respect any custom usage/help configurations that may be defined.
-
-**Shell Version**
-
-A `version` command is available on the shell. For example:
-
-```sh
-$ cmd version
-1.0.0
-```
-
-The following common flag variations map to the version command, producing the same output:
-
-```sh
-$ cmd --version
-1.0.0
-
-$ cmd -v
-1.0.0
-```
-
-This can be overridden by creating a command called `version`, the same way any other command is created.
-
-```javascript
-const v = new Command({
- name: 'version',
- handler (meta) {
- console.log(this.shell.version)
- }
-})
-
-shell.add(v)
-```
-
-### Middleware Libraries
-
-One development goal of this framework is to remain as lightweight and unopinionated as possible. Another is to be as simple to use as possible. These two goals often conflict with each other (the more features you add, the heavier it becomes). In an attempt to find a comfortable balance, some additional middleware libraries are available for those who want a little extra functionality.
-
-1. [@author.io/shell-middleware](https://github.com/author/shell-middleware)
-1. Submit a PR to add yours here.
-
-### Trailers
-_(Postware/Afterware)_
-
-Trailers operate just like middleware, but they execute _after_ the command handler is executed.
-
-```javascript
-const shell = new Shell({
- name: 'mycli',
- trailer: [
- function () { console.log('Done!' ) }
- ],
- command: [{
- name: 'dir',
- handler () {
- console.log('ls -l')
- },
- // Subcommands
- commands: [{
- name: 'perm',
- description: 'Permissions',
- handler () {
- console.log('Display permissions for a directory.')
- }
- }]
- }]
-})
-
-// Execute the "dir" command
-shell.exec('dir')
-
-// Execute the "perm" subcommand
-shell.exec('dir perm')
-```
-
-_`dir` command output:_
-```sh
-ls -l
-Done!
-```
-
-_`dir perm` subcommand output:_
-```sh
-Display permissions for a directory.
-Done!
-```
-
-### Customized Help/Usage Messages
-
-**Customizing Flag Appearance:**
-
-The `Shell` and `Command` classes can both accept several boolean attributes to customize the description of each flag within a command. Each of these is `true` by default.
-
-1. `describeDefault`: Display the default flag value.
-1. `describeOptions`: List the valid options for a flag.
-1. `describeMultipleValues`: Appends `Can be used multiple times.` to the flag description
-1. `describeRequired`: Prepends `Required.` to the flag description whenever a flag is required.
-
-
-Example
-
-
-```javascript
-const c = new Command({
- name: '...',
- flags: {
- name: {
- alias: 'nm',
- required: true,
- default: 'Rad Dev',
- allowMultipleValues: true,
- options: ['Mr Awesome', 'Mrs Awesome', 'Rad Dev'],
- description: 'Specify a name.'
- }
- }
-})
-```
-
-The help message for this flag would look like:
-
-```sh
-Flags:
- -name ['nm'] Required. Specify a name. Options: Mr
- Awesome, Mrs Awesome, Rad Dev. Can be
- used multiple times. (Default Rad Dev)
-```
-
-
-
-**Customizing the Entire Message:**
-
-This library uses a vanilla dependency (i.e. no-subdependencies) called [@author.io/table](https://github.com/author/table) to format the usage and help messages of the shell. The `Table` library can be used to create your own custom screens, though most users will likely want to stick with the defaults. If you want to customize messages, the following example can be used as a starting point. The configuration options for the table can be found in the README of its repository.
-
-```javascript
-import { Shell, Command, Table } from '@author.io/shell'
-
-const shell = new Shell(...)
-shell.usage = '...'
-shell.help = () => {
- const rows = [
- ['Command', 'Alias Names'],
- ['...', '...']
- ]
-
- const table = new Table(rows)
-
- return shell.usage + '\n' + table.output
-}
-```
-
-**The `usage` and/or `help` attributes of an individual `Command` can also be set:**
-
-```javascript
-import { Shell, Command, Table } from '@author.io/shell'
-
-const cmd = new Command(...)
-cmd.usage = '...'
-cmd.help = () => {
- const rows = [
- ['Flags', 'Alias Names'],
- ['...', '...']
- ]
-
- const table = new Table(rows)
-
- return cmd.usage + '\n' + table.output
-}
-```
-
-There is also a `Formatter` class that helps combine usage/help messages internally. This class is exposed for those who want to dig into the inner workings, but it should be considered as more of an example than a supported feature. Since it is an internal class, it may change without warning (though we'll try to keep the methods consistent across releases).
-
-### Introspection/Metadata Generation
-
-A JSON metadoc can be produced from the shell:
-
-```javascript
-console.log(shell.data)
-```
-
-Simple CLI utilities can also be loaded entirely from a JSON file by passing the object into the shell constructor as the only argument. The limitation is no imports or hoisted variables/methods will be recognized in a shell which is loaded this way.
-
-### Autocompletion/Input Hints
-
-This library can use a _command hinting_ feature, i.e. a shell `hint()` method to return suggestions/hints about a partial command. This feature was part of the library through the `v1.5.x` release lifecycle. In `v.1.6.0+`, this feature is no longer a part of the core library. It is now available as the [author/shell-hints plugin](https://github.com/author/shell-hints).
-
-Consider the following shell:
-
-```javascript
-import HintPlugin from 'https://cdn.pika.dev/@author.io/browser-shell-hints'
-
-const shell = new Shell({
- name: 'mycli',
- command: [{
- name: 'dir',
- handler () {
- console.log('ls -l')
- },
- // Subcommands
- commands: [{
- name: 'perm',
- description: 'Permissions',
- handler () {
- console.log('Display permissions for a directory.')
- }
- }, {
- name: 'payload',
- description: 'Payload',
- handler () {
- console.log('Display payload/footprint for a directory.')
- }
- }]
- }]
-})
-
-HintPlugin.apply(shell) // <-- Adds the hint method.
-
-// Help us figure out what we can do!
-console.log(shell.hint('dir p'))
-```
-
-_Output:_
-
-```sh
-{
- commands: ['perm', 'payload'],
- flags: []
-}
-```
-
-The hint matches "**dir p**ermission" and "**dir p**ayload", but does not match any flags.
-
-If no options/hints are available, `null` is returned.
-
-While this add-on provides input hints that could be used for suggestions/completions, it does **not** generate autocompletion files for shells like bash, zsh, fish, powershell, etc.
-
-> There are many variations of autocompletion for different shells, which are not available in browsers (see our Devtools extension for browser completion).
-
-If you wish to generate your own autocompletion capabilities, use the `shell.data` attribute to retrieve data for the shell (see prior section). For terminals, consider using the shell metadata with a module like [omlette](https://github.com/f/omelette) to produce autocompletion for your favorite terminal app. For browser-based CLI apps, consider using our devtools extension for an autocompletion experience.
-
-## Installation
-
-### Node.js
-
-
-Modern (ES Modules)
-
-
-```sh
-npm install @author.io/shell --save
-```
-
-Please note, you'll need a verison of Node that supports ES Modules. In Node 12, this feature is behind the `--experimental-modules` flag. It is available in Node 13+ without a flag, but the `package.json` file must have the `"type": "module"` attribute. This feature is generally available in [Node 14.0.0](https://nodejs.org) and above.
-
-
-
-Legacy (CommonJS/require)
-
-
-DEPRECATED
-
-If you need to use the older CommonJS format (i.e. `require`), run `npm install @author.io/shell-legacy` instead.
-
-
-### Browsers
-
-**CDN**
-
-```javascript
-import { Shell, Command } from 'https://cdn.pika.dev/@author.io/shell'
-```
-
-Also available from [jsdelivr](https://www.jsdelivr.com/package/npm/@author.io/shell/index.js) and [unpkg](https://unpkg.com/@author.io/shell/index.js).
-
-### Debugging
-
-Each distribution has a corresponding `-debug` version that should be installed _alongside_ the main module (the debugging is an add-on module). For example, `npm install @author.io/shell-debug --save-dev` would install the debugging code for Node. In the browser, appending the debug library adds sourcemaps.
-
-### Related Modules
-
-1. [@author.io/table](https://github.com/author/table) - Used to generate the default usage/help messages for the shell and subcommands.
-
-**Sponsors (as of 2020)**
-
-
-
-
-
-
-
diff --git a/dist/shell/index.js b/dist/shell/index.js
deleted file mode 100644
index d887997..0000000
--- a/dist/shell/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// @author.io/shell v1.8.18
-// Copyright (c) 2022 Corey Butler
-// Released under the MIT License.
-import{Parser}from"@author.io/arg";import Table from"@author.io/table";export{default as Table}from"@author.io/table";function _classPrivateFieldGet(receiver,privateMap){return function _classApplyDescriptorGet(receiver,descriptor){return descriptor.get?descriptor.get.call(receiver):descriptor.value}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"get"))}function _classPrivateFieldSet(receiver,privateMap,value){return function _classApplyDescriptorSet(receiver,descriptor,value){if(descriptor.set)descriptor.set.call(receiver,value);else{if(!descriptor.writable)throw new TypeError("attempted to set read only private field");descriptor.value=value}}(receiver,_classExtractFieldDescriptor(receiver,privateMap,"set"),value),value}function _classExtractFieldDescriptor(receiver,privateMap,action){if(!privateMap.has(receiver))throw new TypeError("attempted to "+action+" private field on non-instance");return privateMap.get(receiver)}class Middleware{constructor(){Object.defineProperties(this,{_data:{enumerable:!1,configurable:!1,value:[]},go:{enumerable:!1,configurable:!1,writable:!0,value:(...args)=>{args.pop().apply(this,args)}}})}get size(){return this._data.length}get data(){return this._data}use(method){const methodBody=method.toString();methodBody.indexOf("[native code]")<0&&this._data.push(methodBody),this.go=(stack=>(...args)=>{const next=args.pop();stack(...args,()=>{method.apply(this,[...args,next.bind(null,...args)])})})(this.go)}run(){const args=Array.from(arguments);0!==args.length&&"function"==typeof args[args.length-1]||args.push(()=>{}),this.go(...args)}}var _data=new WeakMap,_tableWidth=new WeakMap,_colAlign=new WeakMap,_colWidth=new WeakMap;class Formatter{constructor(data){_data.set(this,{writable:!0,value:null}),_tableWidth.set(this,{writable:!0,value:80}),_colAlign.set(this,{writable:!0,value:[]}),_colWidth.set(this,{writable:!0,value:["20%","15%","65%"]}),_classPrivateFieldSet(this,_data,data)}set width(value){_classPrivateFieldSet(this,_tableWidth,value<20?20:value)}set columnWidths(value){_classPrivateFieldSet(this,_colWidth,value)}set columnAlignment(value){_classPrivateFieldSet(this,_colAlign,value)}get usage(){const desc=_classPrivateFieldGet(this,_data).description.trim();if(_classPrivateFieldGet(this,_data)instanceof Command){const aliases=_classPrivateFieldGet(this,_data).aliases,out=[`${_classPrivateFieldGet(this,_data).commandroot}${aliases.length>0?"|"+aliases.join("|"):""}${_classPrivateFieldGet(this,_data).__flagConfig.size>0?" [FLAGS]":""}${_classPrivateFieldGet(this,_data).arguments.size>0?" "+Array.from(_classPrivateFieldGet(this,_data).arguments).map(i=>"<"+i+">").join(" "):""}`];return _classPrivateFieldGet(this,_data).__processors.size>0&&(out[out.length-1]+=(_classPrivateFieldGet(this,_data).arguments.size>0||_classPrivateFieldGet(this,_data).__flagConfig.size>0?" |":"")+" [COMMAND]"),desc.trim().length>0&&out!==desc&&out.push(new Table([[desc.trim().replace(/\n/gi,"\n ")]],null,null,_classPrivateFieldGet(this,_tableWidth),[2,0,1,1]).output),out.join("\n")}return _classPrivateFieldGet(this,_data)instanceof Shell?`${_classPrivateFieldGet(this,_data).name}${_classPrivateFieldGet(this,_data).__processors.size>0?" [COMMAND]":""}\n${desc.trim().length>0?new Table([[desc.trim().replace(/\n/gi,"\n ")]],null,null,_classPrivateFieldGet(this,_tableWidth),[2,0,1,1]).output:""}${_classPrivateFieldGet(this,_data).arguments.size>0?" "+Array.from(_classPrivateFieldGet(this,_data).arguments).map(i=>"["+i+"]").join(" "):""}\n`.trim():""}get subcommands(){const rows=Array.from(_classPrivateFieldGet(this,_data).__processors.values()).map(cmd=>[[cmd.name].concat(cmd.aliases).join("|"),cmd.description]),result=[];if(rows.length>0){const table=new Table(rows,_classPrivateFieldGet(this,_colAlign),["25%","75%"],_classPrivateFieldGet(this,_tableWidth),[2]);result.push("\nCommands:\n"),result.push(table.output)}return result.join("\n")}get help(){const usage=this.usage.trim();if(_classPrivateFieldGet(this,_data)instanceof Command){const flags=_classPrivateFieldGet(this,_data).__flagConfig,rows=[];flags.size>0&&flags.forEach((cfg,flag)=>{let aliases=Array.from(cfg.aliases||cfg.alias||[]);aliases=0===aliases.length?"":"["+aliases.map(a=>"-"+a).join(", ")+"]";let dsc=[cfg.description||""];cfg.hasOwnProperty("options")&&_classPrivateFieldGet(this,_data).describeOptions&&dsc.push(`Options: ${cfg.options.join(", ")}.`),cfg.hasOwnProperty("allowMultipleValues")&&!0===cfg.allowMultipleValues&&_classPrivateFieldGet(this,_data).describeMultipleValues&&dsc.push("Can be used multiple times."),cfg.hasOwnProperty("default")&&_classPrivateFieldGet(this,_data).describeDefault&&dsc.push(`(Default: ${cfg.default.toString()})`),cfg.hasOwnProperty("required")&&!0===cfg.required&&_classPrivateFieldGet(this,_data).describeRequired&&dsc.unshift("Required."),dsc=dsc.join(" ").trim(),rows.push(["--"+flag,aliases||"",dsc||""])});const table=new Table(rows,_classPrivateFieldGet(this,_colAlign),_classPrivateFieldGet(this,_colWidth),_classPrivateFieldGet(this,_tableWidth),[2,0,usage.length>0?1:0,0]);let subcommands="\n"+this.subcommands;return 0===subcommands.trim().length&&(subcommands=""),usage+(flags.size>0?"\n\nFlags:\n"+table.output:"")+subcommands}return _classPrivateFieldGet(this,_data)instanceof Shell?[usage,this.subcommands].join("\n"):""}}var _plugins=new WeakMap,_url=new WeakMap,_support=new WeakMap,_formattedDefaultHelp=new WeakMap,_description=new WeakMap,_customUsage=new WeakMap,_customHelp=new WeakMap,_arguments=new WeakMap,_autohelp=new WeakMap,_processors=new WeakMap,_commands=new WeakMap,_width=new WeakMap,_name=new WeakMap,_middleware=new WeakMap,_trailer=new WeakMap,_commonflags=new WeakMap,_display=new WeakMap,_hasCustomDefaultHandler=new WeakMap,_defaultHandler=new WeakMap;class Base{constructor(cfg={}){if(_plugins.set(this,{writable:!0,value:{}}),_url.set(this,{writable:!0,value:null}),_support.set(this,{writable:!0,value:null}),_formattedDefaultHelp.set(this,{writable:!0,value:void 0}),_description.set(this,{writable:!0,value:void 0}),_customUsage.set(this,{writable:!0,value:void 0}),_customHelp.set(this,{writable:!0,value:void 0}),_arguments.set(this,{writable:!0,value:new Set}),_autohelp.set(this,{writable:!0,value:!0}),_processors.set(this,{writable:!0,value:new Map}),_commands.set(this,{writable:!0,value:new Map}),_width.set(this,{writable:!0,value:80}),_name.set(this,{writable:!0,value:"Unknown"}),_middleware.set(this,{writable:!0,value:new Middleware}),_trailer.set(this,{writable:!0,value:new Middleware}),_commonflags.set(this,{writable:!0,value:{}}),_display.set(this,{writable:!0,value:{Default:null,Options:null,MultipleValues:null,Required:null}}),_hasCustomDefaultHandler.set(this,{writable:!0,value:!1}),_defaultHandler.set(this,{writable:!0,value:function(meta){return null!==this.parent&&this.parent.hasCustomDefaultHandler?this.parent.defaultHandler(...arguments):this.shell&&null!==this.shell&&this.shell.hasCustomDefaultHandler?this.shell.defaultHandler(...arguments):void(_classPrivateFieldGet(this,_autohelp)&&console.log(this.help))}}),"object"!=typeof cfg)throw new Error("Invalid command configuration. Expected an object.");if(!cfg.hasOwnProperty("name"))throw new Error('Invalid command configuration. A "name" attribute is required.');if(cfg.hasOwnProperty("help")&&_classPrivateFieldSet(this,_customHelp,cfg.help),cfg.hasOwnProperty("usage")&&_classPrivateFieldSet(this,_customUsage,cfg.usage),cfg.hasOwnProperty("disablehelp")&&!cfg.hasOwnProperty("disableHelp")&&(cfg.disableHelp=cfg.disablehelp),cfg.hasOwnProperty("disableHelp")&&!0===cfg.disableHelp&&_classPrivateFieldSet(this,_autohelp,!1),"function"!=typeof cfg.help&&"string"!=typeof cfg.help||(this.help=cfg.help),"function"!=typeof cfg.usage&&"string"!=typeof cfg.usage||(this.usage=cfg.usage),cfg.hasOwnProperty("defaultHandler")&&cfg.defaultHandler.toString()!==_classPrivateFieldGet(this,_defaultHandler).toString()&&(this.defaultHandler=cfg.defaultHandler),"string"==typeof cfg.arguments&&(cfg.arguments=cfg.arguments.split(/\s+|\t+|\,+|\;+/).map(arg=>arg.trim())),Array.isArray(cfg.arguments)&&_classPrivateFieldSet(this,_arguments,new Set(cfg.arguments)),"string"==typeof cfg.url&&_classPrivateFieldSet(this,_url,cfg.url),"string"==typeof cfg.support&&_classPrivateFieldSet(this,_support,cfg.support),_classPrivateFieldSet(this,_name,(cfg.name||"unknown").trim().split(/\s+/)[0]),_classPrivateFieldSet(this,_description,cfg.description||null),Array.isArray(cfg.commands))cfg.commands.forEach(cmd=>this.add(cmd));else if("object"==typeof cfg.commands)for(const key in cfg.commands){const data=cfg.commands[key];data.name=key,this.add(data)}if(cfg.hasOwnProperty("middleware")&&(console.warn('The "middleware" attribute has been replaced with the "use" attribute.'),cfg.use=cfg.middleware,delete cfg.middleware),cfg.hasOwnProperty("commonflag")||(cfg.hasOwnProperty("commonFlag")?cfg.commonflag=cfg.commonFlag:cfg.hasOwnProperty("commonflags")?cfg.commonflag=cfg.commonflags:cfg.hasOwnProperty("commonFlag")?cfg.commonflag=cfg.commonFlag:cfg.hasOwnProperty("commonFlags")&&(cfg.commonflag=cfg.commonFlags)),cfg.hasOwnProperty("commonflag")&&"object"!=typeof cfg.commonflag)throw new Error('The "commonflag" configuration attribute must be an object.');"object"==typeof cfg.plugins&&_classPrivateFieldSet(this,_plugins,cfg.plugins),Object.defineProperties(this,{__processors:{enumerable:!1,get(){return _classPrivateFieldGet(this,_processors)}},__commands:{enumerable:!1,get(){return _classPrivateFieldGet(this,_commands)}},__width:{enumerable:!1,get(){return _classPrivateFieldGet(this,_width)},set(v){_classPrivateFieldSet(this,_width,v||80)}},__commonflags:{enumerable:!1,get(){return _classPrivateFieldGet(this,_commonflags)},set(value){_classPrivateFieldSet(this,_commonflags,value)}},arguments:{enumerable:!1,get(){return _classPrivateFieldGet(this,_arguments)}},initializeMiddleware:{enumerable:!1,configurable:!1,writable:!1,value:code=>{if("string"==typeof code)this.use(Function("return "+code)());else{if("function"!=typeof code)throw new Error("Invalid middleware: "+code.toString());this.use(code)}}},initializeTrailer:{enumerable:!1,configurable:!1,writable:!1,value:code=>{if("string"==typeof code)this.trailer(Function("return "+code)());else{if("function"!=typeof code)throw new Error("Invalid trailer: "+code.toString());this.trailer(code)}}},initializeHelpAnnotations:{enumerable:!1,configurable:!1,writable:!1,value:cfg=>{cfg.hasOwnProperty("describeDefault")&&"boolean"==typeof cfg.describeDefault&&(_classPrivateFieldGet(this,_display).Default=cfg.describeDefault),cfg.hasOwnProperty("describeOptions")&&"boolean"==typeof cfg.describeOptions&&(_classPrivateFieldGet(this,_display).Options=cfg.describeOptions),cfg.hasOwnProperty("describeMultipleValues")&&"boolean"==typeof cfg.describeMultipleValues&&(_classPrivateFieldGet(this,_display).MultipleValues=cfg.describeMultipleValues),cfg.hasOwnProperty("describeRequired")&&"boolean"==typeof cfg.describeRequired&&(_classPrivateFieldGet(this,_display).Required=cfg.describeRequired)}}}),this.updateHelp()}get plugins(){return _classPrivateFieldGet(this,_plugins)}get name(){return _classPrivateFieldGet(this,_name)||"Unknown"}get description(){return _classPrivateFieldGet(this,_description)||this.usage||""}get url(){return this.URL}get URL(){const uri=(_classPrivateFieldGet(this,_url)||"").trim();if(0===uri.length){if(this.hasOwnProperty("parent"))return this.parent.URL;if(this instanceof Command)return this.shell.URL}return uri}get support(){const support=(_classPrivateFieldGet(this,_support)||"").trim();if(0===support.length){if(this.hasOwnProperty("parent"))return this.parent.support;if(this instanceof Command)return this.shell.support}return support}get autohelp(){return _classPrivateFieldGet(this,_autohelp)}set autohelp(value){"boolean"==typeof value&&(_classPrivateFieldSet(this,_autohelp,value),_classPrivateFieldGet(this,_processors).forEach(cmd=>{cmd.autohelp=value}))}updateHelp(){_classPrivateFieldSet(this,_formattedDefaultHelp,new Formatter(this)),_classPrivateFieldGet(this,_formattedDefaultHelp).width=_classPrivateFieldGet(this,_width)}describeHelp(attr,prop){if(null!==_classPrivateFieldGet(this,_display)[prop])return _classPrivateFieldGet(this,_display)[prop];if(this instanceof Command){if(this.shell&&null!==this.shell&&null!==this.shell[attr])return this.shell[attr];if(null!==this.parent)return this.parent[attr]}return!0}get describeDefault(){return this.describeHelp("describeDefault","Default")}get describeOptions(){return this.describeHelp("describeOptions","Options")}get describeMultipleValues(){return this.describeHelp("describeMultipleValues","MultipleValues")}get describeRequired(){return this.describeHelp("describeRequired","Required")}get usage(){return null!==_classPrivateFieldGet(this,_customUsage)?"function"==typeof _classPrivateFieldGet(this,_customUsage)?_classPrivateFieldGet(this,_customUsage).call(this):_classPrivateFieldGet(this,_customUsage):_classPrivateFieldGet(this,_formattedDefaultHelp).usage}set usage(value){"string"==typeof value&&0===value.trim().length&&(value=null),_classPrivateFieldSet(this,_customUsage,value),this.updateHelp()}get help(){return _classPrivateFieldGet(this,_customHelp)?"function"==typeof _classPrivateFieldGet(this,_customHelp)?_classPrivateFieldGet(this,_customHelp).call(this,this):_classPrivateFieldGet(this,_customHelp):this.autohelp?_classPrivateFieldGet(this,_formattedDefaultHelp).help:""}set help(value){"string"==typeof value&&0===value.trim().length&&(value=null),_classPrivateFieldSet(this,_customHelp,value),this.updateHelp()}set defaultHandler(value){if("function"!=typeof value)throw new Error(`Invalid default method (must be a function, not "${typeof value}").`);_classPrivateFieldSet(this,_defaultHandler,value),_classPrivateFieldSet(this,_hasCustomDefaultHandler,!0),_classPrivateFieldGet(this,_processors).forEach(cmd=>{cmd.defaultProcessor=value})}get defaultHandler(){return _classPrivateFieldGet(this,_defaultHandler)}get hasCustomDefaultHandler(){return _classPrivateFieldGet(this,_hasCustomDefaultHandler)}get data(){const commands={};return Array.from(_classPrivateFieldGet(this,_processors).values()).forEach(cmd=>{const data=cmd.data,name=data.name;delete data.name,commands[name]=data}),commands}get middleware(){return _classPrivateFieldGet(this,_middleware)}get trailers(){return _classPrivateFieldGet(this,_trailer)}get commands(){return _classPrivateFieldGet(this,_processors)}get commandlist(){const list=new Set;return this.commands.forEach(cmd=>{list.add(cmd.name),cmd.commandlist.forEach(subcmd=>list.add(`${cmd.name} ${subcmd}`))}),Array.from(list).sort()}getCommand(name=null){if(!name)return null;const names=name.split(/\s+/i);let cmd=_classPrivateFieldGet(this,_commands).get(names.shift());if(cmd){cmd=_classPrivateFieldGet(this,_processors).get(cmd);for(const nm of names)cmd=cmd.getCommand(nm)}return cmd instanceof Command?cmd:null}remove(){for(const cmd of arguments)if("symbol"==typeof cmd&&(_classPrivateFieldGet(this,_processors).delete(cmd),_classPrivateFieldGet(this,_commands).forEach(oid=>oid===cmd&&_classPrivateFieldGet(this,_commands).delete(oid))),"string"==typeof cmd){const OID=_classPrivateFieldGet(this,_commands).get(cmd);OID&&this.remove(OID)}}use(){for(const arg of arguments){if("function"!=typeof arg)throw new Error(`All "use()" arguments must be valid functions.\n${arg.toString().substring(0,50)} ${arg.toString().length>50?"...":""}`);_classPrivateFieldGet(this,_middleware).use(arg)}_classPrivateFieldGet(this,_processors).forEach(subCmd=>subCmd.use(...arguments))}trailer(){_classPrivateFieldSet(this,_trailer,_classPrivateFieldGet(this,_trailer)||new Middleware);for(const arg of arguments){if("function"!=typeof arg)throw new Error(`All "trailer()" arguments must be valid functions.\n${arg.toString().substring(0,50)} ${arg.toString().length>50?"...":""}`);_classPrivateFieldGet(this,_trailer).use(arg)}_classPrivateFieldGet(this,_processors).forEach(subCmd=>subCmd.trailer(...arguments))}add(){for(let command of arguments){if(!(command instanceof Command)){if("object"!=typeof command)throw new Error('Invalid argument. Only "Command" instances may be added to the processor.');command=new Command(command)}command.autohelp=this.autohelp,this instanceof Shell?command.shell=this:this instanceof Command&&(command.parent=this),_classPrivateFieldGet(this,_processors).set(command.OID,command),_classPrivateFieldGet(this,_commands).set(command.name,command.OID),command.aliases.forEach(alias=>_classPrivateFieldGet(this,_commands).set(alias,command.OID))}}}const FLAG_PATTERN=/((?:"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|\/[^\/\\]*(?:\\[\S\s][^\/\\]*)*\/[gimy]*(?=\s|$)|(?:\\\s|\S))+)(?=\s|$)/g,METHOD_PATTERN=/^([\w]+\s?)\(.*\)\s?{/i,STRIP_QUOTE_PATTERN=/"([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'/gi,COMMAND_PATTERN=/^(\w+)\s+([\s\S]+)?/i;Object.freeze({SUBCOMMAND_PATTERN:/^([^"'][\S\b]+)[\s+]?([^-].*)$/i,FLAG_PATTERN:FLAG_PATTERN,METHOD_PATTERN:METHOD_PATTERN,STRIP_QUOTE_PATTERN:STRIP_QUOTE_PATTERN,COMMAND_PATTERN:COMMAND_PATTERN});var _middlewareGroups=new WeakMap,_history=new WeakMap,_maxHistoryItems=new WeakMap,_version=new WeakMap,_cursor=new WeakMap,_tabWidth=new WeakMap,_runtime=new WeakMap;class Shell extends Base{constructor(cfg={maxhistory:100}){super(cfg),_middlewareGroups.set(this,{writable:!0,value:new Map}),_history.set(this,{writable:!0,value:[]}),_maxHistoryItems.set(this,{writable:!0,value:void 0}),_version.set(this,{writable:!0,value:void 0}),_cursor.set(this,{writable:!0,value:0}),_tabWidth.set(this,{writable:!0,value:void 0}),_runtime.set(this,{writable:!0,value:globalThis.hasOwnProperty("window")?"browser":globalThis.hasOwnProperty("process")&&globalThis.process.release&&globalThis.process.release.name?globalThis.process.release.name:"unknown"}),this.initializeHelpAnnotations(cfg),this.__commonflags=cfg.commonflags||{},cfg.hasOwnProperty("use")&&Array.isArray(cfg.use)&&cfg.use.forEach(code=>this.initializeMiddleware(code)),cfg.hasOwnProperty("trailer")&&Array.isArray(cfg.trailer)&&cfg.trailer.forEach(code=>this.initializeTrailer(code)),_classPrivateFieldSet(this,_version,cfg.version||"1.0.0"),_classPrivateFieldSet(this,_maxHistoryItems,cfg.maxhistory||cfg.maxHistoryItems||100),_classPrivateFieldSet(this,_tabWidth,cfg.hasOwnProperty("tabWidth")?cfg.tabWidth:4),globalThis[Symbol("SHELL_INTEGRATIONS")]=this}get data(){const commands=super.data;return{name:this.name,description:this.description,version:this.version,commands:commands,use:this.middleware.data,trailer:this.trailers.data,help:this.help,usage:this.usage,defaultHandler:this.defaultHandler.toString(),disableHelp:!this.autohelp,runtime:_classPrivateFieldGet(this,_runtime),maxHistoryItems:_classPrivateFieldGet(this,_maxHistoryItems)}}get version(){return _classPrivateFieldGet(this,_version)||"Unknown"}set tableWidth(value){this.__width=value}get tableWidth(){return this.__width}history(count=null){return 0===_classPrivateFieldGet(this,_history).length?[]:null===count?_classPrivateFieldGet(this,_history).slice():_classPrivateFieldGet(this,_history).slice(0,count)}priorCommand(count=0){return 0===_classPrivateFieldGet(this,_history).length?null:count<0?this.nextCommand(Math.abs(count)):(count%=_classPrivateFieldGet(this,_history).length,_classPrivateFieldSet(this,_cursor,_classPrivateFieldGet(this,_cursor)+count),_classPrivateFieldGet(this,_cursor)>=_classPrivateFieldGet(this,_history).length&&_classPrivateFieldSet(this,_cursor,_classPrivateFieldGet(this,_history).length-1),_classPrivateFieldGet(this,_history)[_classPrivateFieldGet(this,_cursor)].input)}nextCommand(count=1){return 0===_classPrivateFieldGet(this,_history).length?null:count<0?this.priorCommand(Math.abs(count)):(count%=_classPrivateFieldGet(this,_history).length,_classPrivateFieldSet(this,_cursor,_classPrivateFieldGet(this,_cursor)-count),_classPrivateFieldGet(this,_cursor)<0?void _classPrivateFieldSet(this,_cursor,0):_classPrivateFieldGet(this,_history)[_classPrivateFieldGet(this,_cursor)].input)}useWith(commands){if(arguments.length<2)throw new Error("useWith(['command', 'command'], fn) requires two or more arguments.");if(commands="string"==typeof commands?commands.split(/\s+/):commands,!Array.isArray(commands)||commands.filter(c=>"string"!=typeof c).length>0)throw new Error("The first argument of useWith must be a string or array of strings. Received "+typeof commands);const fns=Array.from(arguments).slice(1);commands.forEach(cmd=>_classPrivateFieldGet(this,_middlewareGroups).set(cmd.trim(),(_classPrivateFieldGet(this,_middlewareGroups).get(cmd.trim())||[]).concat(fns)))}useExcept(commands){if(arguments.length<2)throw new Error("useExcept(['command', 'command'], fn) requires two or more arguments.");if(commands="string"==typeof commands?commands.split(/\s+/):commands,!Array.isArray(commands)||commands.filter(c=>"string"!=typeof c).length>0)throw new Error("The first argument of useExcept must be a string or array of strings. Received "+typeof commands);const fns=Array.from(arguments).slice(1),all=new Set(this.commandlist.map(i=>i.toLowerCase()));commands.forEach(cmd=>{all.delete(cmd);for(const c of all)0===c.indexOf(cmd)&&all.delete(c)}),this.useWith(Array.from(all),...fns)}async exec(input,callback){Array.isArray(input)&&(input=input.map(i=>i.indexOf(" ")>=0&&!/^[\"\'].+ [\"\']$/.test(i)?`"${i}"`:i).join(" ")),_classPrivateFieldGet(this,_history).unshift({input:input,time:(new Date).toLocaleString()}),_classPrivateFieldGet(this,_history).length>_classPrivateFieldGet(this,_maxHistoryItems)&&_classPrivateFieldGet(this,_history).pop();let parsed=COMMAND_PATTERN.exec(input+" ");if(null===parsed)return-1!==input.indexOf("version")||-1!==input.indexOf("-v")?console.log(this.version):-1!==input.indexOf("help")?console.log(this.help):Command.stderr(this.help);parsed=parsed.filter(item=>void 0!==item);const cmd=parsed[1],args=parsed.length>2?parsed[2]:"",action=this.__commands.get(cmd);if(!action)return"version"===cmd.toLowerCase()?console.log(this.version):Command.stderr(this.help);const processor=this.__processors.get(action);if(!processor)return Command.stderr("Command not found.");const term=processor.getTerminalCommand(args);return await Command.reply(await term.command.run(term.arguments,callback))}getCommandMiddleware(cmd){const results=[];return cmd.split(/\s+/).forEach((c,i,a)=>{const r=_classPrivateFieldGet(this,_middlewareGroups).get(a.slice(0,i+1).join(" "));r&&results.push(r.flat(1/0))}),results.flat(1/0)}clearHistory(){_classPrivateFieldSet(this,_history,[])}clear(){_classPrivateFieldSet(this,_history,[]),console.clear()}}var _pattern=new WeakMap,_oid=new WeakMap,_aliases=new WeakMap,_fn=new WeakMap,_flagConfig=new WeakMap,_parent=new WeakMap,_shell=new WeakMap;class Command extends Base{constructor(cfg={}){if(cfg.hasOwnProperty("handler")&&("string"==typeof cfg.handler&&(cfg.handler=Function("return ("+cfg.handler.replace("function anonymous","function")+").call(this)").call(globalThis)),"function"!=typeof cfg.handler))throw new Error('Invalid command configuration. A "handler" function is required.');if(super(cfg),_pattern.set(this,{writable:!0,value:void 0}),_oid.set(this,{writable:!0,value:void 0}),_aliases.set(this,{writable:!0,value:new Set}),_fn.set(this,{writable:!0,value:void 0}),_flagConfig.set(this,{writable:!0,value:{}}),_parent.set(this,{writable:!0,value:null}),_shell.set(this,{writable:!0,value:null}),cfg.hasOwnProperty("use")&&Array.isArray(cfg.use)&&cfg.use.forEach(code=>this.initializeMiddleware(code)),cfg.hasOwnProperty("trailer")&&Array.isArray(cfg.trailer)&&cfg.trailer.forEach(code=>this.initializeTrailer(code)),this.initializeHelpAnnotations(cfg),_classPrivateFieldSet(this,_fn,cfg.handler),_classPrivateFieldSet(this,_oid,Symbol(cfg.name||cfg.usage||cfg.pattern||"command")),_classPrivateFieldSet(this,_pattern,cfg.pattern||/[\s\S]+/i),cfg.alias&&!cfg.aliases&&(cfg.aliases="string"==typeof cfg.alias?[cfg.alias]:Array.isArray(cfg.alias)?cfg.alias:Array.from(cfg.alias),delete cfg.alias),cfg.aliases){if(!Array.isArray(cfg.aliases))throw new Error("The alias property only accepts an array.");_classPrivateFieldSet(this,_aliases,new Set(cfg.aliases))}if(cfg.flags){if("object"!=typeof cfg.flags)throw new Error(`Invalid flag configuration (expected and object, received ${typeof cfg.flags}).`);for(const[key,value]of Object.entries(cfg.flags))if(value.hasOwnProperty("alias")){if(value.aliases=value.aliases||[],Array.isArray(value.alias)){if(value.aliases=Array.from(new Set(...value.aliases,...value.alias)),value.aliases.filter(a=>"string"!=typeof a)>0)throw new Error(`${key} flag aliases must be strings. Type failure on: ${value.aliases.filter(a=>"string"!=typeof a).join(", ")}.`)}else{if("string"!=typeof value.alias)throw new Error(`Aliases must be strings, not ${typeof value.alias} (${key} flag).`);value.aliases.push(value.alias)}delete value.alias}_classPrivateFieldSet(this,_flagConfig,cfg.flags)}Array.isArray(cfg.subcommands)&&this.add(...cfg.subcommands);const attributes=new Set(["commands","subcommands","plugins","defaultHandler","disableHelp","describeDefault","describeOptions","describeMultipleValues","describeRequired","flags","alias","aliases","description","help","usage","pattern","name","handler","middleware","use","arguments","commonflag","commonflags","trailer","url","support"]),unrecognized=Object.keys(cfg).filter(attribute=>!attributes.has(attribute));if(unrecognized.length>0)throw new Error("Unrecognized configuration attribute(s): "+unrecognized.join(", "));const ignoreFlags=commonFlags=>{if(commonFlags.ignore&&(Array.isArray(commonFlags.ignore)||"string"==typeof commonFlags.ignore)){const ignore=new Set(Array.isArray(commonFlags.ignore)?commonFlags.ignore:[commonFlags.ignore]),root=this.commandroot.replace(new RegExp(`^${this.shell.name}\\s+`,"i"),"");for(const cmd of ignore)if(root.startsWith(cmd)){commonFlags={};break}}return commonFlags};Object.defineProperties(this,{__commonFlags:{enumerable:!1,get(){let flags=ignoreFlags(this.__commonflags);null!==this.parent&&(flags=Object.assign(flags,this.parent.__commonFlags));const result=Object.assign({},null!==this.shell?ignoreFlags(this.shell.__commonflags):{},flags);return(Array.isArray(result.ignore)||"string"==typeof result.ignore)&&delete result.ignore,result}},__flagConfig:{enumerable:!1,get(){const flags=new Map(Object.entries(Object.assign(this.__commonFlags,_classPrivateFieldGet(this,_flagConfig)||{})));return flags.delete("help"),flags}},getTerminalCommand:{enumerable:!1,configurable:!1,writable:!1,value:input=>{const args=input.trim().split(/\t+|\s+/);let cmd=this;for(;args.length>0;){const arg=args[0],subcmd=cmd.getCommand(arg);if(!subcmd)break;cmd=subcmd,args.shift()}return{command:cmd,arguments:args.join(" ")}}}}),this.__commonflags=cfg.commonflags||{},this.__width=null===this.shell?80:this.shell.tableWidth||80,this.updateHelp()}get data(){const commands=super.data;let handler=(_classPrivateFieldGet(this,_fn)||this.defaultHandler).toString();METHOD_PATTERN.test(handler)&&(handler=handler.replace(METHOD_PATTERN.exec(handler)[1],"function "));const flags=Object.assign(this.__commonFlags,_classPrivateFieldGet(this,_flagConfig)||{});for(const[key,value]of Object.entries(flags))value.aliases=value.aliases||[],value.hasOwnProperty("alias")&&value.aliases.indexOf(value.alias)<0&&value.aliases.push(value.alias),delete value.alias;Object.keys(flags).forEach(name=>{flags[name]=Object.assign(this.getFlagConfiguration(name),flags[name])});const data={name:this.name,description:this.description,help:this.help,usage:this.usage,aliases:Array.from(_classPrivateFieldGet(this,_aliases)),flags:flags,handler:handler,commands:commands,disableHelp:!this.autohelp,use:this.middleware.data,trailer:this.trailers.data};for(const[key,value]of Object.entries(data.flags))delete value.alias;return data}set parent(cmd){if(!(cmd instanceof Command))throw new Error(`Cannot set parent of "${this.name}" command to anything other than another command. To make this command a direct descendent of the main shell, use the shell attribute instead.`);_classPrivateFieldSet(this,_parent,cmd)}get parent(){return _classPrivateFieldGet(this,_parent)}set shell(shell){if(!shell)throw new Error(`Cannot set shell of ${this.name} command to a non-Shell object.`);if(!(shell instanceof Shell))throw new Error(`Expected a Shell object, received a "${typeof shell}" object.`);_classPrivateFieldSet(this,_shell,shell),this.__width=null===this.shell?80:shell.tableWidth}get shell(){return _classPrivateFieldGet(this,_shell)?_classPrivateFieldGet(this,_shell):_classPrivateFieldGet(this,_parent)?_classPrivateFieldGet(this,_parent).shell:null}get plugins(){return Object.assign({},this.shell.plugins,this.parent?this.parent.plugins:{},super.plugins)}get commandroot(){return _classPrivateFieldGet(this,_parent)?`${_classPrivateFieldGet(this,_parent).commandroot} ${this.name}`.trim():_classPrivateFieldGet(this,_shell)?`${_classPrivateFieldGet(this,_shell).name} ${this.name}`.trim():this.name}set aliases(value){if(value){if("object"==typeof value)switch(value.constructor.name.toLowerCase()){case"map":value=Array.from(value.keys());break;case"set":value=Array.from(value);break;case"object":value=Object.keys(value).filter(item=>"string"==typeof item);break;case"array":break;case"string":value=value.split(/\s+/)[0];break;default:throw new Error("Invalid alias value. Use an array of strings.")}_classPrivateFieldSet(this,_aliases,Array.from(new Set(value)))}else _classPrivateFieldSet(this,_aliases,[])}get aliases(){return Array.from(_classPrivateFieldGet(this,_aliases))||[]}get OID(){return _classPrivateFieldGet(this,_oid)}addFlag(name,cfg){if("string"!=typeof name){if(!cfg.hasOwnProperty("name"))throw new Error("Invalid flag name (should be a string).");name=cfg.name}_classPrivateFieldGet(this,_flagConfig)[name]=cfg}removeFlag(name){delete _classPrivateFieldGet(this,_flagConfig)[name]}getFlagConfiguration(name){let flag=this.__flagConfig.get(name);if(!flag){for(const[f,cfg]of this.__flagConfig)if(cfg.aliases&&cfg.aliases.indexOf(name)>=0||cfg.alias&&cfg.alias===flag){flag=cfg;break}if(!flag)return null}return{description:flag.description,required:!!flag.hasOwnProperty("required")&&flag.required,aliases:flag.aliases||[flag.alias].filter(i=>null!==i),type:void 0===flag.type?"string":"string"==typeof flag.type?flag.type:flag.type.name.toLowerCase(),options:flag.hasOwnProperty("options")?flag.options:null,allowMultipleValues:!!flag.hasOwnProperty("allowMultipleValues")&&flag.allowMultipleValues}}supportsFlag(name){return _classPrivateFieldGet(this,_flagConfig).hasOwnProperty(name)}deepParse(input){const meta=this.parse(input);if(0===this.__commands.size)return meta;if(0===meta.input.trim().length)return meta;const args=meta.input.split(/\s+/),subcmd=this.__commands.get(args.shift());return subcmd?this.__processors.get(subcmd).deepParse(args.join(" ")):meta}parse(input){const data={command:this.name,input:input.trim()},flagConfig=Object.assign(this.__commonFlags,_classPrivateFieldGet(this,_flagConfig)||{});flagConfig.hasOwnProperty("help")||(flagConfig.help={description:`Display ${this.name} help.`,default:!1,type:"boolean"});const flags=Array.from(FLAG_PATTERN[Symbol.matchAll](input),x=>x[0]),parser=new Parser(flags,flagConfig),pdata=parser.data,recognized={};if(parser.recognizedFlags.forEach(flag=>{recognized[flag]=pdata[flag]}),parser.unrecognizedFlags.forEach(arg=>delete recognized[arg]),data.flags={recognized:recognized,unrecognized:parser.unrecognizedFlags},data.valid=parser.valid,data.violations=parser.violations,data.parsed={},Object.keys(pdata.flagSource).length>0)for(const[key,src]of Object.entries(pdata.flagSource))data.parsed[src.name]=src.inputName;data.help={requested:recognized.help},recognized.help&&(data.help.message=this.help);const args=Array.from(this.arguments);return Object.defineProperties(data,{flag:{enumerable:!0,configurable:!1,writable:!1,value:name=>{try{return"number"==typeof name?Array.from(parser.unrecognizedFlags)[name]:data.flags.recognized.hasOwnProperty(pdata.flagSource[name].name)?data.flags.recognized[pdata.flagSource[name].name]:pdata.flagSource[name].value}catch(e){return this.arguments.has(name)?Array.from(parser.unrecognizedFlags)[args.indexOf(name)]:void 0}}},command:{enumerable:!0,get:()=>this},shell:{enumerable:!0,get:()=>this.shell},data:{enumerable:!0,get(){const uf=parser.unrecognizedFlags,result=Object.assign({},recognized);return delete result.help,args.forEach((name,i)=>{const value=uf[i];let normalizedValue=Object.keys(pdata).filter(key=>key.toLowerCase()===value);normalizedValue=normalizedValue.length>0?normalizedValue.pop():value,void 0!==normalizedValue&&(normalizedValue=normalizedValue.trim(),STRIP_QUOTE_PATTERN.test(normalizedValue)&&(normalizedValue=normalizedValue.substring(1,normalizedValue.length-1))),result.hasOwnProperty(name)?(result[name]=Array.isArray(result[name])?result[name]:[result[name]],result[name].push(normalizedValue)):result[name]=normalizedValue}),uf.length>args.length&&uf.slice(args.length).forEach((flag,i)=>{let name="unknown"+(i+1);for(;result.hasOwnProperty(name);){const number=name.substring(7);name="unknown"+(parseInt(number)+1)}result[name]=flag}),result}}}),Object.defineProperty(data.help,"default",{enumerable:!0,get:()=>this.help}),data}async run(input,callback){const fn=(_classPrivateFieldGet(this,_fn)||this.defaultHandler).bind(this),data="string"==typeof input?this.parse(input):input;if(arguments[0]=this.deepParse(input),arguments[0].plugins=this.plugins,null!==this.shell){const parentMiddleware=this.shell.getCommandMiddleware(this.commandroot.replace(new RegExp("^"+this.shell.name,"i"),"").trim());parentMiddleware.length>0&&this.middleware.use(...parentMiddleware)}const trailers=this.trailers;return arguments[0].help&&arguments[0].help.requested?(console.log(this.help),void(trailers.size>0&&trailers.run(arguments[0]))):this.middleware.size>0?(this.middleware.run(arguments[0],async meta=>await Command.reply(fn(meta,callback))),void(trailers.size>0&&trailers.run(arguments[0]))):(data.plugins=this.plugins,Command.reply(fn(data,callback)),void(trailers.size>0&&trailers.run(arguments[0])))}static stderr(err){return Error,new Promise((resolve,reject)=>reject(err)).catch(console.error)}static reply(callback){return new Promise((resolve,reject)=>{try{"function"==typeof callback&&callback(),resolve()}catch(e){reject(e)}})}}const all={Shell:Shell,Command:Command,Formatter:Formatter,Table:Table,Middleware:Middleware};export default all;export{Command,Formatter,Middleware,Shell};
-//# sourceMappingURL=../shell-debug/index.js.map
diff --git a/dist/shell/package.json b/dist/shell/package.json
deleted file mode 100644
index ec4d962..0000000
--- a/dist/shell/package.json
+++ /dev/null
@@ -1,84 +0,0 @@
-{
- "name": "@author.io/shell",
- "version": "1.8.18",
- "description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
- "main": "./src/index.js",
- "module": "./index.js",
- "exports": {
- "import": "./index.js",
- "default": "./index.js"
- },
- "browser": "./index.js",
- "keywords": [
- "cli",
- "args",
- "arg",
- "shell"
- ],
- "repository": {
- "type": "git",
- "url": "https://github.com/author/shell"
- },
- "dev": {
- "ignorecircular": [
- "src/command.js",
- "src/shell.js"
- ],
- "replace": {
- "<#REPLACE_VERSION#>": "package.version"
- },
- "volume": [
- "./node_modules/@author.io/arg:/node_modules/@author.io/arg",
- "./node_modules/@author.io/table:/node_modules/@author.io/table"
- ],
- "alias": {
- "@author.io/shell": "/app/.dist/@author.io/shell/index.js",
- "@author.io/arg": "/node_modules/@author.io/arg/index.js",
- "@author.io/table": "/node_modules/@author.io/table/index.js"
- },
- "ci": {
- "verbose": true,
- "peer": true,
- "embed": [
- "@author.io/arg",
- "@author.io/table"
- ]
- }
- },
- "author": {
- "name": "Corey Butler",
- "url": "http://coreybutler.com"
- },
- "license": "MIT",
- "type": "module",
- "files": [
- "*.js"
- ],
- "engines": {
- "node": ">=13.5.0"
- },
- "standard": {
- "parser": "babel-eslint",
- "ignore": [
- "_*",
- "_**/*",
- ".**/*",
- "node_modules",
- "karma.conf.js",
- "karma.conf.cjs",
- "build.js"
- ],
- "globals": [
- "window",
- "global",
- "globalThis"
- ]
- },
- "devDependencies": {
- "@author.io/arg": "^1.3.23",
- "@author.io/dev": "^1.1.5",
- "@author.io/table": "^1.0.3",
- "@author.io/shell-debug": "1.8.18"
- },
- "dependencies": {}
-}
\ No newline at end of file
From ea448bd59c7f01522e44693bc8d32f7865e8e019 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Thu, 10 Feb 2022 19:54:27 -0600
Subject: [PATCH 147/152] Embedded arg dependency
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index ddd00c3..cb8fa30 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.9.0",
+ "version": "1.9.1",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "./src/index.js",
"module": "./index.js",
From 541230838e72ddb27ee7e580050b43511f8c1828 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Fri, 11 Feb 2022 11:48:14 -0600
Subject: [PATCH 148/152] Update example to support new custom handler data
reference input syntax
---
README.md | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 2f7208b..12b49ae 100644
--- a/README.md
+++ b/README.md
@@ -347,20 +347,22 @@ const sh = new Shell({
})
const ref = { test: true }
-const result = await sh.exec('run', ref)
+const result = await sh.exec('run', { reference: ref })
```
-In the command above, the data object (line 1) is passed to the `exec()` method using a special object as the second argument. This object is made available in the handler using the `meta.reference` attribute.
+In the command above, the reference data (second to last line) is passed to the `exec()` method using a special object as the second argument. This object is made available in the handler using the `meta.reference` attribute.
If a callback needs to be defined, the second argument of the `exec` method must have an attribute called `callback`, i.e.:
```javascript
const ref = {
- test: true,
- callback: function() {...}
+ test: true
}
-const result = await sh.exec('run', ref)
+const result = await sh.exec('run', {
+ reference: ref,
+ callback: function () {...}
+})
```
The callback method is _not_ available in the `meta.reference`, but the callback will be executed when `exec()` is executed.
From 2eec3f662fa7deedcafaedeaec157b71b3d4e035 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 30 Mar 2022 09:16:38 -0500
Subject: [PATCH 149/152] Delete package-lock.json
---
package-lock.json | 482 ----------------------------------------------
1 file changed, 482 deletions(-)
delete mode 100644 package-lock.json
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 4176ef3..0000000
--- a/package-lock.json
+++ /dev/null
@@ -1,482 +0,0 @@
-{
- "name": "@author.io/shell",
- "version": "1.8.18",
- "lockfileVersion": 2,
- "requires": true,
- "packages": {
- "": {
- "name": "@author.io/shell",
- "version": "1.8.18",
- "license": "MIT",
- "devDependencies": {
- "@author.io/arg": "^1.3.23",
- "@author.io/dev": "^1.1.5",
- "@author.io/table": "^1.0.3"
- },
- "engines": {
- "node": ">=13.5.0"
- }
- },
- "node_modules/@author.io/arg": {
- "version": "1.3.23",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.23.tgz",
- "integrity": "sha512-J3Ia2+HHf4rNpgz0YK6UzRqVZHZt0JXRocMCfh7tPOTK8WPbu0aLXwGHLLH4L6ySFs09V+/Zbke3rLQDzYltDw==",
- "dev": true,
- "engines": {
- "node": ">=12.0.0"
- }
- },
- "node_modules/@author.io/dev": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/@author.io/dev/-/dev-1.1.6.tgz",
- "integrity": "sha512-unNtw/ibtPjbkhd7IDmO4e+JDpWoxqFmuQgF+gu3LDms2Nd0k/pN+umAPaxLPNHW/r7yvaTarMYtwdZOWQsf6A==",
- "dev": true,
- "dependencies": {
- "@author.io/node-shell": "^1.8.2",
- "@author.io/shell": "^1.3.8",
- "chalk": "^4.1.0",
- "glob": "^7.1.6",
- "semver": "^7.3.2"
- },
- "bin": {
- "dev": "index.js",
- "jsdev": "index.js"
- }
- },
- "node_modules/@author.io/node-shell": {
- "version": "1.8.2",
- "resolved": "https://registry.npmjs.org/@author.io/node-shell/-/node-shell-1.8.2.tgz",
- "integrity": "sha512-mnOwUASxLYV3NcSlUvjHwnLkbwhxSUcq/dwUPkawWmu5TJ6txYcU+Eub4QMyCXqpiThyiFrRc6Za89Nh+dKo0w==",
- "dev": true,
- "dependencies": {
- "@author.io/arg": "^1.3.8",
- "@author.io/table": "^1.0.3"
- },
- "engines": {
- "node": ">=13.5.0"
- }
- },
- "node_modules/@author.io/shell": {
- "version": "1.8.13",
- "resolved": "https://registry.npmjs.org/@author.io/shell/-/shell-1.8.13.tgz",
- "integrity": "sha512-5cXWXOjilxtfdKynAyGkoPbjj5JG15JafLPxmylH61i5cvD3ZecpAhNYUwrucmCOP+EspixAY1Tlvr0DyBEjVw==",
- "dev": true,
- "engines": {
- "node": ">=13.5.0"
- }
- },
- "node_modules/@author.io/table": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.1.1.tgz",
- "integrity": "sha512-QvDVZnZ4qZHKrFkGi44QZBJAAkm0lsYKIrdA17ZKzrl5jUjO38qyiatSBl4ttqpWcHNJRBP8A/p7kLAOiRrK8Q==",
- "dev": true
- },
- "node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/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
- },
- "node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
- "dev": true
- },
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
- "dev": true
- },
- "node_modules/glob": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
- "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
- "dev": true,
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "dev": true,
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
- },
- "node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "dev": true,
- "dependencies": {
- "wrappy": "1"
- }
- },
- "node_modules/path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
- "dev": true
- },
- "node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- }
- },
- "dependencies": {
- "@author.io/arg": {
- "version": "1.3.23",
- "resolved": "https://registry.npmjs.org/@author.io/arg/-/arg-1.3.23.tgz",
- "integrity": "sha512-J3Ia2+HHf4rNpgz0YK6UzRqVZHZt0JXRocMCfh7tPOTK8WPbu0aLXwGHLLH4L6ySFs09V+/Zbke3rLQDzYltDw==",
- "dev": true
- },
- "@author.io/dev": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/@author.io/dev/-/dev-1.1.6.tgz",
- "integrity": "sha512-unNtw/ibtPjbkhd7IDmO4e+JDpWoxqFmuQgF+gu3LDms2Nd0k/pN+umAPaxLPNHW/r7yvaTarMYtwdZOWQsf6A==",
- "dev": true,
- "requires": {
- "@author.io/node-shell": "^1.8.2",
- "@author.io/shell": "^1.3.8",
- "chalk": "^4.1.0",
- "glob": "^7.1.6",
- "semver": "^7.3.2"
- }
- },
- "@author.io/node-shell": {
- "version": "1.8.2",
- "resolved": "https://registry.npmjs.org/@author.io/node-shell/-/node-shell-1.8.2.tgz",
- "integrity": "sha512-mnOwUASxLYV3NcSlUvjHwnLkbwhxSUcq/dwUPkawWmu5TJ6txYcU+Eub4QMyCXqpiThyiFrRc6Za89Nh+dKo0w==",
- "dev": true,
- "requires": {
- "@author.io/arg": "^1.3.8",
- "@author.io/table": "^1.0.3"
- }
- },
- "@author.io/shell": {
- "version": "1.8.13",
- "resolved": "https://registry.npmjs.org/@author.io/shell/-/shell-1.8.13.tgz",
- "integrity": "sha512-5cXWXOjilxtfdKynAyGkoPbjj5JG15JafLPxmylH61i5cvD3ZecpAhNYUwrucmCOP+EspixAY1Tlvr0DyBEjVw==",
- "dev": true
- },
- "@author.io/table": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@author.io/table/-/table-1.1.1.tgz",
- "integrity": "sha512-QvDVZnZ4qZHKrFkGi44QZBJAAkm0lsYKIrdA17ZKzrl5jUjO38qyiatSBl4ttqpWcHNJRBP8A/p7kLAOiRrK8Q==",
- "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"
- }
- },
- "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
- },
- "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"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "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
- },
- "fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
- "dev": true
- },
- "glob": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
- "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "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
- },
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "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"
- }
- },
- "once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "dev": true,
- "requires": {
- "wrappy": "1"
- }
- },
- "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
- },
- "semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
- "dev": true
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- }
- }
-}
From 3e4a034899209754ce46688d1665f660f366c3f4 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Wed, 30 Mar 2022 14:52:20 -0500
Subject: [PATCH 150/152] Refactored how middleware is applied. Resolves #11
---
package.json | 4 +--
src/base.js | 73 +++++++++++++++++++++++++++++++----------
src/command.js | 9 ++++-
src/shell.js | 10 +++++-
tests/100-regression.js | 34 ++++++++++++++++++-
5 files changed, 108 insertions(+), 22 deletions(-)
diff --git a/package.json b/package.json
index cb8fa30..43054f3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.9.1",
+ "version": "1.9.2",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "./src/index.js",
"module": "./index.js",
@@ -14,7 +14,7 @@
"test": "npm run test:node && npm run test:deno && npm run test:browser && npm run report:syntax && npm run report:size",
"test:node": "dev test -rt node tests/*.js",
"test:node:sanity": "dev test -rt node tests/01-sanity.js",
- "test:node:base": "dev test -rt node tests/02-base.js",
+ "test:node:middleware": "dev test -rt node tests/02-middleware.js",
"test:node:relationships": "dev test -rt node tests/06-relationships.js",
"test:node:metadata": "dev test -rt node tests/04-metadata.js",
"test:node:regression": "dev test -rt node tests/100-regression.js",
diff --git a/src/base.js b/src/base.js
index 460ef62..a6b064c 100644
--- a/src/base.js
+++ b/src/base.js
@@ -18,7 +18,9 @@ export default class Base {
#width = 80
#name = 'Unknown'
#middleware = new Middleware()
+ #middlewareChain = []
#trailer = new Middleware()
+ #trailerwareChain = []
#commonflags = {}
#display = {
// These are all null, representing they're NOT configured.
@@ -173,17 +175,38 @@ export default class Base {
return this.#arguments
}
},
+ applyMiddleware: {
+ enumerable: false,
+ configurable: false,
+ writable: false,
+ value: () => this.#middlewareChain.forEach(mw => this.#middleware.use(mw))
+ },
+ applyTrailerware: {
+ enumerable: false,
+ configurable: false,
+ writable: false,
+ value: () => {
+ this.#trailer = this.#trailer || new Middleware()
+ this.#trailerwareChain.forEach(mw => this.#trailer.use(mw))
+ }
+ },
initializeMiddleware: {
enumerable: false,
configurable: false,
writable: false,
- value: code => {
+ value: code => this.use(this.normalizeMiddleware(code))
+ },
+ normalizeMiddleware: {
+ enumerable: false,
+ configurable: false,
+ writable: false,
+ value: (code, type = 'middleware') => {
if (typeof code === 'string') {
- this.use(Function('return ' + code)()) // eslint-disable-line no-new-func
+ return Function('return ' + code)() // eslint-disable-line no-new-func
} else if (typeof code === 'function') {
- this.use(code)
+ return code
} else {
- throw new Error('Invalid middleware: ' + code.toString())
+ throw new Error(`Invalid ${type}: ` + code.toString())
}
}
},
@@ -191,15 +214,7 @@ export default class Base {
enumerable: false,
configurable: false,
writable: false,
- value: code => {
- if (typeof code === 'string') {
- this.trailer(Function('return ' + code)()) // eslint-disable-line no-new-func
- } else if (typeof code === 'function') {
- this.trailer(code)
- } else {
- throw new Error('Invalid trailer: ' + code.toString())
- }
- }
+ value: code => this.trailer(this.normalizeMiddleware(code, 'trailer'))
},
initializeHelpAnnotations: {
enumerable: false,
@@ -453,32 +468,56 @@ export default class Base {
}
}
+ // use () {
+ // for (const arg of arguments) {
+ // if (typeof arg !== 'function') {
+ // throw new Error(`All "use()" arguments must be valid functions.\n${arg.toString().substring(0, 50)} ${arg.toString().length > 50 ? '...' : ''}`)
+ // }
+
+ // this.#middleware.use(arg)
+ // }
+
+ // this.#processors.forEach(subCmd => subCmd.use(...arguments))
+ // }
+
use () {
for (const arg of arguments) {
if (typeof arg !== 'function') {
throw new Error(`All "use()" arguments must be valid functions.\n${arg.toString().substring(0, 50)} ${arg.toString().length > 50 ? '...' : ''}`)
}
- this.#middleware.use(arg)
+ this.#middlewareChain.push(arg)
}
this.#processors.forEach(subCmd => subCmd.use(...arguments))
}
trailer () {
- this.#trailer = this.#trailer || new Middleware()
-
for (const arg of arguments) {
if (typeof arg !== 'function') {
throw new Error(`All "trailer()" arguments must be valid functions.\n${arg.toString().substring(0, 50)} ${arg.toString().length > 50 ? '...' : ''}`)
}
- this.#trailer.use(arg)
+ this.#trailerwareChain.push(arg)
}
this.#processors.forEach(subCmd => subCmd.trailer(...arguments))
}
+ // trailer () {
+ // this.#trailer = this.#trailer || new Middleware()
+
+ // for (const arg of arguments) {
+ // if (typeof arg !== 'function') {
+ // throw new Error(`All "trailer()" arguments must be valid functions.\n${arg.toString().substring(0, 50)} ${arg.toString().length > 50 ? '...' : ''}`)
+ // }
+
+ // this.#trailer.use(arg)
+ // }
+
+ // this.#processors.forEach(subCmd => subCmd.trailer(...arguments))
+ // }
+
add () {
for (let command of arguments) {
if (!(command instanceof Command)) {
diff --git a/src/command.js b/src/command.js
index 78872b3..e4b1145 100644
--- a/src/command.js
+++ b/src/command.js
@@ -537,13 +537,20 @@ export default class Command extends Base {
arguments[0].plugins = this.plugins
if (this.shell !== null) {
- const parentMiddleware = this.shell.getCommandMiddleware(this.commandroot.replace(new RegExp(`^${this.shell.name}`, 'i'), '').trim())
+ const { shellware } = this.shell
+ if (shellware.length > 0) {
+ this.middleware.use(...shellware)
+ }
+ const parentMiddleware = this.shell.getCommandMiddleware(this.commandroot.replace(new RegExp(`^${this.shell.name}`, 'i'), '').trim())
if (parentMiddleware.length > 0) {
this.middleware.use(...parentMiddleware)
}
}
+ this.applyMiddleware()
+ this.applyTrailerware()
+
const trailers = this.trailers
if (arguments[0].help && arguments[0].help.requested) {
diff --git a/src/shell.js b/src/shell.js
index d127e16..18d6535 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -9,6 +9,7 @@ export default class Shell extends Base {
#version
#cursor = 0
#tabWidth
+ #middleware = []
#runtime = globalThis.hasOwnProperty('window') // eslint-disable-line no-prototype-builtins
? 'browser'
: (
@@ -27,7 +28,7 @@ export default class Shell extends Base {
this.__commonflags = cfg.commonflags || {}
if (cfg.hasOwnProperty('use') && Array.isArray(cfg.use)) { // eslint-disable-line no-prototype-builtins
- cfg.use.forEach(code => this.initializeMiddleware(code))
+ cfg.use.forEach(code => this.#middleware.push(this.normalizeMiddleware(code)))
}
if (cfg.hasOwnProperty('trailer') && Array.isArray(cfg.trailer)) { // eslint-disable-line no-prototype-builtins
@@ -193,6 +194,7 @@ export default class Shell extends Base {
this.#history.pop()
}
+ // The extra space is added to guarantee the pattern is recognized
let parsed = COMMAND_PATTERN.exec(input + ' ')
if (parsed === null) {
@@ -227,6 +229,8 @@ export default class Shell extends Base {
return Command.stderr('Command not found.')
}
+ // "terminal command" refers to the last command in the input
+ // string (i.e. last subcommand)
const term = processor.getTerminalCommand(args)
if (typeof callback === 'function') {
@@ -236,6 +240,10 @@ export default class Shell extends Base {
return await Command.reply(await term.command.run(term.arguments, callback, reference))
}
+ get shellware () {
+ return this.#middleware
+ }
+
getCommandMiddleware (cmd) {
const results = []
cmd.split(/\s+/).forEach((c, i, a) => {
diff --git a/tests/100-regression.js b/tests/100-regression.js
index f3d916f..e48e7f7 100644
--- a/tests/100-regression.js
+++ b/tests/100-regression.js
@@ -1,5 +1,5 @@
import test from 'tappedout'
-import { Shell } from '@author.io/shell'
+import { Shell, Command } from '@author.io/shell'
// The range error was caused by the underlying table library.
// When a default help message was generated, a negative column
@@ -155,3 +155,35 @@ test('Exec method should return callback value', async t => {
t.end()
})
})
+
+test('Shell level middleware should execeute before command level middleware', t => {
+ let status = []
+ const cmd = new Command({
+ name: 'run',
+ async handler(meta) {
+ return meta.input
+ }
+ })
+
+ cmd.use(async function(meta, next) {
+ status.push('2')
+ next()
+ })
+
+ const sh = new Shell({
+ name: 'test',
+ use: [
+ (meta, next) => {
+ status.push('1')
+ next()
+ }
+ ],
+ commands: [cmd]
+ })
+
+ sh.exec(['run', 'other'], data => {
+ t.expect(2, status.length, 'corrent number of middleware functions executed')
+ t.expect('1,2', status.join(','), 'middleware runs in correct order')
+ t.end()
+ })
+})
From 0ff6009ebc0b3bd18adee9aa9d6161008a6746f4 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 18 Jul 2022 18:00:27 -0500
Subject: [PATCH 151/152] Cleanup dependencies
---
.github/workflows/deploy.yml | 1 +
README.md | 36 ------------------
package.json | 12 +++---
src/base.js | 73 +++++++++---------------------------
src/command.js | 35 ++++++-----------
src/shell.js | 30 ++-------------
tests/04-metadata.js | 27 -------------
tests/100-regression.js | 70 +---------------------------------
8 files changed, 40 insertions(+), 244 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 52a56cb..c1699dc 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -105,6 +105,7 @@ jobs:
id: build_release
if: steps.create_release.outputs.id != ''
run: |
+ ln -s /node_modules ./node_modules
dev build --pack --mode ci --peer
cp -rf .dist ./dist
diff --git a/README.md b/README.md
index 12b49ae..e9e8d43 100644
--- a/README.md
+++ b/README.md
@@ -331,42 +331,6 @@ _Output:_
> Notice the values from the known flags are _first_.
-### Custom Handler Data References
-
-When building JavaScript applications, it may be desirable to pass data references to the `exec` method, making them available to handlers. For example:
-
-```javascript
-const sh = new Shell({
- name: 'test',
- commands: [{
- name: 'run',
- async handler (meta) {
- return meta.reference.test // reference data
- }
- }]
-})
-
-const ref = { test: true }
-const result = await sh.exec('run', { reference: ref })
-```
-
-In the command above, the reference data (second to last line) is passed to the `exec()` method using a special object as the second argument. This object is made available in the handler using the `meta.reference` attribute.
-
-If a callback needs to be defined, the second argument of the `exec` method must have an attribute called `callback`, i.e.:
-
-```javascript
-const ref = {
- test: true
-}
-
-const result = await sh.exec('run', {
- reference: ref,
- callback: function () {...}
-})
-```
-
-The callback method is _not_ available in the `meta.reference`, but the callback will be executed when `exec()` is executed.
-
## Plugins
Plugins expose functions, objects, and primitives to shell handlers.
diff --git a/package.json b/package.json
index 43054f3..3c6ef6e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.9.2",
+ "version": "1.8.18",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "./src/index.js",
"module": "./index.js",
@@ -14,9 +14,8 @@
"test": "npm run test:node && npm run test:deno && npm run test:browser && npm run report:syntax && npm run report:size",
"test:node": "dev test -rt node tests/*.js",
"test:node:sanity": "dev test -rt node tests/01-sanity.js",
- "test:node:middleware": "dev test -rt node tests/02-middleware.js",
+ "test:node:base": "dev test -rt node tests/02-base.js",
"test:node:relationships": "dev test -rt node tests/06-relationships.js",
- "test:node:metadata": "dev test -rt node tests/04-metadata.js",
"test:node:regression": "dev test -rt node tests/100-regression.js",
"test:browser": "dev test -rt browser tests/*.js",
"test:browser:sanity": "dev test -rt browser tests/01-sanity.js",
@@ -24,13 +23,13 @@
"test:deno": "dev test -rt deno tests/*.js",
"test:deno:sanity": "dev test -rt deno tests/01-sanity.js",
"manually": "dev test -rt manual tests/*.js",
- "build": "dev build",
+ "build": "dev build --verbose",
"report:syntax": "dev report syntax --pretty",
"report:size": "dev report size ./.dist/**/*.js ./.dist/**/*.js.map",
"report:compat": "dev report compatibility ./src/**/*.js",
"report:preview": "npm pack --dry-run && echo \"==============================\" && echo \"This report shows what will be published to the module registry. Pay attention to the tarball contents and assure no sensitive files will be published.\"",
"ci": "dev test --verbose --mode ci --peer -rt node tests/*.js && dev test --mode ci -rt deno tests/*.js && dev test --mode ci -rt browser tests/*.js",
- "x": "dev build --verbose --mode ci --peer"
+ "x": "esbuild ./src/index.js --format esm --bundle --minify --outfile=.dist/shell/index.js"
},
"keywords": [
"cli",
@@ -55,7 +54,7 @@
"./node_modules/@author.io/table:/node_modules/@author.io/table"
],
"alias": {
- "@author.io/shell": "/app/.dist/shell/index.js",
+ "@author.io/shell": "/app/.dist/@author.io/shell/index.js",
"@author.io/arg": "/node_modules/@author.io/arg/index.js",
"@author.io/table": "/node_modules/@author.io/table/index.js"
},
@@ -98,6 +97,7 @@
]
},
"devDependencies": {
+ "esbuild": "^0.14.10",
"@author.io/arg": "^1.3.23",
"@author.io/dev": "^1.1.5",
"@author.io/table": "^1.0.3"
diff --git a/src/base.js b/src/base.js
index a6b064c..460ef62 100644
--- a/src/base.js
+++ b/src/base.js
@@ -18,9 +18,7 @@ export default class Base {
#width = 80
#name = 'Unknown'
#middleware = new Middleware()
- #middlewareChain = []
#trailer = new Middleware()
- #trailerwareChain = []
#commonflags = {}
#display = {
// These are all null, representing they're NOT configured.
@@ -175,38 +173,17 @@ export default class Base {
return this.#arguments
}
},
- applyMiddleware: {
- enumerable: false,
- configurable: false,
- writable: false,
- value: () => this.#middlewareChain.forEach(mw => this.#middleware.use(mw))
- },
- applyTrailerware: {
- enumerable: false,
- configurable: false,
- writable: false,
- value: () => {
- this.#trailer = this.#trailer || new Middleware()
- this.#trailerwareChain.forEach(mw => this.#trailer.use(mw))
- }
- },
initializeMiddleware: {
enumerable: false,
configurable: false,
writable: false,
- value: code => this.use(this.normalizeMiddleware(code))
- },
- normalizeMiddleware: {
- enumerable: false,
- configurable: false,
- writable: false,
- value: (code, type = 'middleware') => {
+ value: code => {
if (typeof code === 'string') {
- return Function('return ' + code)() // eslint-disable-line no-new-func
+ this.use(Function('return ' + code)()) // eslint-disable-line no-new-func
} else if (typeof code === 'function') {
- return code
+ this.use(code)
} else {
- throw new Error(`Invalid ${type}: ` + code.toString())
+ throw new Error('Invalid middleware: ' + code.toString())
}
}
},
@@ -214,7 +191,15 @@ export default class Base {
enumerable: false,
configurable: false,
writable: false,
- value: code => this.trailer(this.normalizeMiddleware(code, 'trailer'))
+ value: code => {
+ if (typeof code === 'string') {
+ this.trailer(Function('return ' + code)()) // eslint-disable-line no-new-func
+ } else if (typeof code === 'function') {
+ this.trailer(code)
+ } else {
+ throw new Error('Invalid trailer: ' + code.toString())
+ }
+ }
},
initializeHelpAnnotations: {
enumerable: false,
@@ -468,56 +453,32 @@ export default class Base {
}
}
- // use () {
- // for (const arg of arguments) {
- // if (typeof arg !== 'function') {
- // throw new Error(`All "use()" arguments must be valid functions.\n${arg.toString().substring(0, 50)} ${arg.toString().length > 50 ? '...' : ''}`)
- // }
-
- // this.#middleware.use(arg)
- // }
-
- // this.#processors.forEach(subCmd => subCmd.use(...arguments))
- // }
-
use () {
for (const arg of arguments) {
if (typeof arg !== 'function') {
throw new Error(`All "use()" arguments must be valid functions.\n${arg.toString().substring(0, 50)} ${arg.toString().length > 50 ? '...' : ''}`)
}
- this.#middlewareChain.push(arg)
+ this.#middleware.use(arg)
}
this.#processors.forEach(subCmd => subCmd.use(...arguments))
}
trailer () {
+ this.#trailer = this.#trailer || new Middleware()
+
for (const arg of arguments) {
if (typeof arg !== 'function') {
throw new Error(`All "trailer()" arguments must be valid functions.\n${arg.toString().substring(0, 50)} ${arg.toString().length > 50 ? '...' : ''}`)
}
- this.#trailerwareChain.push(arg)
+ this.#trailer.use(arg)
}
this.#processors.forEach(subCmd => subCmd.trailer(...arguments))
}
- // trailer () {
- // this.#trailer = this.#trailer || new Middleware()
-
- // for (const arg of arguments) {
- // if (typeof arg !== 'function') {
- // throw new Error(`All "trailer()" arguments must be valid functions.\n${arg.toString().substring(0, 50)} ${arg.toString().length > 50 ? '...' : ''}`)
- // }
-
- // this.#trailer.use(arg)
- // }
-
- // this.#processors.forEach(subCmd => subCmd.trailer(...arguments))
- // }
-
add () {
for (let command of arguments) {
if (!(command instanceof Command)) {
diff --git a/src/command.js b/src/command.js
index e4b1145..9666458 100644
--- a/src/command.js
+++ b/src/command.js
@@ -1,5 +1,5 @@
-// import { Parser } from '../../../@author.io/arg/index.js'
-import { Parser } from '@author.io/arg'
+import { Parser } from '../node_modules/@author.io/arg/index.js'
+// import { Parser } from '@author.io/arg'
import Shell from './shell.js'
import Base from './base.js'
import { METHOD_PATTERN, FLAG_PATTERN, STRIP_QUOTE_PATTERN } from './utility.js'
@@ -529,28 +529,21 @@ export default class Command extends Base {
return data
}
- async run (input, callback, reference = undefined) {
+ async run (input, callback) {
const fn = (this.#fn || this.defaultHandler).bind(this)
- const metadata = typeof input === 'string' ? this.parse(input) : input
+ const data = typeof input === 'string' ? this.parse(input) : input
arguments[0] = this.deepParse(input)
arguments[0].plugins = this.plugins
if (this.shell !== null) {
- const { shellware } = this.shell
- if (shellware.length > 0) {
- this.middleware.use(...shellware)
- }
-
const parentMiddleware = this.shell.getCommandMiddleware(this.commandroot.replace(new RegExp(`^${this.shell.name}`, 'i'), '').trim())
+
if (parentMiddleware.length > 0) {
this.middleware.use(...parentMiddleware)
}
}
- this.applyMiddleware()
- this.applyTrailerware()
-
const trailers = this.trailers
if (arguments[0].help && arguments[0].help.requested) {
@@ -565,7 +558,7 @@ export default class Command extends Base {
// No subcommand was recognized
if (this.middleware.size > 0) {
- this.middleware.run(arguments[0], async meta => await Command.reply(fn(Object.assign(meta, { reference }), callback)))
+ this.middleware.run(arguments[0], async meta => await Command.reply(fn(meta, callback)))
if (trailers.size > 0) {
trailers.run(arguments[0])
@@ -575,14 +568,12 @@ export default class Command extends Base {
}
// Command.reply(fn(arguments[0], callback))
- metadata.plugins = this.plugins
- const result = await Command.reply(fn(Object.assign(metadata, { reference }), callback))
+ data.plugins = this.plugins
+ Command.reply(fn(data, callback))
if (trailers.size > 0) {
trailers.run(arguments[0])
}
-
- return result
}
static stderr (err) {
@@ -594,15 +585,13 @@ export default class Command extends Base {
}
static reply (callback) {
- return new Promise(async (resolve, reject) => { // eslint-disable-line no-async-promise-executor
+ return new Promise((resolve, reject) => {
try {
if (typeof callback === 'function') {
- resolve(callback())
- } else if (callback instanceof Promise) {
- callback.then(resolve).catch(reject)
- } else {
- resolve(...arguments)
+ callback()
}
+
+ resolve()
} catch (e) {
reject(e)
}
diff --git a/src/shell.js b/src/shell.js
index 18d6535..c5bad75 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -9,7 +9,6 @@ export default class Shell extends Base {
#version
#cursor = 0
#tabWidth
- #middleware = []
#runtime = globalThis.hasOwnProperty('window') // eslint-disable-line no-prototype-builtins
? 'browser'
: (
@@ -28,7 +27,7 @@ export default class Shell extends Base {
this.__commonflags = cfg.commonflags || {}
if (cfg.hasOwnProperty('use') && Array.isArray(cfg.use)) { // eslint-disable-line no-prototype-builtins
- cfg.use.forEach(code => this.#middleware.push(this.normalizeMiddleware(code)))
+ cfg.use.forEach(code => this.initializeMiddleware(code))
}
if (cfg.hasOwnProperty('trailer') && Array.isArray(cfg.trailer)) { // eslint-disable-line no-prototype-builtins
@@ -165,22 +164,11 @@ export default class Shell extends Base {
}
async exec (input, callback) {
- // Optionally apply reference data. Only for advanced use
- // in applications (not strict CLIs).
- let reference
- if (typeof callback === 'object') {
- if (!callback.hasOwnProperty('reference') && !callback.hasOwnProperty('callback')) { // eslint-disable-line no-prototype-builtins
- throw new Error('exec method data references require a reference and/or callback attribute - recognized: ' + Object.keys(callback).join(', '))
- }
- reference = callback.reference
- callback = callback.callback
- }
-
// The array check exists because people are passing process.argv.slice(2) into this
// method, often forgetting to join the values into a string.
if (Array.isArray(input)) {
input = input.map(i => {
- if (i.indexOf(' ') >= 0 && !/^[\"\'].+ [\"\']$/.test(i)) { // eslint-disable-line no-useless-escape
+ if (i.indexOf(' ') >= 0 && !/^[\"\'].+ [\"\']$/.test(i)) {
return `"${i}"`
} else {
return i
@@ -194,7 +182,6 @@ export default class Shell extends Base {
this.#history.pop()
}
- // The extra space is added to guarantee the pattern is recognized
let parsed = COMMAND_PATTERN.exec(input + ' ')
if (parsed === null) {
@@ -229,19 +216,8 @@ export default class Shell extends Base {
return Command.stderr('Command not found.')
}
- // "terminal command" refers to the last command in the input
- // string (i.e. last subcommand)
const term = processor.getTerminalCommand(args)
-
- if (typeof callback === 'function') {
- return callback(await Command.reply(await term.command.run(term.arguments, callback, reference))) // eslint-disable-line standard/no-callback-literal
- }
-
- return await Command.reply(await term.command.run(term.arguments, callback, reference))
- }
-
- get shellware () {
- return this.#middleware
+ return await Command.reply(await term.command.run(term.arguments, callback))
}
getCommandMiddleware (cmd) {
diff --git a/tests/04-metadata.js b/tests/04-metadata.js
index c44d624..925ec13 100644
--- a/tests/04-metadata.js
+++ b/tests/04-metadata.js
@@ -159,30 +159,3 @@ test('Ordered Named Arguments', t => {
shell.exec('account create test@domain.com pwd')
})
-
-
-test('Application reference data', async t => {
- const data = { test: true }
- const sh = new Shell({
- name: 'test',
- commands: [{
- name: 'run',
- async handler (meta) {
- return meta.reference.test
- }
- }]
- })
-
- const result = await sh.exec('run', { reference: data })
-
- t.expect(result, true, 'reference data detected in handler')
-
- try {
- await sh.exec('run', { demo: data })
- t.fail('failure to provide reference and callback throws error')
- } catch (e) {
- t.pass('failure to provide reference and callback throws error')
- }
-
- t.end()
-})
diff --git a/tests/100-regression.js b/tests/100-regression.js
index e48e7f7..762f27c 100644
--- a/tests/100-regression.js
+++ b/tests/100-regression.js
@@ -1,5 +1,5 @@
import test from 'tappedout'
-import { Shell, Command } from '@author.io/shell'
+import { Shell } from '@author.io/shell'
// The range error was caused by the underlying table library.
// When a default help message was generated, a negative column
@@ -119,71 +119,3 @@ test('Accept arrays with values containing spaces', t => {
const argv = ["run", "-c", "a connection", "--save"]
sh.exec(argv).catch(t.fail)
})
-
-test('Exec method should return promise value', async t => {
- const sh = new Shell({
- name: 'test',
- commands: [{
- name: 'run',
- async handler(meta) {
- return meta.input
- }
- }]
- })
-
- const argv = ['run', 'example']
- const result = await sh.exec(argv).catch(t.fail)
-
- t.expect(result, 'example', 'returns command promise results')
- t.end()
-})
-
-test('Exec method should return callback value', async t => {
- const sh = new Shell({
- name: 'test',
- commands: [{
- name: 'run',
- async handler(meta) {
- return meta.input
- }
- }]
- })
-
- const argv = ['run', 'other']
- sh.exec(argv, data => {
- t.expect(data, 'other', 'returns command callback results')
- t.end()
- })
-})
-
-test('Shell level middleware should execeute before command level middleware', t => {
- let status = []
- const cmd = new Command({
- name: 'run',
- async handler(meta) {
- return meta.input
- }
- })
-
- cmd.use(async function(meta, next) {
- status.push('2')
- next()
- })
-
- const sh = new Shell({
- name: 'test',
- use: [
- (meta, next) => {
- status.push('1')
- next()
- }
- ],
- commands: [cmd]
- })
-
- sh.exec(['run', 'other'], data => {
- t.expect(2, status.length, 'corrent number of middleware functions executed')
- t.expect('1,2', status.join(','), 'middleware runs in correct order')
- t.end()
- })
-})
From d4bdb7689efbd0c688b5392f2f474e7e92f5fcf6 Mon Sep 17 00:00:00 2001
From: Corey Butler
Date: Mon, 18 Jul 2022 18:04:37 -0500
Subject: [PATCH 152/152] Update version
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 3c6ef6e..40f0d90 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@author.io/shell",
- "version": "1.8.18",
+ "version": "1.9.2",
"description": "A micro-framework for creating CLI-like experiences. This supports Node.js and browsers.",
"main": "./src/index.js",
"module": "./index.js",