Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(apply): added cli support for decorators and vocab #37

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,4 @@ Copyright 2018-2019 Clause, Inc. All trademarks are the property of their respec
[developers]: https://github.com/accordproject/web-components/blob/master/DEVELOPERS.md

[apache]: https://github.com/accordproject/web-components/blob/master/LICENSE
[creativecommons]: http://creativecommons.org/licenses/by/4.0/
[creativecommons]: http://creativecommons.org/licenses/by/4.0/
48 changes: 48 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
.then((result) => {
Logger.info('Input is valid');
if (!options.functional) {
console.log(result);

Check warning on line 70 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, ubuntu-latest)

Unexpected console statement

Check warning on line 70 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, ubuntu-latest)

Unexpected console statement

Check warning on line 70 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, macOS-latest)

Unexpected console statement

Check warning on line 70 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, macOS-latest)

Unexpected console statement

Check warning on line 70 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, windows-latest)

Unexpected console statement

Check warning on line 70 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, windows-latest)

Unexpected console statement
}
})
.catch((err) => {
Expand Down Expand Up @@ -234,7 +234,7 @@
return Commands.parse(argv.model, argv.resolve, argv.all, argv.output, options)
.then((result) => {
if (result) {
console.log(result);

Check warning on line 237 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, ubuntu-latest)

Unexpected console statement

Check warning on line 237 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, ubuntu-latest)

Unexpected console statement

Check warning on line 237 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, macOS-latest)

Unexpected console statement

Check warning on line 237 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, macOS-latest)

Unexpected console statement

Check warning on line 237 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, windows-latest)

Unexpected console statement

Check warning on line 237 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, windows-latest)

Unexpected console statement
}
})
.catch((err) => {
Expand Down Expand Up @@ -353,7 +353,7 @@
if (argv.output){
fs.writeFileSync(argv.output, cto);
} else {
console.log(cto);

Check warning on line 356 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, ubuntu-latest)

Unexpected console statement

Check warning on line 356 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, ubuntu-latest)

Unexpected console statement

Check warning on line 356 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, macOS-latest)

Unexpected console statement

Check warning on line 356 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, macOS-latest)

Unexpected console statement

Check warning on line 356 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, windows-latest)

Unexpected console statement

Check warning on line 356 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, windows-latest)

Unexpected console statement
}
} catch (err){
Logger.error(err);
Expand Down Expand Up @@ -402,12 +402,60 @@
strict: argv.strict,
})
.then(obj => {
console.log(JSON.stringify(obj, null, 2));

Check warning on line 405 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, ubuntu-latest)

Unexpected console statement

Check warning on line 405 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, ubuntu-latest)

Unexpected console statement

Check warning on line 405 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, macOS-latest)

Unexpected console statement

Check warning on line 405 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, macOS-latest)

Unexpected console statement

Check warning on line 405 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, windows-latest)

Unexpected console statement

Check warning on line 405 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, windows-latest)

Unexpected console statement
})
.catch((err) => {
Logger.error(err.message);
});
})
.command('decorate', 'apply the decorators and vocabs to the target models from given list of dcs files and vocab files', yargs => {
yargs.demandOption('models', 'Please provide a model');
yargs.option('models', {
muskanbararia marked this conversation as resolved.
Show resolved Hide resolved
describe: 'The file location of the source models',
alias: 'model',
type: 'string',
array:true,
});
yargs.option('decorator', {
describe: 'List of dcs files to be applied to model',
type: 'string',
array:true
});
yargs.option('vocabulary', {
describe: 'List of vocab files to be applied to model',
type: 'string',
array:true
});
yargs.option('format', {
describe: 'Output format (json or cto)',
type: 'string',
default:'cto',
choices: ['json', 'cto']
});
yargs.option('output', {
describe: 'output directory path',
type: 'string',
});
yargs.check((args) => {
// Custom validation to ensure at least one of the two options is provided
if (!args.decorator && !args.vocabulary) {
throw new Error('You must provide at least one of dcs files or voc files');
}
return true;
});
}, argv => {
let options={};
options.format=argv.format;
options.output=argv.output;

return Commands.decorate(argv.models, argv.decorator,argv.vocabulary,options)
.then(obj => {
console.log(obj);

Check warning on line 453 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, ubuntu-latest)

Unexpected console statement

Check warning on line 453 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, ubuntu-latest)

Unexpected console statement

Check warning on line 453 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, macOS-latest)

Unexpected console statement

Check warning on line 453 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, macOS-latest)

