diff --git a/Lara-JS/src-code/Weaver.ts b/Lara-JS/src-code/Weaver.ts index 1c049473..26c613f7 100644 --- a/Lara-JS/src-code/Weaver.ts +++ b/Lara-JS/src-code/Weaver.ts @@ -8,6 +8,7 @@ import { isJavaError } from "./JavaError.js"; import { promisify } from "util"; import { isValidFileExtension } from "./FileExtensions.js"; import WeaverMessageFromLauncher from "./WeaverMessageFromLauncher.js"; +import assert from "assert"; let directExecution = false; @@ -100,11 +101,19 @@ export class Weaver { javaWeaver.setScriptEngine(new NodeJsEngine()); javaWeaver.setEventTrigger(new JavaEventTrigger()); + const isClassicCli = + args.configClassic !== undefined && args.configClassic !== null; + let datastore; - if (args._[0] === "classic") { + if (isClassicCli) { + //if (args._[0] === "classic") { try { + assert(args.configClassic instanceof Array); + console.log("FLAGS: " + args.configClassic); + datastore = JavaLaraI.convertArgsToDataStore( - args._.slice(1), + //args._.slice(1), + args.configClassic, javaWeaver ).get(); args.scriptFile = datastore.get("aspect").toString(); @@ -139,7 +148,6 @@ export class Weaver { // Needed only for side-effects over the datastore new JavaLaraIDataStore(null, datastore, javaWeaver); // nosonar typescript:S1848 - JavaSpecsSystem.programStandardInit(); Weaver.javaWeaver = javaWeaver; @@ -165,16 +173,26 @@ export class Weaver { await import(file); } + if (typeof args.scriptFile !== "string") { + throw new Error( + "Script file '" + + args.scriptFile + + "' is not a string: " + + typeof args.scriptFile + ); + } + + const scriptFile = args.scriptFile; + Weaver.debug("Executing user script..."); if ( - typeof args.scriptFile === "string" && - fs.existsSync(args.scriptFile) && - isValidFileExtension(path.extname(args.scriptFile)) + fs.existsSync(scriptFile) && + isValidFileExtension(path.extname(scriptFile)) ) { // import is using a URL converted to string. // The URL is used due to a Windows error with paths. See https://stackoverflow.com/questions/69665780/error-err-unsupported-esm-url-scheme-only-file-and-data-urls-are-supported-by // The conversion of the URl back to a string is due to a TS bug. See https://github.com/microsoft/TypeScript/issues/42866 - await import(pathToFileURL(path.resolve(args.scriptFile)).toString()) + await import(pathToFileURL(path.resolve(scriptFile)).toString()) .then(() => { Weaver.debug("Execution completed successfully."); }) @@ -192,7 +210,7 @@ export class Weaver { Weaver.debug(error); }); } else { - throw new Error("Invalid file path or file type."); + throw new Error("Invalid file path or file type: " + scriptFile); } } @@ -257,6 +275,7 @@ waitForMessage(eventEmitter) if (directExecution) { Weaver.start(); + await Weaver.executeScript( messageFromParent.args, messageFromParent.config diff --git a/Lara-JS/src-code/WeaverLauncher.ts b/Lara-JS/src-code/WeaverLauncher.ts index 95627f83..af794226 100644 --- a/Lara-JS/src-code/WeaverLauncher.ts +++ b/Lara-JS/src-code/WeaverLauncher.ts @@ -13,6 +13,9 @@ import { } from "./ChildProcessHandling.js"; import WeaverConfiguration from "./WeaverConfiguration.js"; import WeaverMessageFromLauncher from "./WeaverMessageFromLauncher.js"; +import { writeFileSync } from "fs"; + +import { Weaver } from "./Weaver.js"; listenForTerminationSignals(); @@ -28,7 +31,46 @@ export default class WeaverLauncher { this.debug = Debug(`WeaverLauncher:${this.config.weaverPrettyName}:main`); } - async execute(customArgs: string | undefined = undefined): Promise { + /* + executeSync(customArgs: string[] | undefined = undefined): void { + const cliArgs = customArgs ?? hideBin(process.argv); + + if (cliArgs.length > 0 && cliArgs[0] === "classic") { + const weaverArgs = cliArgs.slice(1); + console.log( + `Executing ${this.config.weaverPrettyName} script in classic CLI mode...` + ); + } + + await execute(customArgs); + } + */ + + async execute(customArgs: string[] | undefined = undefined): Promise { + const cliArgs = customArgs ?? hideBin(process.argv); + + if (cliArgs.length > 0 && cliArgs[0] === "classic") { + const weaverArgs = cliArgs.slice(1); + + return new Promise((resolve, reject) => { + try { + console.log( + `Executing ${this.config.weaverPrettyName} script in classic CLI mode...` + ); + // TODO: Avoid using a third-party data object (i.e., Arguments) in our main interface + // TODO: Use instead the argument-handling launcher Java code instead of reimplementing it + void this.main({ + $0: weaverArgs[0], + _: [], + scriptFile: weaverArgs[0], + configClassic: weaverArgs, + } as Arguments); + } catch (error) { + console.error(error); + } + }); + } + await this.generateConfig(customArgs).parse(); } @@ -63,6 +105,21 @@ export default class WeaverLauncher { } protected async executeWeaver(args: Arguments) { + // Check if Classic CLI + const isClassicCli = + args.configClassic !== undefined && args.configClassic !== null; + + // If classic CLI, do not spawn processes, execute directly + if (isClassicCli) { + await Weaver.setupWeaver(args, this.config); + + Weaver.start(); + + await Weaver.executeScript(args, this.config); + Weaver.shutdown(); + process.exit(0); + } + if (this.midExecution) return; this.midExecution = true; const activeProcess = Object.values(getActiveChildProcesses())[0]; @@ -81,11 +138,13 @@ export default class WeaverLauncher { } } - const child = fork( - this.config.weaverFileName - ? fileURLToPath(import.meta.resolve(this.config.weaverFileName)) - : path.join(dirname(fileURLToPath(import.meta.url)), "Weaver.js") - ); + const weaverScript = this.config.weaverFileName + ? fileURLToPath(import.meta.resolve(this.config.weaverFileName)) + : path.join(dirname(fileURLToPath(import.meta.url)), "Weaver.js"); + + console.debug("Launcher weaver using the script '" + weaverScript + "'"); + + const child = fork(weaverScript); child.send({ config: this.config, args, @@ -95,7 +154,7 @@ export default class WeaverLauncher { this.midExecution = false; } - protected generateConfig(args: string | undefined = undefined) { + protected generateConfig(args: string[] | undefined = undefined) { return yargs(args ?? hideBin(process.argv)) .scriptName(this.config.weaverName) .command({