diff --git a/README.md b/README.md index 7894c4f2..498bad82 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ Stated templates are modular and can be imported from a URL: } ``` + ## Why Do We Need stated? Consider this ordinary program: @@ -1719,6 +1720,38 @@ This can be combined with the `--importPath` option to import files relative to "res": "bar: foo" } ``` +## The $open function +Allowing expressions to open local files is a security risk. For this reason the core TemplateProcessor does +not support the $open function. However, the CLI/REPL which are for local usage allow the $open function. Additionally, +programs that want to allow properly guarded `$open` operations may inject a `$open` function of their choosing +into the TemplateProcessor contexet. $open accepts a relative path, and parses the JSON or YAML file on that path into +an object. +```json [false, "true", false, "a.c='the answer is: 42' and b.c='the answer is: 42'", "true"] +> .note This shows two equivalent ways to open a json or yaml file using $open +"=============================================================" +> .cd example +"Current directory changed to: /Users/falken/proj/jsonataexperiments/example" +> .init -f "importLocal.json" +{ + "a": "${'ex01.json'~>$open~>$import}", + "b": "${$import($open('ex01.json'))}" +} +> .out +{ + "a": { + "a": 42, + "b": 42, + "c": "the answer is: 42" + }, + "b": { + "a": 42, + "b": 42, + "c": "the answer is: 42" + } +} +> .cd .. +"Current directory changed to: /Users/falken/proj/jsonataexperiments" +``` # Understanding Plans This information is to explain the planning algorithms to comitters. As a user you do not need to understand how Stated formulates plans. Before explaining how a plan is made, let's show the end-to-end flow of how a plan is used diff --git a/example/importLocal.json b/example/importLocal.json new file mode 100644 index 00000000..c1117e35 --- /dev/null +++ b/example/importLocal.json @@ -0,0 +1,4 @@ +{ + "a": "${'ex01.json'~>$open~>$import}", + "b": "${$import($open('ex01.json'))}" +} \ No newline at end of file diff --git a/src/CliCore.ts b/src/CliCore.ts index 6721b299..4fa5f407 100644 --- a/src/CliCore.ts +++ b/src/CliCore.ts @@ -65,7 +65,7 @@ export default class CliCore { return {...parsed, ...processedArgs}; //spread the processedArgs back into what was parsed } - async readFileAndParse(filepath, importPath) { + async readFileAndParse(filepath, importPath?) { const fileExtension = path.extname(filepath).toLowerCase().replace(/\W/g, ''); if (fileExtension === 'js' || fileExtension === 'mjs') { return await import(CliCore.resolveImportPath(filepath, importPath)); @@ -117,11 +117,7 @@ export default class CliCore { if(filepath===undefined){ return undefined; } - let _filepath = filepath; - if(this.currentDirectory){ - _filepath = path.join(this.currentDirectory, _filepath); - } - const input = await this.readFileAndParse(_filepath, importPath); + const input = await this.openFile(filepath); 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 @@ -143,7 +139,7 @@ export default class CliCore { // set options this.templateProcessor.logger.level = this.logLevel; this.templateProcessor.logger.debug(`arguments: ${JSON.stringify(parsed)}`); - + this.templateProcessor.context["open"] = this.openFile.bind(this); //$open('foo.json') is supported by the CLI adding $open function. It is not part of core TemplateProcessor as that would be security hole try { await this.templateProcessor.initialize(input); if (oneshot === true) { @@ -163,6 +159,14 @@ export default class CliCore { } + private async openFile(fname:string){ + let _filepath = fname; + if(this.currentDirectory){ + _filepath = path.join(this.currentDirectory, _filepath); + } + return await this.readFileAndParse(_filepath); + } + async set(args) { const options = args.match(/(?:[^\s"]+|"[^"]*")+/g); diff --git a/src/TestUtils.ts b/src/TestUtils.ts index 67419cf1..b525c8c6 100644 --- a/src/TestUtils.ts +++ b/src/TestUtils.ts @@ -109,7 +109,7 @@ function runMarkdownTests(testData: CommandAndResponse[], cliCore:CliCore, print expect(responseNormalized).toBeDefined(); } } - }, 30000); // set timeout to 30 seconds for each test + }, 100000); // set timeout to 100 seconds for each test }); }finally { cliCore.close();