WIP: Merge 'dev' into 'main' #1

Draft
ID19810919hisaDClr wants to merge 12 commits from dev into main
9 changed files with 368 additions and 303 deletions
Showing only changes of commit e29f085961 - Show all commits

View File

@ -15,3 +15,12 @@ https://unix.stackexchange.com/questions/65235/universal-node-js-shebang
## Set location for npm packages with repl sessions ## Set location for npm packages with repl sessions
https://sabljakovich.medium.com/how-to-use-npm-packages-with-node-js-repl-sessions-cd77300ebfe2 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.

18
log
View File

@ -13,7 +13,8 @@ class Log extends This {
echo(message) { echo(message) {
/** /**
* @command * @program()
* @command()
* @argument('<message>') * @argument('<message>')
*/ */
console.log(message); console.log(message);
@ -21,7 +22,8 @@ class Log extends This {
success(message) { success(message) {
/** /**
* @command * @program()
* @command()
* @argument('<message>') * @argument('<message>')
*/ */
console.log(this._echoInGreen(message)); console.log(this._echoInGreen(message));
@ -29,7 +31,8 @@ class Log extends This {
info(message) { info(message) {
/** /**
* @command * @program()
* @command()
* @argument('<message>') * @argument('<message>')
*/ */
console.log(`[INFO] ${message}`); console.log(`[INFO] ${message}`);
@ -37,7 +40,8 @@ class Log extends This {
warn(message) { warn(message) {
/** /**
* @command * @program()
* @command()
* @argument('<message>') * @argument('<message>')
*/ */
console.warn(`[WARN] ${this._echoInYellow(message)}`); console.warn(`[WARN] ${this._echoInYellow(message)}`);
@ -45,13 +49,17 @@ class Log extends This {
error(message) { error(message) {
/** /**
* @command * @program()
* @command()
* @argument('<message>') * @argument('<message>')
*/ */
console.error(`[ERR] ${this._echoInRed(message)}`); console.error(`[ERR] ${this._echoInRed(message)}`);
} }
start() { start() {
/**
* @program()
*/
this.program.parse(); this.program.parse();
if (Object.keys(this.program.opts()).length || this.program.args.length) { if (Object.keys(this.program.opts()).length || this.program.args.length) {

230
package-lock.json generated Normal file
View File

@ -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=="
}
}
}

View File

@ -4,7 +4,6 @@
}, },
"dependencies": { "dependencies": {
"commander": "^12.1.0", "commander": "^12.1.0",
"omelette": "^0.4.17",
"shelljs": "^0.8.5" "shelljs": "^0.8.5"
}, },
"devDependencies": { "devDependencies": {

31
pm
View File

@ -1,7 +1,6 @@
#!/usr/bin/env node #!/usr/bin/env node
const This = require('./this'); const This = require('./this');
const util = require('util');
// Example of subcommands which are implemented as stand-alone executable files. // Example of subcommands which are implemented as stand-alone executable files.
// //
@ -19,6 +18,7 @@ class Pm extends This {
install() { install() {
/** /**
* @program()
* @command('install one or more packages') * @command('install one or more packages')
* @alias('i') * @alias('i')
*/ */
@ -27,6 +27,7 @@ class Pm extends This {
search() { search() {
/** /**
* @program()
* @command('search with optional query') * @command('search with optional query')
* @alias('s') * @alias('s')
*/ */
@ -35,6 +36,7 @@ class Pm extends This {
update() { update() {
/** /**
* @program()
* @command('update installed packages') * @command('update installed packages')
* @executable('myUpdateSubCommand') * @executable('myUpdateSubCommand')
*/ */
@ -43,6 +45,7 @@ class Pm extends This {
list() { list() {
/** /**
* @program()
* @command('list packages installed') * @command('list packages installed')
*/ */
// Calls stand-alone excutable `pm-list` because of @command(<description>) in docstring // Calls stand-alone excutable `pm-list` because of @command(<description>) in docstring
@ -118,31 +121,7 @@ class Pm extends This {
} }
start() { start() {
this.program.parse(); super.start();
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
} }
} }

View File

@ -1,39 +1,23 @@
#!/usr/bin/env node #!/usr/bin/env node
const This = require('./this'); const This = require('./this');
const util = require('util');
class PmInstall extends This { class PmInstall extends This {
constructor() { constructor() {
super(); super();
this.version = '0.0.1'; 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 super.init(); // initialize commander with overridden version and description
} }
start() { start() {
// Usage /**
const pmInstall = new PmInstall(); * @program()
// Output: Methods of ExampleClass: [ 'methodOne', 'methodTwo' ] * @usage('-n 3 32 -l x y z -- op')
// Properties of ExampleClass: [ 'propertyOne', 'propertyTwo', 'version' ] and Version: 1.1.0 * @option('-n, --number <numbers...>', 'specify numbers')
// pmInstall.discovery(); * @option('-l, --letter [letters...]', 'specify letters')
*/
this.program super.start();
.usage('-n 3 32 -l x y z -- op')
.option('-n, --number <numbers...>', '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();
}
} }
} }

12
pm-list
View File

@ -1,23 +1,17 @@
#!/usr/bin/env node #!/usr/bin/env node
const This = require('./this'); const This = require('./this');
const { Command } = require('commander');
const program = new Command();
class PmList extends This { class PmList extends This {
constructor() { constructor() {
super(); super();
this.version = '0.0.1'; this.version = '0.0.1';
this.description = 'List packages of fake package manager';
super.init(); // initialize commander with overridden version and description
} }
start() { start() {
// Usage super.start();
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();
} }
} }

View File

@ -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

91
this
View File

@ -3,6 +3,7 @@
const path = require('path'); const path = require('path');
const { Command } = require('commander'); const { Command } = require('commander');
const shell = require('shelljs'); const shell = require('shelljs');
const util = require('util');
class This { class This {
constructor() { constructor() {
@ -60,8 +61,20 @@ class This {
} }
start() { 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) { execCmd(cmd) {
@ -102,10 +115,21 @@ class This {
// Utility function to extract docstring from a function, e.g. // Utility function to extract docstring from a function, e.g.
// //
// start() {
// /**
// * @program()
// * @usage([options] [command])
// * @option('-d, --debug', 'Enable debug mode')
// ..
// }
//
//
// echo(str) { // echo(str) {
// /** // /**
// @command // * @program()
// @argument('<message>') // * @command()
// * @argument('<message>')
// * @option('-c, --color <name>', 'Prints in color mode')
// */ // */
// console.log(str); // console.log(str);
// } // }
@ -128,33 +152,46 @@ class This {
} }
// Extract command and arguments // Extract command and arguments
const commandMatch = docString.match(/@command(?:\('([^']*)'\))?/); const programRegex = /@program\(\)/;
const aliasMatch = docString.match(/@alias\('(.+?)'\)/); const usageRegex = /@usage\('(.+?)'\)/;
const argumentsMatch = /@argument\('(.+?)'\)/g; const commandRegex = /@command(?:\('(.+?)'\))?/;
const optionsMatch = /@option\('(.+?)'\)/g; const aliasRegex = /@alias\('(.+?)'\)/;
const defaultMatch = docString.match(/@default/); const argumentsRegex = /@argument\('(.+?)'\)/g;
const executableMatch = docString.match(/@executable\('(.+?)'\)/); const optionsRegex = /@option\('(?<flag>.+?)',\s*'(?<description>.+?)'(?:,\s*'(?<defaultValue>.+?)')?\)/g;
const defaultRegex = /@default/;
const executableRegex = /@executable\('(.+?)'\)/;
if (!commandMatch) { // get regex matches with capture groups
// No @command tag found 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; return;
} }
if (commandMatch) {
// Generate the commander statement
const commandName = fn.name; const commandName = fn.name;
const commandDescription = commandMatch ? commandMatch[1] : ''; const commandDescription = commandMatch ? commandMatch[1] : '';
const alias = aliasMatch ? aliasMatch[1] : ''; const alias = aliasMatch ? aliasMatch[1] : '';
const defaultCommand = defaultMatch ? true : false; const defaultCommand = defaultMatch ? true : false;
const executable = executableMatch ? executableMatch[1] : ''; const executable = executableMatch ? executableMatch[1] : '';
// Generate the commander statement
// Get the function reference // Get the function reference
const func = this[commandName].bind(this); const func = this[commandName].bind(this);
// Create a command // Create a command
// See https://github.com/tj/commander.js?tab=readme-ov-file#quick-start
// When `.command()` is invoked with a description argument, // When `.command()` is invoked with a description argument,
// this tells Commander that you're going to use a stand-alone executable for the subcommand. // this tells Commander that you're going to use a stand-alone executable for the subcommand.
let command; let command;
if (commandDescription) { if (commandDescription) {
// build stand-alone command
command = this.program.command(commandName, commandDescription, { command = this.program.command(commandName, commandDescription, {
isDefault: defaultCommand, isDefault: defaultCommand,
executableFile: executable, executableFile: executable,
@ -164,6 +201,7 @@ class This {
command.alias(alias); command.alias(alias);
} }
} else { } else {
// build command with function name as action
command = this.program.command(commandName, { isDefault: defaultCommand }); command = this.program.command(commandName, { isDefault: defaultCommand });
// Set the action for the command // Set the action for the command
@ -173,21 +211,28 @@ class This {
} }
// If the commandName expects arguments, we add them here // If the commandName expects arguments, we add them here
let argMatch; (docString.match(argumentsRegex) || [])
while ((argMatch = argumentsMatch.exec(docString)) !== null) { .map((e) => e.replace(argumentsRegex, '$1'))
command.argument(argMatch[1]); .forEach((arg) => {
} command.argument(arg);
});
// If the commandName expects options, we add them here // If the commandName expects options, we add them here
let optMatch; // See https://github.com/tj/commander.js?tab=readme-ov-file#options
while ((optMatch = optionsMatch.exec(docString)) !== null) { for (const match of docString.matchAll(optionsRegex)) {
command.option(optMatch[1]); command.option(match.groups['flag'], match.groups['description'], match.groups['defaultValue']);
} }
} else {
// Add usage
if (usageMatch) {
this.program.usage(usageMatch[1]);
} }
_addMethodsToClass(cls, metadata) { // If the program expects options, we add them here
if (cls) { // See https://github.com/tj/commander.js?tab=readme-ov-file#options
cls.commands.push(metadata); for (const match of docString.matchAll(optionsRegex)) {
this.program.option(match.groups['flag'], match.groups['description'], match.groups['defaultValue']);
}
} }
} }