Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
c069f1f232 | |||
6679297c2f | |||
4c114c7ee4 | |||
a09d060593 | |||
d6336f4836 | |||
e29f085961 | |||
64815d15f6 | |||
d5de0bfe54 | |||
4f15c61019 | |||
b3b2505a97 | |||
e77fab3b84 | |||
94cc6816d5 |
|
@ -5,7 +5,7 @@
|
||||||
"semi": true,
|
"semi": true,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"trailingComma": "es5",
|
"trailingComma": "es5",
|
||||||
"bracketSpacing": false,
|
"bracketSpacing": true,
|
||||||
"arrowParens": "always",
|
"arrowParens": "always",
|
||||||
"endOfLine": "lf"
|
"endOfLine": "lf"
|
||||||
}
|
}
|
||||||
|
|
11
README.md
11
README.md
|
@ -15,3 +15,14 @@ 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.
|
||||||
|
|
||||||
|
- only commander v11 supports nodejs v16
|
||||||
|
|
50
completion/bash_template.sh
Normal file
50
completion/bash_template.sh
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
[[ "$1" != "" ]] || {
|
||||||
|
echo "Usage: source bash_template.sh <scriptname>"
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ "$1" = "" ]] || {
|
||||||
|
_pm()
|
||||||
|
{
|
||||||
|
local cur prev
|
||||||
|
local IFS=$'\n'
|
||||||
|
|
||||||
|
# Retrieve the original value
|
||||||
|
local width=$(bind -v | sed -n 's/^set completion-display-width //p')
|
||||||
|
|
||||||
|
if [[ $width -ne 0 ]]; then
|
||||||
|
# Change the readline variable
|
||||||
|
bind "set completion-display-width 0"
|
||||||
|
# On the first tab press, expand a common prefix
|
||||||
|
# On the second tab press, list out options
|
||||||
|
# Any subsequent tab presses cycle through these options
|
||||||
|
bind "set show-all-if-ambiguous on"
|
||||||
|
bind "set menu-complete-display-prefix on"
|
||||||
|
bind "TAB: menu-complete"
|
||||||
|
bind "set colored-completion-prefix on"
|
||||||
|
bind "set colored-stats on"
|
||||||
|
|
||||||
|
# Set up PROMPT_COMMAND to reset itself to its current value
|
||||||
|
PROMPT_COMMAND="PROMPT_COMMAND=$(printf %q "$PROMPT_COMMAND")"
|
||||||
|
|
||||||
|
# Set up PROMPT_COMMAND to reset the readline variable
|
||||||
|
PROMPT_COMMAND+="; bind 'set completion-display-width $width'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cur=${COMP_WORDS[COMP_CWORD]}
|
||||||
|
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||||
|
|
||||||
|
# Get all options from omelette
|
||||||
|
#COMPREPLY=( $(compgen -W '$(./'$1' --compbash --compgen "${COMP_CWORD}" "${prev}" "${COMP_LINE}")' -- "$cur") )
|
||||||
|
|
||||||
|
# Get all options from commander
|
||||||
|
COMPREPLY=( $(compgen -W '$(./'$1' compgen --shell bash)' -- "$cur") )
|
||||||
|
|
||||||
|
# If no options available, print files and folders
|
||||||
|
if [ ${#COMPREPLY[@]} -eq 0 ]; then
|
||||||
|
COMPREPLY=( $(compgen -f -o default -o plusdirs $cur) )
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
complete -F _pm $1
|
||||||
|
}
|
11
init/oosh
Normal file
11
init/oosh
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#!/usr/bin/env -iS HOME=${HOME} sh
|
||||||
|
#http://www.etalabs.net/sh_tricks.html
|
||||||
|
|
||||||
|
OOSH_DIR=${HOME}/oosh
|
||||||
|
|
||||||
|
apk add bash bash-completion curl git nodejs-current npm
|
||||||
|
#mkdir -p $OOSH_DIR
|
||||||
|
git clone https://gitea.starconnect.ch/Public/nodejs-bash-completion.git $OOSH_DIR
|
||||||
|
cd $OOSH_DIR
|
||||||
|
git checkout dev
|
||||||
|
npm install
|
91
log
Executable file
91
log
Executable file
|
@ -0,0 +1,91 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const This = require('./this');
|
||||||
|
const util = require('util');
|
||||||
|
|
||||||
|
class Log extends This {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.version = '0.0.1';
|
||||||
|
this.description = 'Helper script for building log messages';
|
||||||
|
super.init(); // initialize commander with overridden version and description
|
||||||
|
}
|
||||||
|
|
||||||
|
echo(message) {
|
||||||
|
/**
|
||||||
|
* @program()
|
||||||
|
* @command()
|
||||||
|
* @argument('<message>')
|
||||||
|
*/
|
||||||
|
console.log(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
success(message) {
|
||||||
|
/**
|
||||||
|
* @program()
|
||||||
|
* @command()
|
||||||
|
* @argument('<message>')
|
||||||
|
*/
|
||||||
|
console.log(this._echoInGreen(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
info(message) {
|
||||||
|
/**
|
||||||
|
* @program()
|
||||||
|
* @command()
|
||||||
|
* @argument('<message>')
|
||||||
|
*/
|
||||||
|
console.log(`[INFO] ${message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
warn(message) {
|
||||||
|
/**
|
||||||
|
* @program()
|
||||||
|
* @command()
|
||||||
|
* @argument('<message>')
|
||||||
|
*/
|
||||||
|
console.warn(`[WARN] ${this._echoInYellow(message)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
error(message) {
|
||||||
|
/**
|
||||||
|
* @program()
|
||||||
|
* @command()
|
||||||
|
* @argument('<message>')
|
||||||
|
*/
|
||||||
|
console.error(`[ERR] ${this._echoInRed(message)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
/**
|
||||||
|
* @program()
|
||||||
|
*/
|
||||||
|
if (this.debugLevel > 2) {
|
||||||
|
this.program.exitOverride();
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.program.parse();
|
||||||
|
} catch (err) {
|
||||||
|
// this.echo('\n');
|
||||||
|
// this.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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.echo('\n');
|
||||||
|
this.echo(`Options: ${opts}`);
|
||||||
|
this.echo(`Remaining arguments: ${args}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// don't debug log if level is < 3 or the output will be hard to read
|
||||||
|
this.program.parse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// main
|
||||||
|
const log = new Log();
|
||||||
|
log.start();
|
|
@ -1,19 +1,31 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const This = require('./this');
|
||||||
const shell = require('shelljs');
|
const shell = require('shelljs');
|
||||||
|
|
||||||
// 1) Use shell object with its methods
|
class MyUpdateSubCommand extends This {
|
||||||
if (!shell.which('git')) {
|
constructor() {
|
||||||
shell.echo('Sorry, this script requires git');
|
super();
|
||||||
shell.exit(1);
|
this.version = '0.0.1';
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
// Usage
|
||||||
|
const myUpdateSubCommand = new MyUpdateSubCommand();
|
||||||
|
// Output: Methods of ExampleClass: [ 'methodOne', 'methodTwo' ]
|
||||||
|
// Properties of ExampleClass: [ 'propertyOne', 'propertyTwo', 'version' ] and Version: 1.1.0
|
||||||
|
// myUpdateSubCommand.discover();
|
||||||
|
|
||||||
|
if (!shell.which('git')) {
|
||||||
|
shell.echo('Sorry, this script requires git');
|
||||||
|
shell.exit(1);
|
||||||
|
} else {
|
||||||
|
shell.echo('Woohoo! You have git installed!');
|
||||||
|
shell.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) or the following 'with' statement to specify that the `shell` object is the default object.
|
// main
|
||||||
// The statements following the with statement refer to the echo methods, without specifying
|
const myUpdateSubCommand = new MyUpdateSubCommand();
|
||||||
// an object. JavaScript assumes the `shell` object for these references.
|
myUpdateSubCommand.start();
|
||||||
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with
|
|
||||||
with (shell) {
|
|
||||||
echo('hello world');
|
|
||||||
echo('-n', 'no newline at end -> ');
|
|
||||||
let str = echo('hello world');
|
|
||||||
}
|
|
||||||
|
|
44
os
Executable file
44
os
Executable file
|
@ -0,0 +1,44 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const This = require('./this');
|
||||||
|
|
||||||
|
class Os extends This {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.version = '0.0.1';
|
||||||
|
this.description = 'Shows informations about the operating system';
|
||||||
|
super.init(); // initialize commander with overridden version and description
|
||||||
|
}
|
||||||
|
|
||||||
|
info() {
|
||||||
|
/**
|
||||||
|
* @program()
|
||||||
|
* @command()
|
||||||
|
*/
|
||||||
|
console.warn(`Function ${this._getCurrentFunctionName()} not implemented`);
|
||||||
|
}
|
||||||
|
|
||||||
|
check() {
|
||||||
|
/**
|
||||||
|
* @program()
|
||||||
|
* @command()
|
||||||
|
*/
|
||||||
|
console.warn(`Function ${this._getCurrentFunctionName()} not implemented`);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkEnv() {
|
||||||
|
/**
|
||||||
|
* @program()
|
||||||
|
* @command()
|
||||||
|
*/
|
||||||
|
console.warn(`Function ${this._getCurrentFunctionName()} not implemented`);
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
super.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// main
|
||||||
|
const os = new Os();
|
||||||
|
os.start();
|
230
package-lock.json
generated
Normal file
230
package-lock.json
generated
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
{
|
||||||
|
"name": "once-nodejs",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "^11.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": "11.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
|
||||||
|
"integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,8 +3,7 @@
|
||||||
"format": "prettier --ignore-path .gitignore --write \"./*\""
|
"format": "prettier --ignore-path .gitignore --write \"./*\""
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "^12.1.0",
|
"commander": "^11.1.0",
|
||||||
"omelette": "^0.4.17",
|
|
||||||
"shelljs": "^0.8.5"
|
"shelljs": "^0.8.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
148
pm
148
pm
|
@ -1,8 +1,6 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const path = require('path');
|
const This = require('./this');
|
||||||
const { Command } = require('commander');
|
|
||||||
const program = new Command();
|
|
||||||
|
|
||||||
// Example of subcommands which are implemented as stand-alone executable files.
|
// Example of subcommands which are implemented as stand-alone executable files.
|
||||||
//
|
//
|
||||||
|
@ -10,28 +8,128 @@ const program = new Command();
|
||||||
// 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.
|
||||||
//
|
//
|
||||||
// Only `install` and `list` are implemented, see pm-install and pm-list.js
|
// Only `install` and `list` are implemented, see pm-install and pm-list.js
|
||||||
|
class Pm extends This {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.version = '0.0.1';
|
||||||
|
this.description = 'Fake package manager';
|
||||||
|
super.init(); // initialize commander with overridden version and description
|
||||||
|
}
|
||||||
|
|
||||||
program
|
install() {
|
||||||
.name(path.parse(process.argv[1]).base)
|
/**
|
||||||
.version('0.0.1')
|
* @program()
|
||||||
.description('Fake package manager')
|
* @command('install one or more packages')
|
||||||
.command('install [name]', 'install one or more packages')
|
* @alias('i')
|
||||||
.alias('i')
|
*/
|
||||||
.command('search [query]', 'search with optional query')
|
// Calls stand-alone excutable `pm-install` because of @command(<description>) in docstring
|
||||||
.alias('s')
|
}
|
||||||
.command('update', 'update installed packages', {
|
|
||||||
executableFile: 'myUpdateSubCommand',
|
|
||||||
})
|
|
||||||
.command('list', 'list packages installed', { isDefault: false });
|
|
||||||
|
|
||||||
program.parse();
|
search() {
|
||||||
|
/**
|
||||||
|
* @program()
|
||||||
|
* @command('search with optional query')
|
||||||
|
* @alias('s')
|
||||||
|
*/
|
||||||
|
// Calls stand-alone excutable `pm-search` because of @command(<description>) in docstring
|
||||||
|
}
|
||||||
|
|
||||||
// Try the following on macOS or Linux:
|
update() {
|
||||||
// ./examples/pm
|
/**
|
||||||
//
|
* @program()
|
||||||
// Try the following:
|
* @command('update installed packages')
|
||||||
// ./pm
|
* @executable('myUpdateSubCommand')
|
||||||
// ./pm help install
|
*/
|
||||||
// ./pm install -h
|
// Calls stand-alone excutable `myUpdateSubCommand` because of @command(<description>) in docstring
|
||||||
// ./pm install foo bar baz
|
}
|
||||||
// ./pm install foo bar baz --force
|
|
||||||
|
list() {
|
||||||
|
/**
|
||||||
|
* @program()
|
||||||
|
* @command('list packages installed')
|
||||||
|
*/
|
||||||
|
// Calls stand-alone excutable `pm-list` because of @command(<description>) in docstring
|
||||||
|
}
|
||||||
|
|
||||||
|
// override This.discover()
|
||||||
|
discover() {
|
||||||
|
const methods = this.listMethods();
|
||||||
|
return methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic test methods
|
||||||
|
_testListMethod() {
|
||||||
|
const pm = new Pm();
|
||||||
|
const pmMethods = pm.listMethods();
|
||||||
|
|
||||||
|
const testMethods =
|
||||||
|
pmMethods.includes('install') &&
|
||||||
|
pmMethods.includes('search') &&
|
||||||
|
pmMethods.includes('update') &&
|
||||||
|
pmMethods.includes('list') &&
|
||||||
|
pmMethods.includes('discover') &&
|
||||||
|
pmMethods.includes('start');
|
||||||
|
const testInternalMethods = !pmMethods.includes('_testListMethod');
|
||||||
|
|
||||||
|
console.assert(testMethods, 'Pm.listMethod() failed');
|
||||||
|
console.assert(
|
||||||
|
testInternalMethods,
|
||||||
|
'Pm.listMethod() for internal methods failed. Classes with _ should be ignored'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (testMethods && testInternalMethods) {
|
||||||
|
this.execCmd(`${this.workingDir}/log success 'testListMethod passed'`);
|
||||||
|
} else {
|
||||||
|
this.execCmd(`${this.workingDir}/log error 'testListMethod failed'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_testListProperties() {
|
||||||
|
const pm = new Pm();
|
||||||
|
const pmProperties = pm.listProperties();
|
||||||
|
|
||||||
|
const testProperties =
|
||||||
|
pmProperties.includes('version') && pmProperties.includes('description') && pmProperties.includes('program');
|
||||||
|
console.assert(testProperties, 'Pm.listProperties() failed');
|
||||||
|
|
||||||
|
if (testProperties) {
|
||||||
|
this.execCmd(`${this.workingDir}/log success 'testListProperties passed'`);
|
||||||
|
} else {
|
||||||
|
this.execCmd(`${this.workingDir}/log error 'testListProperties failed'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_testGetClassName() {
|
||||||
|
const pm = new Pm();
|
||||||
|
const pmClassName = pm.getClassName();
|
||||||
|
|
||||||
|
const testClassName = pmClassName === 'Pm';
|
||||||
|
console.assert(testClassName, 'Pm.getClassName() failed');
|
||||||
|
|
||||||
|
if (testClassName) {
|
||||||
|
this.execCmd(`${this.workingDir}/log success 'testGetClassName passed'`);
|
||||||
|
} else {
|
||||||
|
this.execCmd(`${this.workingDir}/log error 'testGetClassName failed'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selfTest() {
|
||||||
|
// Run tests
|
||||||
|
this._testListMethod();
|
||||||
|
this._testListProperties();
|
||||||
|
this._testGetClassName();
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
super.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// main
|
||||||
|
const pm = new Pm();
|
||||||
|
// // applies logDecorator to this.discover() and binds it to the instance to maintain the correct context
|
||||||
|
// const logDecoratedDiscover = pm._logDecorator(pm.discover).bind(pm);
|
||||||
|
// logDecoratedDiscover();
|
||||||
|
|
||||||
|
pm.start();
|
||||||
|
//pm.selfTest();
|
||||||
|
|
58
pm-install
58
pm-install
|
@ -1,42 +1,26 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const path = require('path');
|
const This = require('./this');
|
||||||
const { Command } = require('commander');
|
|
||||||
const program = new Command();
|
|
||||||
|
|
||||||
const errorColor = (str) => {
|
class PmInstall extends This {
|
||||||
// Add ANSI escape codes to display text in red.
|
constructor() {
|
||||||
return `\x1b[31m${str}\x1b[0m`;
|
super();
|
||||||
|
this.version = '0.0.1';
|
||||||
|
this.description = 'Install package with fake package manager';
|
||||||
|
super.init(); // initialize commander with overridden version and description
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
/**
|
||||||
|
* @program()
|
||||||
|
* @usage('-n 3 32 -l x y z -- op')
|
||||||
|
* @option('-n, --number <numbers...>', 'specify numbers')
|
||||||
|
* @option('-l, --letter [letters...]', 'specify letters')
|
||||||
|
*/
|
||||||
|
super.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
program
|
// main
|
||||||
.name(path.parse(process.argv[1]).base)
|
const pmInstall = new PmInstall();
|
||||||
.version('0.0.1')
|
pmInstall.start();
|
||||||
.description('Install package with fake package manager')
|
|
||||||
.usage("-n 3 32 -l x y z -- op")
|
|
||||||
.configureOutput({
|
|
||||||
// Visibly override write routines as example!
|
|
||||||
//writeOut: (str) => process.stdout.write(`[OUT] ${str}`),
|
|
||||||
writeErr: (str) => process.stdout.write(`[ERR] ${str}`),
|
|
||||||
// Highlight errors in color.
|
|
||||||
outputError: (str, write) => write(errorColor(str))
|
|
||||||
});
|
|
||||||
|
|
||||||
program
|
|
||||||
.option('-n, --number <numbers...>', 'specify numbers')
|
|
||||||
.option('-l, --letter [letters...]', 'specify letters')
|
|
||||||
.parse();
|
|
||||||
|
|
||||||
// console.log('options array');
|
|
||||||
// console.log(program.options.map(o => o.flags));
|
|
||||||
|
|
||||||
// console.log('visible options');
|
|
||||||
// const helper = program.createHelp();
|
|
||||||
// console.log(helper.visibleOptions(program).map(o => o.flags));
|
|
||||||
|
|
||||||
if (Object.keys(program.opts()).length || program.args.length) {
|
|
||||||
console.log('Options: ', program.opts());
|
|
||||||
console.log('Remaining arguments: ', program.args);
|
|
||||||
} else {
|
|
||||||
program.outputHelp();
|
|
||||||
}
|
|
||||||
|
|
25
pm-list
25
pm-list
|
@ -1,11 +1,20 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const path = require('path');
|
const This = require('./this');
|
||||||
const { Command } = require('commander');
|
|
||||||
const program = new Command();
|
|
||||||
|
|
||||||
program
|
class PmList extends This {
|
||||||
.name(path.parse(process.argv[1]).base)
|
constructor() {
|
||||||
.version('0.0.1')
|
super();
|
||||||
.description('List packages of fake package manager')
|
this.version = '0.0.1';
|
||||||
.outputHelp();
|
this.description = 'List packages of fake package manager';
|
||||||
|
super.init(); // initialize commander with overridden version and description
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
super.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// main
|
||||||
|
const pmList = new PmList();
|
||||||
|
pmList.start();
|
||||||
|
|
25
pm-search
25
pm-search
|
@ -1,11 +1,20 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const path = require('path');
|
const This = require('./this');
|
||||||
const { Command } = require('commander');
|
|
||||||
const program = new Command();
|
|
||||||
|
|
||||||
program
|
class PmSearch extends This {
|
||||||
.name(path.parse(process.argv[1]).base)
|
constructor() {
|
||||||
.version('0.0.1')
|
super();
|
||||||
.description('Search packages of fake package manager')
|
this.version = '0.0.1';
|
||||||
.outputHelp();
|
this.description = 'Search packages of fake package manager';
|
||||||
|
super.init(); // initialize commander with overridden version and description
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
super.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// main
|
||||||
|
const pmSearch = new PmSearch();
|
||||||
|
pmSearch.start();
|
||||||
|
|
161
pnpm-lock.yaml
161
pnpm-lock.yaml
|
@ -1,161 +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
|
|
284
this
Normal file
284
this
Normal file
|
@ -0,0 +1,284 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const os = require('os');
|
||||||
|
const path = require('path');
|
||||||
|
const { Command } = require('commander');
|
||||||
|
const shell = require('shelljs');
|
||||||
|
const util = require('util');
|
||||||
|
|
||||||
|
class This {
|
||||||
|
constructor() {
|
||||||
|
this.version = '0.0.1'; // Default version, can be overridden in subclasses
|
||||||
|
this.description = 'This is the parent class all other scripts should extend.';
|
||||||
|
this.scriptName = path.parse(process.argv[1]).base;
|
||||||
|
this.workingDir = path.parse(process.argv[1]).dir;
|
||||||
|
this.debugLevel = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// implement commander abilities
|
||||||
|
this.program = new Command()
|
||||||
|
.name(this.scriptName)
|
||||||
|
.version(this.version)
|
||||||
|
.description(this.description)
|
||||||
|
.configureOutput({
|
||||||
|
// Visibly override write routines as example!
|
||||||
|
//writeOut: (str) => process.stdout.write(`[OUT] ${str}`),
|
||||||
|
//writeErr: (str) => process.stdout.write(`[ERR] ${str}`),
|
||||||
|
// Highlight errors in color.
|
||||||
|
outputError: (str, write) => write(this._echoInRed(str)),
|
||||||
|
});
|
||||||
|
|
||||||
|
// dynamically add all methods with appropriate docstring to commander
|
||||||
|
let cmds = [];
|
||||||
|
this.listMethods().forEach((method) => {
|
||||||
|
let cmd = this._parseDocStringToCmd(this[method]);
|
||||||
|
// exclude start function as commandline cmd, because its the scripts main entry point
|
||||||
|
if (cmd && cmd != 'start') {
|
||||||
|
cmds.push(cmd);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// add functions for shell completion
|
||||||
|
this.program
|
||||||
|
.command('compgen')
|
||||||
|
.option('-s, --shell <name>', 'You can select between [bash]', 'bash')
|
||||||
|
.action((arg) => {
|
||||||
|
console.log(cmds.join(os.EOL));
|
||||||
|
return process.exit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getClassName() {
|
||||||
|
return this.constructor.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
listMethods() {
|
||||||
|
const methods = Object.getOwnPropertyNames(Object.getPrototypeOf(this)).filter(
|
||||||
|
(prop) => typeof this[prop] === 'function' && prop !== 'constructor' && !prop.startsWith('_')
|
||||||
|
);
|
||||||
|
return methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
listProperties() {
|
||||||
|
const properties = Object.keys(this).filter((prop) => typeof this[prop] !== 'function');
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
discover() {
|
||||||
|
const methods = util.inspect(this.listMethods(), { depth: null, colors: true, showHidden: true });
|
||||||
|
const properties = util.inspect(this.listProperties(), { depth: null, colors: true, showHidden: true });
|
||||||
|
this.execCmd(
|
||||||
|
`${this.workingDir}/log echo 'My name is "${this.getClassName()}" and I have the version: ${this.version}'`
|
||||||
|
);
|
||||||
|
this.execCmd(`${this.workingDir}/log echo 'My methods are: ${methods}'`);
|
||||||
|
this.execCmd(`${this.workingDir}/log echo 'My properties are: ${properties}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to create a context manager for this instance
|
||||||
|
withContext(callback) {
|
||||||
|
callback(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
/**
|
||||||
|
* @program()
|
||||||
|
*/
|
||||||
|
this.program.exitOverride();
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.program.parse();
|
||||||
|
|
||||||
|
if (this.debugLevel == 0) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// this.execCmd(`${this.workingDir}/log echo '\n'`);
|
||||||
|
// this.execCmd(`${this.workingDir}/log error '${err}'`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 '\n'`);
|
||||||
|
this.execCmd(`${this.workingDir}/log echo 'Options: ${opts}'`);
|
||||||
|
this.execCmd(`${this.workingDir}/log echo 'Remaining arguments: ${args}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
execCmd(cmd) {
|
||||||
|
// Run external tool synchronously
|
||||||
|
if (shell.exec(cmd).code !== 0) {
|
||||||
|
shell.echo('[ERR] ' + this._echoInRed(`Command '${cmd}' failed`));
|
||||||
|
shell.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_echoInRed(str) {
|
||||||
|
// Add ANSI escape codes to display text in red.
|
||||||
|
return `\x1b[31m${str}\x1b[0m`;
|
||||||
|
}
|
||||||
|
|
||||||
|
_echoInYellow(str) {
|
||||||
|
// Add ANSI escape codes to display text in yellow.
|
||||||
|
return `\x1b[33m${str}\x1b[0m`;
|
||||||
|
}
|
||||||
|
|
||||||
|
_echoInGreen(str) {
|
||||||
|
// Add ANSI escape codes to display text in green.
|
||||||
|
return `\x1b[32m${str}\x1b[0m`;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getCurrentFunctionName() {
|
||||||
|
// Create an Error object (but don't throw it)
|
||||||
|
const err = new Error();
|
||||||
|
|
||||||
|
// Extract the current stack trace
|
||||||
|
Error.captureStackTrace(err, this._getCurrentFunctionName);
|
||||||
|
|
||||||
|
// Extract the function name from the stack trace
|
||||||
|
const callerName = err.stack.split('\n')[1].trim().split(' ')[1];
|
||||||
|
|
||||||
|
return callerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility function to extract docstring from a function, e.g.
|
||||||
|
//
|
||||||
|
// start() {
|
||||||
|
// /**
|
||||||
|
// * @program()
|
||||||
|
// * @usage([options] [command])
|
||||||
|
// * @option('-d, --debug', 'Enable debug mode')
|
||||||
|
// ..
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// echo(str) {
|
||||||
|
// /**
|
||||||
|
// * @program()
|
||||||
|
// * @command()
|
||||||
|
// * @argument('<message>')
|
||||||
|
// * @option('-c, --color <name>', 'Prints in color mode')
|
||||||
|
// */
|
||||||
|
// console.log(str);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Attention:
|
||||||
|
// In JavaScript, when a script is executed as a bash script with a shebang (#!/usr/bin/env node),
|
||||||
|
// the toString method on functions does not include comments preceding the function definition.
|
||||||
|
_getFunctionDocString(fn) {
|
||||||
|
const fnStr = fn.toString();
|
||||||
|
const docStringMatch = fnStr.match(/\/\*[\s\S]*?\*\//);
|
||||||
|
return docStringMatch ? docStringMatch[0] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parser function to convert docstring to commander statement
|
||||||
|
_parseDocStringToCmd(fn) {
|
||||||
|
const docString = this._getFunctionDocString(fn);
|
||||||
|
if (!docString) {
|
||||||
|
// No docstring found
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract command and arguments
|
||||||
|
const programRegex = /@program\(\)/;
|
||||||
|
const usageRegex = /@usage\('(.+?)'\)/;
|
||||||
|
const commandRegex = /@command(?:\('(.+?)'\))?/;
|
||||||
|
const aliasRegex = /@alias\('(.+?)'\)/;
|
||||||
|
const argumentsRegex = /@argument\('(.+?)'\)/g;
|
||||||
|
const optionsRegex = /@option\('(?<flag>.+?)',\s*'(?<description>.+?)'(?:,\s*'(?<defaultValue>.+?)')?\)/g;
|
||||||
|
const defaultRegex = /@default/;
|
||||||
|
const executableRegex = /@executable\('(.+?)'\)/;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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] : '';
|
||||||
|
|
||||||
|
// Get the function reference
|
||||||
|
const func = this[commandName].bind(this);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
} 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 {
|
||||||
|
// Add usage
|
||||||
|
if (usageMatch) {
|
||||||
|
this.program.usage(usageMatch[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return name of function, if docstring could be parsed successfully
|
||||||
|
return fn.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Higher-order function to decorate other functions and provide logging
|
||||||
|
_logDecorator(fn) {
|
||||||
|
return function (...args) {
|
||||||
|
console.log(`Calling ${fn.name} with arguments:`, args);
|
||||||
|
const result = fn.apply(this, args); // Use apply to maintain context
|
||||||
|
console.log(`Result of ${fn.name}:`, result);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = This;
|
Loading…
Reference in New Issue
Block a user