From 7b77df78b5d4788188406f9d49e1417be17faee9 Mon Sep 17 00:00:00 2001 From: Geoffrey Hendrey Date: Tue, 1 Oct 2024 12:38:27 -0700 Subject: [PATCH] Fix repl open (#84) * v0.1.38 * restore .open command which got accidentally yanked when refactoring CLI. Add test. --- package.json | 2 +- src/CliCore.ts | 62 +++++++++++++++++++++++++++++++++++++ src/StatedREPL.ts | 1 + src/test/CliCore.test.js | 1 + src/test/StatedREPL.test.js | 21 +++++++++++++ 5 files changed, 86 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b380b80..fd809a0f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stated-js", - "version": "0.1.37", + "version": "0.1.39", "license": "Apache-2.0", "description": "JSONata embedded in JSON", "main": "./dist/src/index.js", diff --git a/src/CliCore.ts b/src/CliCore.ts index 17079df8..f70ea306 100644 --- a/src/CliCore.ts +++ b/src/CliCore.ts @@ -17,6 +17,7 @@ import * as repl from 'repl'; import {stringifyTemplateJSON} from "./utils/stringify.js"; import jsonata from "jsonata"; import {CliCoreBase} from "./CliCoreBase.js"; +import fs from 'fs'; export default class CliCore extends CliCoreBase{ @@ -27,6 +28,67 @@ export default class CliCore extends CliCoreBase{ super(templateProcessor); } + public async open(directory: string = this.currentDirectory) { + if(directory === ""){ + directory = this.currentDirectory; + } + + let files: string[]|undefined = undefined; + try { + // Read all files from the directory + files = await fs.promises.readdir(directory); + } catch (error) { + console.log(`Error reading directory ${directory}: ${error}`); + console.log('Changed directory with .cd or .open an/existing/directory'); + this.replServer.displayPrompt(); + return {error: `Error reading directory ${directory}: ${error}`}; + } + // Filter out only .json and .yaml files + const templateFiles: string[] = files.filter(file => file.endsWith('.json') || file.endsWith('.yaml')); + + // Display the list of files to the user + templateFiles.forEach((file, index) => { + console.log(`${index + 1}: ${file}`); + }); + + // Create an instance of AbortController + const ac = new AbortController(); + const {signal} = ac; // Get the AbortSignal from the controller + + // Ask the user to choose a file + this.replServer.question('Enter the number of the file to open (or type "abort" to cancel): ', {signal}, async (answer) => { + // Check if the operation was aborted + if (signal.aborted) { + console.log('File open operation was aborted.'); + this.replServer.displayPrompt(); + return; + } + + const fileIndex = parseInt(answer, 10) - 1; // Convert to zero-based index + if (fileIndex >= 0 && fileIndex < templateFiles.length) { + // User has entered a valid file number; initialize with this file + const filepath = templateFiles[fileIndex]; + try { + const result = await this.init(`-f "${filepath}"`); // Adjust this call as per your init method's expected format + console.log(stringifyTemplateJSON(result)); + console.log("...try '.out' or 'template.output' to see evaluated template") + } catch (error) { + console.log('Error loading file:', error); + } + } else { + console.log('Invalid file number.'); + } + this.replServer.displayPrompt(); + }); + + // Allow the user to type "abort" to cancel the file open operation + this.replServer.once('SIGINT', () => { + ac.abort(); + }); + + return "open... (type 'abort' to cancel)"; + } + public async tail(args: string): Promise { console.log("Started tailing... Press Ctrl+C to stop.") diff --git a/src/StatedREPL.ts b/src/StatedREPL.ts index e3d764fd..fd3c5f5b 100755 --- a/src/StatedREPL.ts +++ b/src/StatedREPL.ts @@ -140,6 +140,7 @@ export default class StatedREPL { console.error(stringify(e.message)); } this.replServer.displayPrompt(); + return true; } static colorize(s:string):string{ diff --git a/src/test/CliCore.test.js b/src/test/CliCore.test.js index fa84d8e7..9f8d23ba 100644 --- a/src/test/CliCore.test.js +++ b/src/test/CliCore.test.js @@ -167,3 +167,4 @@ test("import and run __init function", async () => { + diff --git a/src/test/StatedREPL.test.js b/src/test/StatedREPL.test.js index 5491d0b2..0053f608 100644 --- a/src/test/StatedREPL.test.js +++ b/src/test/StatedREPL.test.js @@ -95,6 +95,25 @@ if(typeof Bun === "undefined") { //run on node, not bun } }); + test("open", async () => { + const originalCmdLineArgsStr = process.argv; + process.argv = ["node", "dist/stated.js"]; // this is an argv when running stated.js repl. + // extend CliCore with restore command + const repl = new StatedREPL(); + + try { + await repl.initialize(); + + // we call restore on the repl, which will expect it to be defined in CliCore. + const msg = await repl.cli('open'); + + expect(msg).toBe(true); + } finally { + process.argv = originalCmdLineArgsStr; + if (repl !== undefined) await repl.close(); + } + }); + } // This test validates a bug when running an init command in StatedREPL overwrites context of provided TemplateProcessor @@ -113,3 +132,5 @@ test("TemplateProcessor keeps context on init", async () => { ); }); + +