From 793ef72e981b1abde1fe6033e797d7ba950d6c71 Mon Sep 17 00:00:00 2001 From: jeromesimeon Date: Sat, 7 Aug 2021 10:59:33 -0400 Subject: [PATCH] fix(cli) Add --output option to import/export commands in CLI Signed-off-by: jeromesimeon --- packages/concerto-cli/index.js | 25 +++++++++++------- packages/concerto-cli/lib/commands.js | 17 +++++++++--- packages/concerto-cli/test/cli.js | 37 ++++++++++++++++++++------- 3 files changed, 58 insertions(+), 21 deletions(-) diff --git a/packages/concerto-cli/index.js b/packages/concerto-cli/index.js index 511a09fa39..6f62d61536 100755 --- a/packages/concerto-cli/index.js +++ b/packages/concerto-cli/index.js @@ -161,10 +161,16 @@ require('yargs') type: 'boolean', default: false }); + yargs.option('output', { + describe: 'path to the output file', + type: 'string' + }); }, (argv) => { - return Commands.import(argv.input, argv.model, argv.resolve) + return Commands.import(argv.input, argv.model, argv.resolve, argv.output) .then((result) => { - Logger.info(result); + if (result) { + Logger.info(result); + } }) .catch((err) => { Logger.error(err.message); @@ -172,19 +178,20 @@ require('yargs') }) .command('export', 'export a metamodel to cto syntax', (yargs) => { yargs.demandOption(['input'], 'Please provide an input metamodel'); - yargs.option('model', { - describe: 'array of concerto (cto) model files', - type: 'string', - array: true - }); yargs.option('input', { describe: 'the metamodel to export', type: 'string' }); + yargs.option('output', { + describe: 'path to the output file', + type: 'string' + }); }, (argv) => { - return Commands.export(argv.input, argv.model) + return Commands.export(argv.input, argv.output) .then((result) => { - Logger.info(result); + if (result) { + Logger.info(result); + } }) .catch((err) => { Logger.error(err.message); diff --git a/packages/concerto-cli/lib/commands.js b/packages/concerto-cli/lib/commands.js index 6a87de210c..fdb31d2f6c 100644 --- a/packages/concerto-cli/lib/commands.js +++ b/packages/concerto-cli/lib/commands.js @@ -191,9 +191,10 @@ class Commands { * @param {string} input - CTO * @param {string[]} [ctoFiles] - the CTO files used for import resolution * @param {boolean} resolve - whether to resolve the names + * @param {string} outputPath to an output file * @param {string} the metamodel */ - static async import(input, ctoFiles = [], resolve) { + static async import(input, ctoFiles = [], resolve = false, outputPath) { // Add input to ctoFiles for convenience if (!ctoFiles.includes(input)) { ctoFiles.push(input); @@ -206,6 +207,11 @@ class Commands { } else { result = MetaModel.ctoToMetaModel(inputString); } + if (outputPath) { + Logger.info('Creating file: ' + outputPath); + fs.writeFileSync(outputPath, JSON.stringify(result)); + return; + } return JSON.stringify(result); } @@ -213,13 +219,18 @@ class Commands { * Export a metamodel to a CTO string * * @param {string} input metamodel - * @param {string[]} ctoFiles - the CTO files used for import resolution + * @param {string} outputPath to an output file * @param {string} transformed (meta)model */ - static async export(input, ctoFiles) { + static async export(input, outputPath) { const inputString = fs.readFileSync(input, 'utf8'); const json = JSON.parse(inputString); const result = MetaModel.ctoFromMetaModel(json); + if (outputPath) { + Logger.info('Creating file: ' + outputPath); + fs.writeFileSync(outputPath, result); + return; + } return result; } } diff --git a/packages/concerto-cli/test/cli.js b/packages/concerto-cli/test/cli.js index 2fdf2efe87..1ea2d1a6ab 100644 --- a/packages/concerto-cli/test/cli.js +++ b/packages/concerto-cli/test/cli.js @@ -124,19 +124,19 @@ describe('cicero-cli', () => { describe('#compile', () => { it('should compile to a Go model', async () => { - const dir = await tmp.dir({ unsafeCleanup: true}); + const dir = await tmp.dir({ unsafeCleanup: true }); await Commands.compile('Go', models, dir.path, {offline:false}); fs.readdirSync(dir.path).length.should.be.above(0); dir.cleanup(); }); it('should compile to a PlantUML model', async () => { - const dir = await tmp.dir({ unsafeCleanup: true}); + const dir = await tmp.dir({ unsafeCleanup: true }); await Commands.compile('PlantUML', models, dir.path, {offline:false}); fs.readdirSync(dir.path).length.should.be.above(0); dir.cleanup(); }); it('should compile to a Typescript model', async () => { - const dir = await tmp.dir({ unsafeCleanup: true}); + const dir = await tmp.dir({ unsafeCleanup: true }); await Commands.compile('Typescript', models, dir.path, {offline:false}); fs.readdirSync(dir.path).length.should.be.above(0); dir.cleanup(); @@ -148,25 +148,25 @@ describe('cicero-cli', () => { dir.cleanup(); }); it('should compile to a JSONSchema model', async () => { - const dir = await tmp.dir({ unsafeCleanup: true}); + const dir = await tmp.dir({ unsafeCleanup: true }); await Commands.compile('JSONSchema', models, dir.path, {offline:false}); fs.readdirSync(dir.path).length.should.be.above(0); dir.cleanup(); }); it('should compile to a XMLSchema model', async () => { - const dir = await tmp.dir({ unsafeCleanup: true}); + const dir = await tmp.dir({ unsafeCleanup: true }); await Commands.compile('XMLSchema', models, dir.path, {offline:false}); fs.readdirSync(dir.path).length.should.be.above(0); dir.cleanup(); }); it('should compile to a GraphQL model', async () => { - const dir = await tmp.dir({ unsafeCleanup: true}); + const dir = await tmp.dir({ unsafeCleanup: true }); await Commands.compile('GraphQL', models, dir.path, {offline:false}); fs.readdirSync(dir.path).length.should.be.above(0); dir.cleanup(); }); it('should not compile to an unknown model', async () => { - const dir = await tmp.dir({ unsafeCleanup: true}); + const dir = await tmp.dir({ unsafeCleanup: true }); await Commands.compile('BLAH', models, dir.path, {offline:false}); fs.readdirSync(dir.path).length.should.be.equal(0); dir.cleanup(); @@ -175,7 +175,7 @@ describe('cicero-cli', () => { describe('#get', () => { it('should save external dependencies', async () => { - const dir = await tmp.dir({ unsafeCleanup: true}); + const dir = await tmp.dir({ unsafeCleanup: true }); await Commands.get(models, dir.path); fs.readdirSync(dir.path).should.eql([ '@models.accordproject.org.cicero.contract.cto', @@ -186,7 +186,7 @@ describe('cicero-cli', () => { }); it('should save external dependencies for an external model', async () => { - const dir = await tmp.dir({ unsafeCleanup: true}); + const dir = await tmp.dir({ unsafeCleanup: true }); await Commands.get(['https://models.accordproject.org/patents/patent.cto'], dir.path); fs.readdirSync(dir.path).should.eql([ '@models.accordproject.org.address.cto', @@ -210,6 +210,15 @@ describe('cicero-cli', () => { result.should.deep.equal(expected); }); + it('should transform cto to metamodel and save it', async () => { + const output = await tmp.file({ unsafeCleanup: true }); + const expected = JSON.parse(fs.readFileSync(path.resolve(__dirname, 'models/contract.json'))); + await Commands.import(path.resolve(__dirname, 'models/contract.cto'), undefined, undefined, output.path); + const result = JSON.parse(fs.readFileSync(output.path)); + result.should.deep.equal(expected); + output.cleanup(); + }); + it('should transform cto to metamodel and resolve names', async () => { const expected = JSON.parse(fs.readFileSync(path.resolve(__dirname, 'models/contractResolved.json'))); const contractFile = path.resolve(__dirname, 'models/contract.cto'); @@ -225,5 +234,15 @@ describe('cicero-cli', () => { const result = await Commands.export(metamodel); result.should.equal(expected); }); + + it('should transform a metamodel to cto and save it', async () => { + const output = await tmp.file({ unsafeCleanup: true }); + const expected = fs.readFileSync(path.resolve(__dirname, 'models/contract2.cto'), 'utf-8'); + const metamodel = path.resolve(__dirname, 'models/contract.json'); + await Commands.export(metamodel, output.path); + const result = fs.readFileSync(output.path, 'utf-8'); + result.should.equal(expected); + output.cleanup(); + }); }); }); \ No newline at end of file