From e29f085961c3b4ce656f935f928793918c257b57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Da=C3=9Fler?= Date: Sun, 30 Jun 2024 15:28:25 +0200 Subject: [PATCH] feat(): Optimize docstring parser for commander and make depending changes --- README.md | 9 ++ log | 18 +++- package-lock.json | 230 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 - pm | 31 +------ pm-install | 32 ++----- pm-list | 12 +-- pnpm-lock.yaml | 183 ------------------------------------ this | 155 ++++++++++++++++++++----------- 9 files changed, 368 insertions(+), 303 deletions(-) create mode 100644 package-lock.json delete mode 100644 pnpm-lock.yaml diff --git a/README.md b/README.md index 8793fc2..72c68ed 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,12 @@ https://unix.stackexchange.com/questions/65235/universal-node-js-shebang ## Set location for npm packages with repl sessions https://sabljakovich.medium.com/how-to-use-npm-packages-with-node-js-repl-sessions-cd77300ebfe2 + +## Dependencies versionn + +The iSH-App on iOS has the following latest versions available + +- nodejs v16.11.1 +- npm v7.17.0 + +These versions are deprecated, but if we want to use these scripts on iSH, we have to make sure they run on that outdated versions. diff --git a/log b/log index 21f3a31..7c648dd 100755 --- a/log +++ b/log @@ -13,7 +13,8 @@ class Log extends This { echo(message) { /** - * @command + * @program() + * @command() * @argument('') */ console.log(message); @@ -21,7 +22,8 @@ class Log extends This { success(message) { /** - * @command + * @program() + * @command() * @argument('') */ console.log(this._echoInGreen(message)); @@ -29,7 +31,8 @@ class Log extends This { info(message) { /** - * @command + * @program() + * @command() * @argument('') */ console.log(`[INFO] ${message}`); @@ -37,7 +40,8 @@ class Log extends This { warn(message) { /** - * @command + * @program() + * @command() * @argument('') */ console.warn(`[WARN] ${this._echoInYellow(message)}`); @@ -45,13 +49,17 @@ class Log extends This { error(message) { /** - * @command + * @program() + * @command() * @argument('') */ console.error(`[ERR] ${this._echoInRed(message)}`); } start() { + /** + * @program() + */ this.program.parse(); if (Object.keys(this.program.opts()).length || this.program.args.length) { diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..89be523 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,230 @@ +{ + "name": "once-nodejs", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "commander": "^12.1.0", + "shelljs": "^0.8.5" + }, + "devDependencies": { + "prettier": "^3.3.2" + } + }, + "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==" + }, + "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==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "engines": { + "node": ">=18" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "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==" + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-core-module": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", + "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "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": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "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": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/prettier": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + } + } +} diff --git a/package.json b/package.json index 7768209..8700838 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,6 @@ }, "dependencies": { "commander": "^12.1.0", - "omelette": "^0.4.17", "shelljs": "^0.8.5" }, "devDependencies": { diff --git a/pm b/pm index 2cc3798..b0e6159 100755 --- a/pm +++ b/pm @@ -1,7 +1,6 @@ #!/usr/bin/env node const This = require('./this'); -const util = require('util'); // Example of subcommands which are implemented as stand-alone executable files. // @@ -19,6 +18,7 @@ class Pm extends This { install() { /** + * @program() * @command('install one or more packages') * @alias('i') */ @@ -27,6 +27,7 @@ class Pm extends This { search() { /** + * @program() * @command('search with optional query') * @alias('s') */ @@ -35,6 +36,7 @@ class Pm extends This { update() { /** + * @program() * @command('update installed packages') * @executable('myUpdateSubCommand') */ @@ -43,6 +45,7 @@ class Pm extends This { list() { /** + * @program() * @command('list packages installed') */ // Calls stand-alone excutable `pm-list` because of @command() in docstring @@ -118,31 +121,7 @@ class Pm extends This { } start() { - this.program.parse(); - - if (Object.keys(this.program.opts()).length || this.program.args.length) { - // Debugging commander options and arguments - const opts = util.inspect(this.program.opts(), { depth: null, colors: true, showHidden: true }); - const args = util.inspect(this.program.args, { depth: null, colors: true, showHidden: true }); - this.execCmd(`${this.workingDir}/log echo 'Options: ${opts}'`); - this.execCmd(`${this.workingDir}/log echo 'Remaining arguments: ${args}'`); - } else { - this.program.outputHelp(); - } - - // applies logDecorator to this.discovery() and binds it to 'this' to maintain the correct context - //const logDecoratedDiscovery = this._logDecorator(this.discovery).bind(this); - //logDecoratedDiscovery(); - - // Try the following on macOS or Linux: - // ./examples/pm - // - // Try the following: - // ./pm - // ./pm help install - // ./pm install -h - // ./pm install foo bar baz - // ./pm install foo bar baz --force + super.start(); } } diff --git a/pm-install b/pm-install index acdf0ce..653761a 100755 --- a/pm-install +++ b/pm-install @@ -1,39 +1,23 @@ #!/usr/bin/env node const This = require('./this'); -const util = require('util'); class PmInstall extends This { constructor() { super(); this.version = '0.0.1'; - this.description = 'Install package with fake package manager' + this.description = 'Install package with fake package manager'; super.init(); // initialize commander with overridden version and description } start() { - // Usage - const pmInstall = new PmInstall(); - // Output: Methods of ExampleClass: [ 'methodOne', 'methodTwo' ] - // Properties of ExampleClass: [ 'propertyOne', 'propertyTwo', 'version' ] and Version: 1.1.0 - // pmInstall.discovery(); - - this.program - .usage('-n 3 32 -l x y z -- op') - .option('-n, --number ', 'specify numbers') - .option('-l, --letter [letters...]', 'specify letters') - - this.program.parse(); - - if (Object.keys(this.program.opts()).length || this.program.args.length) { - // Debugging commander options and arguments - const opts = util.inspect(this.program.opts(), { depth: null, colors: true, showHidden: true }); - const args = util.inspect(this.program.args, { depth: null, colors: true, showHidden: true }); - this.execCmd(`${this.workingDir}/log echo 'Options: ${opts}'`); - this.execCmd(`${this.workingDir}/log echo 'Remaining arguments: ${args}'`); - } else { - this.program.outputHelp(); - } + /** + * @program() + * @usage('-n 3 32 -l x y z -- op') + * @option('-n, --number ', 'specify numbers') + * @option('-l, --letter [letters...]', 'specify letters') + */ + super.start(); } } diff --git a/pm-list b/pm-list index 2ef0455..9e0f6e2 100755 --- a/pm-list +++ b/pm-list @@ -1,23 +1,17 @@ #!/usr/bin/env node const This = require('./this'); -const { Command } = require('commander'); -const program = new Command(); class PmList extends This { constructor() { super(); this.version = '0.0.1'; + this.description = 'List packages of fake package manager'; + super.init(); // initialize commander with overridden version and description } start() { - // Usage - const pmList = new PmList(); - // Output: Methods of ExampleClass: [ 'methodOne', 'methodTwo' ] - // Properties of ExampleClass: [ 'propertyOne', 'propertyTwo', 'version' ] and Version: 1.1.0 - // pmList.discovery(); - - program.name(this.scriptName).version('0.0.1').description('List packages of fake package manager').outputHelp(); + super.start(); } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index a6ff437..0000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,183 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -dependencies: - commander: - specifier: ^12.1.0 - version: 12.1.0 - omelette: - specifier: ^0.4.17 - version: 0.4.17 - shelljs: - specifier: ^0.8.5 - version: 0.8.5 - -devDependencies: - prettier: - specifier: ^3.3.2 - version: 3.3.2 - -packages: - /balanced-match@1.0.2: - resolution: - { integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== } - dev: false - - /brace-expansion@1.1.11: - resolution: - { integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== } - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: false - - /commander@12.1.0: - resolution: - { integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== } - engines: { node: '>=18' } - dev: false - - /concat-map@0.0.1: - resolution: - { integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== } - dev: false - - /fs.realpath@1.0.0: - resolution: - { integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== } - dev: false - - /function-bind@1.1.2: - resolution: - { integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== } - dev: false - - /glob@7.2.3: - resolution: - { integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== } - deprecated: Glob versions prior to v9 are no longer supported - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: false - - /hasown@2.0.2: - resolution: - { integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== } - engines: { node: '>= 0.4' } - dependencies: - function-bind: 1.1.2 - dev: false - - /inflight@1.0.6: - resolution: - { integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== } - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: false - - /inherits@2.0.4: - resolution: - { integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== } - dev: false - - /interpret@1.4.0: - resolution: - { integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== } - engines: { node: '>= 0.10' } - dev: false - - /is-core-module@2.14.0: - resolution: - { integrity: sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A== } - engines: { node: '>= 0.4' } - dependencies: - hasown: 2.0.2 - dev: false - - /minimatch@3.1.2: - resolution: - { integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== } - dependencies: - brace-expansion: 1.1.11 - dev: false - - /omelette@0.4.17: - resolution: - { integrity: sha512-UlU69G6Bhu0XFjw3tjFZ0qyiMUjAOR+rdzblA1nLQ8xiqFtxOVlkhM39BlgTpLFx9fxkm6rnxNNRsS5GxE/yww== } - engines: { node: '>=0.8.0' } - dev: false - - /once@1.4.0: - resolution: - { integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== } - dependencies: - wrappy: 1.0.2 - dev: false - - /path-is-absolute@1.0.1: - resolution: - { integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== } - engines: { node: '>=0.10.0' } - dev: false - - /path-parse@1.0.7: - resolution: - { integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== } - dev: false - - /prettier@3.3.2: - resolution: - { integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA== } - engines: { node: '>=14' } - hasBin: true - dev: true - - /rechoir@0.6.2: - resolution: - { integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== } - engines: { node: '>= 0.10' } - dependencies: - resolve: 1.22.8 - dev: false - - /resolve@1.22.8: - resolution: - { integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== } - hasBin: true - dependencies: - is-core-module: 2.14.0 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - dev: false - - /shelljs@0.8.5: - resolution: - { integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== } - engines: { node: '>=4' } - hasBin: true - dependencies: - glob: 7.2.3 - interpret: 1.4.0 - rechoir: 0.6.2 - dev: false - - /supports-preserve-symlinks-flag@1.0.0: - resolution: - { integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== } - engines: { node: '>= 0.4' } - dev: false - - /wrappy@1.0.2: - resolution: - { integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== } - dev: false diff --git a/this b/this index dc8c866..53959ad 100644 --- a/this +++ b/this @@ -3,6 +3,7 @@ const path = require('path'); const { Command } = require('commander'); const shell = require('shelljs'); +const util = require('util'); class This { constructor() { @@ -60,8 +61,20 @@ class This { } start() { - // Not implemented, so it needs to be overridden! - console.warn(this._echoInYellow(`Method ${this._getCurrentFunctionName()} not implemented!`)); + /** + * @program() + */ + this.program.parse(); + + if (Object.keys(this.program.opts()).length || this.program.args.length) { + // Debugging commander options and arguments + const opts = util.inspect(this.program.opts(), { depth: null, colors: true, showHidden: true }); + const args = util.inspect(this.program.args, { depth: null, colors: true, showHidden: true }); + this.execCmd(`${this.workingDir}/log echo 'Options: ${opts}'`); + this.execCmd(`${this.workingDir}/log echo 'Remaining arguments: ${args}'`); + } else { + this.program.outputHelp(); + } } execCmd(cmd) { @@ -102,11 +115,22 @@ class This { // Utility function to extract docstring from a function, e.g. // + // start() { + // /** + // * @program() + // * @usage([options] [command]) + // * @option('-d, --debug', 'Enable debug mode') + // .. + // } + // + // // echo(str) { // /** - // @command - // @argument('') - // */ + // * @program() + // * @command() + // * @argument('') + // * @option('-c, --color ', 'Prints in color mode') + // */ // console.log(str); // } // @@ -128,66 +152,87 @@ class This { } // Extract command and arguments - const commandMatch = docString.match(/@command(?:\('([^']*)'\))?/); - const aliasMatch = docString.match(/@alias\('(.+?)'\)/); - const argumentsMatch = /@argument\('(.+?)'\)/g; - const optionsMatch = /@option\('(.+?)'\)/g; - const defaultMatch = docString.match(/@default/); - const executableMatch = docString.match(/@executable\('(.+?)'\)/); + const programRegex = /@program\(\)/; + const usageRegex = /@usage\('(.+?)'\)/; + const commandRegex = /@command(?:\('(.+?)'\))?/; + const aliasRegex = /@alias\('(.+?)'\)/; + const argumentsRegex = /@argument\('(.+?)'\)/g; + const optionsRegex = /@option\('(?.+?)',\s*'(?.+?)'(?:,\s*'(?.+?)')?\)/g; + const defaultRegex = /@default/; + const executableRegex = /@executable\('(.+?)'\)/; - if (!commandMatch) { - // No @command tag found + // get regex matches with capture groups + const programMatch = docString.match(programRegex); + const usageMatch = docString.match(usageRegex); + const commandMatch = docString.match(commandRegex); + const aliasMatch = docString.match(aliasRegex); + const defaultMatch = docString.match(defaultRegex); + const executableMatch = docString.match(executableRegex); + + if (!programMatch) { + // No @program() tag found return; } - const commandName = fn.name; - const commandDescription = commandMatch ? commandMatch[1] : ''; - const alias = aliasMatch ? aliasMatch[1] : ''; - const defaultCommand = defaultMatch ? true : false; - const executable = executableMatch ? executableMatch[1] : ''; + if (commandMatch) { + // Generate the commander statement + const commandName = fn.name; + const commandDescription = commandMatch ? commandMatch[1] : ''; + const alias = aliasMatch ? aliasMatch[1] : ''; + const defaultCommand = defaultMatch ? true : false; + const executable = executableMatch ? executableMatch[1] : ''; - // Generate the commander statement - // Get the function reference - const func = this[commandName].bind(this); + // Get the function reference + const func = this[commandName].bind(this); - // Create a command - // When `.command()` is invoked with a description argument, - // this tells Commander that you're going to use a stand-alone executable for the subcommand. - let command; - if (commandDescription) { - command = this.program.command(commandName, commandDescription, { - isDefault: defaultCommand, - executableFile: executable, - }); + // Create a command + // See https://github.com/tj/commander.js?tab=readme-ov-file#quick-start + // When `.command()` is invoked with a description argument, + // this tells Commander that you're going to use a stand-alone executable for the subcommand. + let command; + if (commandDescription) { + // build stand-alone command + command = this.program.command(commandName, commandDescription, { + isDefault: defaultCommand, + executableFile: executable, + }); - if (alias) { - command.alias(alias); + if (alias) { + command.alias(alias); + } + } else { + // build command with function name as action + command = this.program.command(commandName, { isDefault: defaultCommand }); + + // Set the action for the command + command.action((arg) => { + func(arg); + }); + } + + // If the commandName expects arguments, we add them here + (docString.match(argumentsRegex) || []) + .map((e) => e.replace(argumentsRegex, '$1')) + .forEach((arg) => { + command.argument(arg); + }); + + // If the commandName expects options, we add them here + // See https://github.com/tj/commander.js?tab=readme-ov-file#options + for (const match of docString.matchAll(optionsRegex)) { + command.option(match.groups['flag'], match.groups['description'], match.groups['defaultValue']); } } else { - command = this.program.command(commandName, { isDefault: defaultCommand }); + // Add usage + if (usageMatch) { + this.program.usage(usageMatch[1]); + } - // Set the action for the command - command.action((arg) => { - func(arg); - }); - } - - // If the commandName expects arguments, we add them here - let argMatch; - while ((argMatch = argumentsMatch.exec(docString)) !== null) { - command.argument(argMatch[1]); - } - - // If the commandName expects options, we add them here - let optMatch; - while ((optMatch = optionsMatch.exec(docString)) !== null) { - command.option(optMatch[1]); - } - } - - _addMethodsToClass(cls, metadata) { - if (cls) { - cls.commands.push(metadata); + // If the program expects options, we add them here + // See https://github.com/tj/commander.js?tab=readme-ov-file#options + for (const match of docString.matchAll(optionsRegex)) { + this.program.option(match.groups['flag'], match.groups['description'], match.groups['defaultValue']); + } } }