Unexpected console statement

Check warning on line 453 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, windows-latest)

Unexpected console statement

Check warning on line 453 in index.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, windows-latest)

Unexpected console statement
})
.catch((err) => {
Logger.error(err.message);
});
})
.option('verbose', {
alias: 'v',
default: false
Expand Down
61 changes: 60 additions & 1 deletion lib/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
const CodeGen = require('@accordproject/concerto-codegen').CodeGen;

const { Compare, compareResultToString } = require('@accordproject/concerto-analysis');
const { ModelFile, ModelManager } = require('@accordproject/concerto-core');
const { ModelFile, ModelManager,DecoratorManager } = require('@accordproject/concerto-core');
const { VocabularyManager } = require('@accordproject/concerto-vocabulary');

/**
* Utility class that implements the commands exposed by the CLI.
Expand Down Expand Up @@ -282,12 +283,12 @@
for (const finding of results.findings) {
const result = compareResultToString(finding.result);
const coloredResult = this.colorCompareResult(result);
console.log(`[${finding.key}]: ${finding.message} (${coloredResult})`);

Check warning on line 286 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, ubuntu-latest)

Unexpected console statement

Check warning on line 286 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, ubuntu-latest)

Unexpected console statement

Check warning on line 286 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, macOS-latest)

Unexpected console statement

Check warning on line 286 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, macOS-latest)

Unexpected console statement

Check warning on line 286 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, windows-latest)

Unexpected console statement

Check warning on line 286 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, windows-latest)

Unexpected console statement
}
const result = compareResultToString(results.result);
const coloredResult = this.colorCompareResult(result);
console.log('');

Check warning on line 290 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, ubuntu-latest)

Unexpected console statement

Check warning on line 290 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, ubuntu-latest)

Unexpected console statement

Check warning on line 290 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, macOS-latest)

Unexpected console statement

Check warning on line 290 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, macOS-latest)

Unexpected console statement

Check warning on line 290 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, windows-latest)

Unexpected console statement

Check warning on line 290 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, windows-latest)

Unexpected console statement
console.log(`overall result: ${coloredResult}`);

Check warning on line 291 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, ubuntu-latest)

Unexpected console statement

Check warning on line 291 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, ubuntu-latest)

Unexpected console statement

Check warning on line 291 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, macOS-latest)

Unexpected console statement

Check warning on line 291 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, macOS-latest)

Unexpected console statement

Check warning on line 291 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (18.x, windows-latest)

Unexpected console statement

Check warning on line 291 in lib/commands.js

View workflow job for this annotation

GitHub Actions / Unit Tests (16.x, windows-latest)

Unexpected console statement
if (result === 'error') {
process.exit(1);
}
Expand Down Expand Up @@ -628,6 +629,64 @@
inferredConcertoJsonModel.models[0]
);
}

/**
* Decorate a given model with given list of dcs and vocab files and print the result
* @param {string} modelFiles - the model to which vocab and decorator has to be applied
* @param {string[]} dcsFiles - the decorator files to be applied to model
* @param {string[]} vocFiles - the vocab files to be applied to model
* @param {object} options - optional parameters
muskanbararia marked this conversation as resolved.
Show resolved Hide resolved
* @param {string} options.format - format of output models (CTO or JSON)
* @param {string} options.output - the output directory where the decorated models are to be written
* @returns {string} - Depending on the options, CTO string or JSON string
*/
static async decorate(modelFiles, dcsFiles,vocFiles,options) {
try {
const allModelContent = modelFiles.map(file => fs.readFileSync(file, 'utf-8'));
const allDCSFiles = dcsFiles ? dcsFiles.map(file => fs.readFileSync(file, 'utf-8')) : [];
const allVocsFiles = vocFiles ? vocFiles.map(file => fs.readFileSync(file, 'utf-8')) : [];
let modelManager = new ModelManager();
allModelContent.forEach(modelContent => {
modelManager.addModel(modelContent);
});
allDCSFiles.forEach(content => {
modelManager = DecoratorManager.decorateModels(modelManager, JSON.parse(content));
});
const vocManager = new VocabularyManager({ missingTermGenerator: VocabularyManager.englishMissingTermGenerator });
const namespace = modelManager.getNamespaces().filter(namespace=>namespace!=='[email protected]' && namespace!=='concerto');
allVocsFiles.forEach(content => {
vocManager.addVocabulary(content);
});
const vocabKeySet=[];
namespace.forEach(name=>{
let vocab = vocManager.getVocabulariesForNamespace(name);
vocab.forEach(voc=>vocabKeySet.push(voc.getLocale()));
});
vocabKeySet.map(voc=>{
let commandSet = vocManager.generateDecoratorCommands(modelManager, voc);
modelManager = DecoratorManager.decorateModels(modelManager, commandSet);
});
let result=[];
const extension = (options.format === 'cto') ? '.cto':'.json';
namespace.forEach(name=>{
let model = modelManager.getModelFile(name);
let modelAst=model.getAst();
let data = (options.format === 'cto') ? Printer.toCTO(modelAst):JSON.stringify(modelAst);
if (options.output) {
if (!fs.existsSync(options.output)) {
// If it doesn't exist, create the directory
fs.mkdirSync(options.output);
}
const filePath = path.join(options.output, model.namespace.split('@')[0]+extension);
fs.writeFileSync(filePath, data);
}
result.push(data);
});
return result;
} catch (e) {
throw new Error(e);
}
}
}

module.exports = Commands;
104 changes: 104 additions & 0 deletions test/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -682,4 +682,108 @@ describe('concerto-cli', () => {
expect(obj.fatherName.length >= 1).to.be.true;
});
});

