#!/usr/bin/env node const path = require('path'); const { Command } = require('commander'); const shell = require('shelljs'); 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; } 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)), }); } 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); } start() { // Not implemented, so it needs to be overridden! console.warn(this._echoInYellow(`Method ${this._getCurrentFunctionName()} not implemented!`)); } 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`; } _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; } // 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;