diff --git a/myUpdateSubCommand b/myUpdateSubCommand index 626480a..70cef5d 100755 --- a/myUpdateSubCommand +++ b/myUpdateSubCommand @@ -1,19 +1,31 @@ #!/usr/bin/env node +const This = require('./this'); const shell = require('shelljs'); -// 1) Use shell object with its methods -if (!shell.which('git')) { - shell.echo('Sorry, this script requires git'); - shell.exit(1); +class MyUpdateSubCommand extends This { + constructor() { + super(); + 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.discovery(); + + 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. -// The statements following the with statement refer to the echo methods, without specifying -// an object. JavaScript assumes the `shell` object for these references. -// 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'); -} \ No newline at end of file +// main +const myUpdateSubCommand = new MyUpdateSubCommand(); +myUpdateSubCommand.start(); diff --git a/package.json b/package.json index 2180896..7768209 100644 --- a/package.json +++ b/package.json @@ -10,4 +10,4 @@ "devDependencies": { "prettier": "^3.3.2" } -} \ No newline at end of file +} diff --git a/pm b/pm index 26c499d..16d6d4e 100755 --- a/pm +++ b/pm @@ -1,7 +1,7 @@ #!/usr/bin/env node -const path = require('path'); -const { Command } = require('commander'); +const This = require('./this'); +const {Command} = require('commander'); const program = new Command(); // Example of subcommands which are implemented as stand-alone executable files. @@ -10,28 +10,46 @@ const program = new Command(); // 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 +class Pm extends This { + constructor() { + super(); + this.version = '0.0.1'; + } -program - .name(path.parse(process.argv[1]).base) - .version('0.0.1') - .description('Fake package manager') - .command('install [name]', 'install one or more packages') - .alias('i') - .command('search [query]', 'search with optional query') - .alias('s') - .command('update', 'update installed packages', { - executableFile: 'myUpdateSubCommand', - }) - .command('list', 'list packages installed', { isDefault: false }); + start() { + // Usage + const pm = new Pm(); + // Output: Methods of ExampleClass: [ 'methodOne', 'methodTwo' ] + // Properties of ExampleClass: [ 'propertyOne', 'propertyTwo', 'version' ] and Version: 1.1.0 + // pm.discovery(); -program.parse(); + program + .name(this.scriptName) + .version('0.0.1') + .description('Fake package manager') + .command('install [name]', 'install one or more packages') + .alias('i') + .command('search [query]', 'search with optional query') + .alias('s') + .command('update', 'update installed packages', { + executableFile: 'myUpdateSubCommand', + }) + .command('list', 'list packages installed', {isDefault: false}); -// 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 \ No newline at end of file + program.parse(); + + // 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 + } +} + +// main +const pm = new Pm(); +pm.start(); diff --git a/pm-install b/pm-install index 3c80325..a0a2282 100755 --- a/pm-install +++ b/pm-install @@ -1,42 +1,61 @@ #!/usr/bin/env node -const path = require('path'); -const { Command } = require('commander'); +const This = require('./this'); +const {Command} = require('commander'); const program = new Command(); const errorColor = (str) => { // Add ANSI escape codes to display text in red. return `\x1b[31m${str}\x1b[0m`; +}; + +class PmInstall extends This { + constructor() { + super(); + this.version = '0.0.1'; + } + + 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(); + + program + .name(this.scriptName) + .version('0.0.1') + .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 ', '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(); + } + } } -program - .name(path.parse(process.argv[1]).base) - .version('0.0.1') - .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 ', '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(); -} \ No newline at end of file +// main +const pmInstall = new PmInstall(); +pmInstall.start(); diff --git a/pm-list b/pm-list index 4236bcd..3381913 100755 --- a/pm-list +++ b/pm-list @@ -1,11 +1,26 @@ #!/usr/bin/env node -const path = require('path'); -const { Command } = require('commander'); +const This = require('./this'); +const {Command} = require('commander'); const program = new Command(); -program - .name(path.parse(process.argv[1]).base) - .version('0.0.1') - .description('List packages of fake package manager') - .outputHelp(); +class PmList extends This { + constructor() { + super(); + this.version = '0.0.1'; + } + + 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(); + } +} + +// main +const pmList = new PmList(); +pmList.start(); diff --git a/pm-search b/pm-search index dad72e6..8d8ac3f 100755 --- a/pm-search +++ b/pm-search @@ -1,11 +1,26 @@ #!/usr/bin/env node -const path = require('path'); -const { Command } = require('commander'); +const This = require('./this'); +const {Command} = require('commander'); const program = new Command(); -program - .name(path.parse(process.argv[1]).base) - .version('0.0.1') - .description('Search packages of fake package manager') - .outputHelp(); +class PmSearch extends This { + constructor() { + super(); + this.version = '0.0.1'; + } + + start() { + // Usage + const pmSearch = new PmSearch(); + // Output: Methods of ExampleClass: [ 'methodOne', 'methodTwo' ] + // Properties of ExampleClass: [ 'propertyOne', 'propertyTwo', 'version' ] and Version: 1.1.0 + // pmSearch.discovery(); + + program.name(this.scriptName).version('0.0.1').description('Search packages of fake package manager').outputHelp(); + } +} + +// main +const pmSearch = new PmSearch(); +pmSearch.start(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7162869..f6145c5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,37 +21,43 @@ devDependencies: version: 3.3.2 packages: - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + resolution: + {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: false /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + 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==} + resolution: + {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} dev: false /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + resolution: + {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: false /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + resolution: + {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: false /function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + resolution: + {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} dev: false /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + resolution: + {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported dependencies: fs.realpath: 1.0.0 @@ -63,14 +69,16 @@ packages: dev: false /hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + 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==} + 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 @@ -78,62 +86,73 @@ packages: dev: false /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + resolution: + {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} dev: false /interpret@1.4.0: - resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} + resolution: + {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} engines: {node: '>= 0.10'} dev: false /is-core-module@2.14.0: - resolution: {integrity: sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==} + 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==} + 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==} + 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==} + 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==} + resolution: + {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} dev: false /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + resolution: + {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: false /prettier@3.3.2: - resolution: {integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==} + 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==} + 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==} + resolution: + {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true dependencies: is-core-module: 2.14.0 @@ -142,7 +161,8 @@ packages: dev: false /shelljs@0.8.5: - resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} + resolution: + {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} engines: {node: '>=4'} hasBin: true dependencies: @@ -152,10 +172,12 @@ packages: dev: false /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + resolution: + {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} dev: false /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + resolution: + {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: false diff --git a/this b/this new file mode 100644 index 0000000..c3d1ac1 --- /dev/null +++ b/this @@ -0,0 +1,39 @@ +#!/usr/bin/env node + +const path = require('path'); + +class This { + constructor() { + this.version = '0.0.1'; // Default version, can be overridden in subclasses + this.scriptName = path.parse(process.argv[1]).base; + } + + 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; + } + + discovery() { + console.log(`My name is '${this.getClassName()}' and I have the version: ${this.version}`); + console.log(`My methods are:`, this.listMethods()); + console.log(`My properties are:`, this.listProperties()); + } + + // Method to create a context manager for this instance + withContext(callback) { + callback(this); + } +} + +module.exports = This;