describe('#decorate', () => {
it('should apply the list of decorators to model and output in cto by default', async () => {
const dir = await tmp.dir({ unsafeCleanup: true });
const model = [(path.resolve(__dirname, 'models', 'decorate-model.cto'))];
const decorators = [path.resolve(__dirname, 'data', 'decorate-dcs.json')];
const vocabs = undefined;
const options={
format:'cto'
};
const expected = fs.readFileSync(path.resolve(__dirname, 'models', 'decorate-model-expected-with-dcs.cto'),'utf-8');
const result =await Commands.decorate(model,decorators,vocabs,options);
result[0].replace(/[\r\n]+/g, '\n').should.equal(expected.replace(/[\r\n]+/g, '\n'));
dir.cleanup();
});

it('should apply the list of vocabs to the model and output in cto by default', async () => {
const dir = await tmp.dir({ unsafeCleanup: true });
const model = [path.resolve(__dirname, 'models', 'decorate-model.cto')];
const vocabs = [path.resolve(__dirname, 'data', 'decorate-voc')];
const decorators = undefined;
const options={
format:'cto'
};
const expected = fs.readFileSync(path.resolve(__dirname, 'models', 'decorate-model-expected-with-vocabs-only.cto'),'utf-8');
const result =await Commands.decorate(model,decorators,vocabs,options);
result[0].replace(/[\r\n]+/g, '\n').should.equal(expected.replace(/[\r\n]+/g, '\n'));
dir.cleanup();
});

it('should apply the list of vocabs and list of decorators to the model and output in asked format', async () => {
const dir = await tmp.dir({ unsafeCleanup: true });
const model = [path.resolve(__dirname, 'models', 'decorate-model.cto')];
const vocabs = [path.resolve(__dirname, 'data', 'decorate-voc')];
const decorators = [path.resolve(__dirname, 'data', 'decorate-dcs.json')];
const options={
format:'json'
};
const result =await Commands.decorate(model,decorators,vocabs,options);
let jsonObj=JSON.parse(result);
(typeof jsonObj).should.equal('object');
dir.cleanup();
});
it('should throw error if data is invalid', async () => {
const dir = await tmp.dir({ unsafeCleanup: true });
const model = [path.resolve(__dirname, 'models', 'decorate-invalid-model.cto')];
const vocabs = [path.resolve(__dirname, 'data', 'decorate-voc')];
const decorators =undefined;
const options={
format:'json'
};
const expected = fs.readFileSync(path.resolve(__dirname, 'models', 'decorate-model-expected-with-vocabs-and-deco.json'),'utf-8');
try {
const result =await Commands.decorate(model,decorators,vocabs,options);
result.should.eql(expected);
} catch (err) {
(typeof err).should.equal('object');
}
dir.cleanup();
});
it('should write to a file if output is provided', async () => {
const output = await tmp.dir({ unsafeCleanup: true });
const model = [path.resolve(__dirname, 'models', 'decorate-model.cto')];
const vocabs = [path.resolve(__dirname, 'data', 'decorate-voc')];
const decorators =undefined;
const options={
format:'json',
output:output.path
};
await Commands.decorate(model,decorators,vocabs,options);
const files = fs.readdirSync(output.path);
const anyFileExists = files.length > 0;
expect(anyFileExists).to.be.true;
output.cleanup();
});
it('should write to a file if output is provided and create the directory if it does not exist', async () => {
const output = await tmp.dir({ unsafeCleanup: true });
const model = [path.resolve(__dirname, 'models', 'decorate-model.cto')];
const vocabs = [path.resolve(__dirname, 'data', 'decorate-voc')];
const decorators =undefined;
const options={
format:'json',
output:output.path+'_output'
};
await Commands.decorate(model,decorators,vocabs,options);
const files = fs.readdirSync(output.path+'_output');
const anyFileExists = files.length > 0;
expect(anyFileExists).to.be.true;
output.cleanup();
});
it('should apply decorators when the model files are having dependency', async () => {
const dir = await tmp.dir({ unsafeCleanup: true });
const model = [path.resolve(__dirname, 'models', 'version-c.cto'),path.resolve(__dirname, 'models', 'version-b.cto')];
const vocabs = undefined;
const decorators =[path.resolve(__dirname, 'data', 'decorate-dcs.json')];
const options={
format:'cto',
};
const expected = fs.readFileSync(path.resolve(__dirname, 'models', 'decorate-model-expected-with-dependency.cto'),'utf-8');
const result =await Commands.decorate(model,decorators,vocabs,options);
result[0].replace(/[\r\n]+/g, '\n').should.equal(expected.replace(/[\r\n]+/g, '\n'));
dir.cleanup();
});
});
});
51 changes: 51 additions & 0 deletions test/data/decorate-dcs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"$class": "org.accordproject.decoratorcommands.DecoratorCommandSet",
"name": "pii",
"version": "1.0.0",
"commands": [
{
"$class": "org.accordproject.decoratorcommands.Command",
"type": "UPSERT",
"target": {
"$class": "org.accordproject.decoratorcommands.CommandTarget",
"property": "ssn"
},
"decorator": {
"$class": "[email protected]",
"name": "PII",
"arguments": [
]
}
},
{
"$class": "org.accordproject.decoratorcommands.Command",
"type": "UPSERT",
"target": {
"$class": "org.accordproject.decoratorcommands.CommandTarget",
"property": "bar"
},
"decorator": {
"$class": "[email protected]",
"name": "PII",
"arguments": [
]
}
},
{
"$class": "org.accordproject.decoratorcommands.Command",
"type": "UPSERT",
"target": {
"$class": "org.accordproject.decoratorcommands.CommandTarget",
"type": "[email protected]"
},
"decorator": {
"$class": "[email protected]",
"name": "Hide",
"arguments": [{
"$class" : "[email protected]",
"value" : "object"
}]
}
}
]
}
6 changes: 6 additions & 0 deletions test/data/decorate-voc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
locale: en-gb
namespace: [email protected]
declarations:
- Driver: A driver of a vehicle
properties:
- favoriteColor: favourite colour
Empty file.
23 changes: 23 additions & 0 deletions test/models/decorate-model-expected-with-dcs.cto
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace [email protected]

abstract concept Person identified by ssn {
o String firstName
o String lastName
@PII()
o String ssn
}

concept Driver extends Person {
o String favoriteColor
}

concept Employee {
@PII()
o String ssn
}

concept Car identified by vin {
o String vin
@Hide("object")
o Person owner
}
6 changes: 6 additions & 0 deletions test/models/decorate-model-expected-with-dependency.cto
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace [email protected]

concept Boo {
@PII()
o String bar
}
Loading
Loading