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 2 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
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,22 @@ Options:
--output output directory path [string] [default: "./"]
```

### Concerto Decorate

The `decorate` command allows you to add decorators and vocabularies to your local CTO file from a set of local DCS and Vocab Command Set files

```
concerto decorate

apply the decorators and vocabs to the target models from given list of dcs files and vocab files

Options:
--model The CTO file
--voc The List of vocab files
--dcs The List of decorator command set files
--f output format (cto or json), default: cto
muskanbararia marked this conversation as resolved.
Show resolved Hide resolved
```

## License <a name="license"></a>
Accord Project source code files are made available under the Apache License, Version 2.0 (Apache-2.0), located in the LICENSE file. Accord Project documentation files are made available under the Creative Commons Attribution 4.0 International License (CC-BY-4.0), available at http://creativecommons.org/licenses/by/4.0/.

41 changes: 41 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 (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 (16.x, macOS-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 (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 (16.x, macOS-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 (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 (16.x, macOS-latest)

Unexpected console statement
}
} catch (err){
Logger.error(err);
Expand Down Expand Up @@ -402,12 +402,53 @@
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 (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 (16.x, macOS-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('model', 'Please provide a model');
yargs.option('model', {
describe: 'The file location of the source model',
type: 'string',
});
yargs.option('dcs', {
describe: 'List of dcs files to be applied to model',
type: 'string',
array:true
});
yargs.option('voc', {
describe: 'List of vocab files to be applied to model',
type: 'string',
array:true
});
yargs.option('f', {
describe: 'Output format (json or cto)',
type: 'string',
default:'cto',
choices: ['json', 'cto']
});
yargs.check((args) => {
// Custom validation to ensure at least one of the two options is provided
if (!args.dcs && !args.voc) {
throw new Error('You must provide at least one of dcs files or voc files');
}
return true;
});
}, argv => {
let options={};
options.format=argv.f;

return Commands.decorate(argv.model, argv.dcs,argv.voc,options)
.then(obj => {
console.log(obj);

Check warning on line 446 in index.js

View workflow job for this annotation

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

Unexpected console statement

Check warning on line 446 in index.js

View workflow job for this annotation

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

Unexpected console statement

Check warning on line 446 in index.js

View workflow job for this annotation

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

Unexpected console statement

Check warning on line 446 in index.js

View workflow job for this annotation

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

Unexpected console statement
})
.catch((err) => {
Logger.error(err.message);
});
})
.option('verbose', {
alias: 'v',
default: false
Expand Down
44 changes: 43 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 (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 (16.x, macOS-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 (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 (16.x, macOS-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 (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 (16.x, macOS-latest)

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

/**
* Decorate a given model with given list of dcs and vocab files and print the result
* @param {string} modelFile - 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
* @returns {string} - Depending on the options, CTO string or JSON string
*/
static async decorate(modelFile, dcsFiles,vocFiles,options) {
try {
const modelContent = fs.readFileSync(path.resolve(modelFile), 'utf-8');
const allDCSFiles = dcsFiles ? dcsFiles.map(file => fs.readFileSync(file, 'utf8')) : [];
const allVocsFiles = vocFiles ? vocFiles.map(file => fs.readFileSync(file, 'utf8')) : [];
const modelManager = new ModelManager();
modelManager.addModel(modelContent);
muskanbararia marked this conversation as resolved.
Show resolved Hide resolved
let updatedModelManager = modelManager;
muskanbararia marked this conversation as resolved.
Show resolved Hide resolved
if (allDCSFiles.length > 0) {
muskanbararia marked this conversation as resolved.
Show resolved Hide resolved
allDCSFiles.forEach(content => {
updatedModelManager = DecoratorManager.decorateModels(updatedModelManager, JSON.parse(content));
});
}
if (allVocsFiles.length > 0) {
const vocManager = new VocabularyManager({ missingTermGenerator: VocabularyManager.englishMissingTermGenerator });
allVocsFiles.forEach(content => {
vocManager.addVocabulary(content);
});
const commandSet = vocManager.generateDecoratorCommands(updatedModelManager, 'en-gb');
updatedModelManager = DecoratorManager.decorateModels(updatedModelManager, commandSet);
}
const namespace = updatedModelManager.getModels().map(obj=>obj.name.replace(/\.cto$/, ''))[0];
let modelAst = updatedModelManager.getModelFile(namespace).getAst();
if (options.format === 'cto') {
return Printer.toCTO(modelAst);
} else {
return JSON.stringify(modelAst);
}
} catch (e) {
throw new Error(e);
}
}
}

module.exports = Commands;
61 changes: 61 additions & 0 deletions test/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -682,4 +682,65 @@ 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.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.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 expected = fs.readFileSync(path.resolve(__dirname, 'models', 'decorate-model-expected-with-vocabs-and-deco.json'),'utf-8');
const result =await Commands.decorate(model,decorators,vocabs,options);
result.should.equal(expected);
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();
});
});
});
37 changes: 37 additions & 0 deletions test/data/decorate-dcs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"$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",
"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
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"$class":"[email protected]","decorators":[],"namespace":"[email protected]","imports":[],"declarations":[{"$class":"[email protected]","name":"Person","isAbstract":true,"properties":[{"$class":"[email protected]","name":"firstName","isArray":false,"isOptional":false,"location":{"$class":"[email protected]","start":{"offset":74,"line":5,"column":5,"$class":"[email protected]"},"end":{"offset":98,"line":6,"column":5,"$class":"[email protected]"}},"decorators":[{"$class":"[email protected]","name":"Term","arguments":[{"$class":"[email protected]","value":"First Name of the Person"}]}]},{"$class":"[email protected]","name":"lastName","isArray":false,"isOptional":false,"location":{"$class":"[email protected]","start":{"offset":98,"line":6,"column":5,"$class":"[email protected]"},"end":{"offset":119,"line":7,"column":3,"$class":"[email protected]"}},"decorators":[{"$class":"[email protected]","name":"Term","arguments":[{"$class":"[email protected]","value":"Last Name of the Person"}]}]},{"$class":"[email protected]","name":"ssn","isArray":false,"isOptional":false,"location":{"$class":"[email protected]","start":{"offset":119,"line":7,"column":3,"$class":"[email protected]"},"end":{"offset":133,"line":8,"column":1,"$class":"[email protected]"}},"decorators":[{"$class":"[email protected]","name":"PII","arguments":[]},{"$class":"[email protected]","name":"Term","arguments":[{"$class":"[email protected]","value":"Ssn of the Person"}]}]}],"location":{"$class":"[email protected]","start":{"offset":24,"line":3,"column":1,"$class":"[email protected]"},"end":{"offset":134,"line":8,"column":2,"$class":"[email protected]"}},"identified":{"$class":"[email protected]","name":"ssn"},"decorators":[{"$class":"[email protected]","name":"Term","arguments":[{"$class":"[email protected]","value":"Person"}]}]},{"$class":"[email protected]","name":"Driver","isAbstract":false,"properties":[{"$class":"[email protected]","name":"favoriteColor","isArray":false,"isOptional":false,"location":{"$class":"[email protected]","start":{"offset":173,"line":11,"column":3,"$class":"[email protected]"},"end":{"offset":197,"line":12,"column":1,"$class":"[email protected]"}},"decorators":[{"$class":"[email protected]","name":"Term","arguments":[{"$class":"[email protected]","value":"favourite colour"}]}]}],"location":{"$class":"[email protected]","start":{"offset":138,"line":10,"column":1,"$class":"[email protected]"},"end":{"offset":198,"line":12,"column":2,"$class":"[email protected]"}},"superType":{"$class":"[email protected]","name":"Person","namespace":"[email protected]"},"decorators":[{"$class":"[email protected]","name":"Term","arguments":[{"$class":"[email protected]","value":"A driver of a vehicle"}]}]},{"$class":"[email protected]","name":"Employee","isAbstract":false,"properties":[{"$class":"[email protected]","name":"ssn","isArray":false,"isOptional":false,"location":{"$class":"[email protected]","start":{"offset":224,"line":15,"column":3,"$class":"[email protected]"},"end":{"offset":238,"line":16,"column":1,"$class":"[email protected]"}},"decorators":[{"$class":"[email protected]","name":"PII","arguments":[]},{"$class":"[email protected]","name":"Term","arguments":[{"$class":"[email protected]","value":"Ssn of the Employee"}]}]}],"location":{"$class":"[email protected]","start":{"offset":202,"line":14,"column":1,"$class":"[email protected]"},"end":{"offset":239,"line":16,"column":2,"$class":"[email protected]"}},"decorators":[{"$class":"[email protected]","name":"Term","arguments":[{"$class":"[email protected]","value":"Employee"}]}]},{"$class":"[email protected]","name":"Car","isAbstract":false,"properties":[{"$class":"[email protected]","name":"vin","isArray":false,"isOptional":false,"location":{"$class":"[email protected]","start":{"offset":281,"line":20,"column":5,"$class":"[email protected]"},"end":{"offset":299,"line":21,"column":5,"$class":"[email protected]"}},"decorators":[{"$class":"[email protected]","name":"Term","arguments":[{"$class":"[email protected]","value":"Vin of the Car"}]}]},{"$class":"[email protected]","name":"owner","type":{"$class":"[email protected]","name":"Person","namespace":"[email protected]"},"isArray":false,"isOptional":false,"location":{"$class":"[email protected]","start":{"offset":299,"line":21,"column":5,"$class":"[email protected]"},"end":{"offset":315,"line":22,"column":1,"$class":"[email protected]"}},"decorators":[{"$class":"[email protected]","name":"Hide","arguments":[{"$class":"[email protected]","value":"object"}]},{"$class":"[email protected]","name":"Term","arguments":[{"$class":"[email protected]","value":"Owner of the Car"}]}]}],"location":{"$class":"[email protected]","start":{"offset":243,"line":18,"column":1,"$class":"[email protected]"},"end":{"offset":316,"line":22,"column":2,"$class":"[email protected]"}},"identified":{"$class":"[email protected]","name":"vin"},"decorators":[{"$class":"[email protected]","name":"Term","arguments":[{"$class":"[email protected]","value":"Car"}]}]}]}
31 changes: 31 additions & 0 deletions test/models/decorate-model-expected-with-vocabs-only.cto
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace [email protected]

@Term("Person")
abstract concept Person identified by ssn {
@Term("First Name of the Person")
o String firstName
@Term("Last Name of the Person")
o String lastName
@Term("Ssn of the Person")
o String ssn
}

@Term("A driver of a vehicle")
concept Driver extends Person {
@Term("favourite colour")
o String favoriteColor
}

@Term("Employee")
concept Employee {
@Term("Ssn of the Employee")
o String ssn
}

@Term("Car")
concept Car identified by vin {
@Term("Vin of the Car")
o String vin
@Term("Owner of the Car")
o Person owner
}
22 changes: 22 additions & 0 deletions test/models/decorate-model.cto
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace [email protected]

abstract concept Person identified by ssn
{
o String firstName
o String lastName
o String ssn
}

concept Driver extends Person {
o String favoriteColor
}

concept Employee {
o String ssn
}

concept Car identified by vin
{
o String vin
o Person owner
}
Loading