diff --git a/README.md b/README.md index dcd1160c..7894c4f2 100644 --- a/README.md +++ b/README.md @@ -376,6 +376,73 @@ The `.errors` command will produce a report of all errors in the template "message": "The right side of the \"+\" operator must evaluate to a number" } } +``` +## $errorReport function +JSONata does not have a `throw/catch` syntax. However, JSONata has a `$error` function that you can use +to throw an error. However, doing so will end the execution of the JSONata expression. If you wish to +simply record the fact that an error occured without exiting the expression, use the `$errorReport` function +which returns an error object but does not throw. +```json +> .init -f example/errorReport.json +{ + "a": [ + 0, + 1, + 2, + "${$errorReport('oops', 'my_custom_error')}", + 4, + 5 + ], + "b": "${($errorReport('e0');$errorReport('e1');$errorReport('e2'))}" +} +> .out +{ + "a": [ + 0, + 1, + 2, + { + "error": { + "message": "oops", + "name": "my_custom_error" + } + }, + 4, + 5 + ], + "b": { + "error": { + "message": "e2" + } + } +} +> .errors +{ + "/a/3": { + "error": { + "message": "oops", + "name": "my_custom_error" + } + }, + "/b": [ + { + "error": { + "message": "e0" + } + }, + { + "error": { + "message": "e1" + } + }, + { + "error": { + "message": "e2" + } + } + ] +} + ``` ## Expressions and Variables What makes a Stated template different from an ordinary JSON file? JSONata Expressions of course! Stated analyzes the diff --git a/example/errorReport.json b/example/errorReport.json new file mode 100644 index 00000000..5bcd9c8d --- /dev/null +++ b/example/errorReport.json @@ -0,0 +1,11 @@ +{ + "a": [ + 0, + 1, + 2, + "${$errorReport('oops', 'my_custom_error')}", + 4, + 5 + ], + "b": "${($errorReport('e0');$errorReport('e1');$errorReport('e2'))}" +} diff --git a/src/CliCore.ts b/src/CliCore.ts index 27596236..6721b299 100644 --- a/src/CliCore.ts +++ b/src/CliCore.ts @@ -31,7 +31,7 @@ export default class CliCore { constructor(templateProcessor: TemplateProcessor = null) { this.templateProcessor = templateProcessor; this.logLevel = "info"; - this.currentDirectory = path.join(process.cwd(), 'example'); // Default to cwd/example + this.currentDirectory = process.cwd(); } public close(){ if(this.templateProcessor){ @@ -117,7 +117,11 @@ export default class CliCore { if(filepath===undefined){ return undefined; } - const input = await this.readFileAndParse(filepath, importPath); + let _filepath = filepath; + if(this.currentDirectory){ + _filepath = path.join(this.currentDirectory, _filepath); + } + const input = await this.readFileAndParse(_filepath, importPath); const contextData = contextFilePath ? await this.readFileAndParse(contextFilePath, importPath) : {}; options.importPath = importPath; //path is where local imports will be sourced from. We sneak path in with the options // if we initialize for the first time, we need to create a new instance of TemplateProcessor @@ -364,9 +368,9 @@ public async open(directory: string = this.currentDirectory) { 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 = path.join(directory, templateFiles[fileIndex]); + const filepath = templateFiles[fileIndex]; try { - const result = await this.init(`-f "${filepath}"`); // Adjust this call as per your init method's expected format + const result = await this.init(`-f "${filepath}"`); console.log(StatedREPL.stringify(result)); console.log("...try '.out' or 'template.output' to see evaluated template") } catch (error) { diff --git a/src/StatedREPL.ts b/src/StatedREPL.ts index 0bbeaf2e..764b7237 100755 --- a/src/StatedREPL.ts +++ b/src/StatedREPL.ts @@ -109,7 +109,7 @@ export default class StatedREPL { } async cli(cliCoreMethodName, args){ - let result; + let result=""; try{ const method = this.cliCore[cliCoreMethodName].bind(this.cliCore); result = await method(args);