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

Root hierarchy + identifiers (v3) #246

Merged
merged 19 commits into from
Mar 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
fd4fda5
fix(core) Root hierarchy should have proper inheritance
jeromesimeon Mar 19, 2021
da9b411
fix(core) A variant of type hierarchy with identified assets
jeromesimeon Mar 19, 2021
bd1bf25
chore(identifiable) No need to special case identifier field
jeromesimeon Mar 19, 2021
1e72d30
feature(1.0) Numerous fixes to identifiers handling
jeromesimeon Mar 23, 2021
8c482dd
fix(core) Minor adjustments to identifiers support
jeromesimeon Mar 24, 2021
29c9492
fix(timestamp) Switch timestamps to be system-defined
jeromesimeon Mar 24, 2021
5775994
test(1.0) Initial testing support for 1.0.0
jeromesimeon Mar 24, 2021
b052d24
chore(core) Remove unused systemmodel file
jeromesimeon Mar 24, 2021
e0a9148
fix(1.0) Semantic rather than syntactic isSystemIdentified
jeromesimeon Mar 25, 2021
111cd42
tests(1.0) More tests for 1.0 validation semantics
jeromesimeon Mar 26, 2021
9666a27
chore(tools) Adjust loopback generation after timestamp changes
jeromesimeon Mar 26, 2021
350f8a9
fix(core) Properly create field now
jeromesimeon Mar 27, 2021
3b7d7e1
chore(test) Fixes timezone for tests
jeromesimeon Mar 27, 2021
278d476
fix(validate-f) Functional validation shouldn't expect system identif…
jeromesimeon Mar 28, 2021
edfa648
feature(cli) Add functional validation option, cleanup options
jeromesimeon Mar 28, 2021
3b5accd
chore(test) Remove temporary README in tests
jeromesimeon Mar 28, 2021
3c9910c
chore(test) Validation test cleanup
jeromesimeon Mar 28, 2021
7e6e652
chore(doc) Update changelog
jeromesimeon Mar 30, 2021
17cd6c8
fix(core) Update jsdoc in factory module
jeromesimeon Mar 30, 2021
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
28 changes: 14 additions & 14 deletions packages/concerto-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Options:

### Concerto validate

The `validate` command lets you check whether a JSON sample is a valid instance of the given model.
The `validate` command lets you check whether a JSON input is a valid instance of the given model.

```
concerto validate
Expand All @@ -31,9 +31,10 @@ Options:
--version Show version number [boolean]
--verbose, -v [default: false]
--help Show help [boolean]
--sample sample JSON to validate [string] [default: "sample.json"]
--ctoSystem system model to be used [string]
--ctoFiles array of CTO files [array] [default: "."]
--input JSON to validate [string]
--model array of concerto (cto) model files [array]
--offline do not resolve external models [boolean] [default: false]
--functional new validation API [boolean] [default: false]
```

### Concerto compile
Expand All @@ -49,46 +50,46 @@ Options:
--version Show version number [boolean]
--verbose, -v [default: false]
--help Show help [boolean]
--ctoSystem system model to be used [string]
--ctoFiles array of CTO files [array] [default: "."]
--model array of concerto (cto) model files [array] [required]
--offline do not resolve external models [boolean] [default: false]
--target target of the code generation [string] [default: "JSONSchema"]
--output output directory path [string] [default: "./output/"]
```

#### Go Lang

```
concerto compile --ctoFiles modelfile.cto --target Go
concerto compile --model modelfile.cto --target Go
```

#### Plant UML

```
concerto compile --ctoFiles modelfile.cto --target PlantUML
concerto compile --model modelfile.cto --target PlantUML
```

#### Typescript

```
concerto compile --ctoFiles modelfile.cto --target Typescript
concerto compile --model modelfile.cto --target Typescript
```

#### Java

```
concerto compile --ctoFiles modelfile.cto --target Java
concerto compile --model modelfile.cto --target Java
```

#### JSONSchema

```
concerto compile --ctoFiles modelfile.cto --target JSONSchema
concerto compile --model modelfile.cto --target JSONSchema
```

#### XMLSchema

```
concerto compile --ctoFiles modelfile.cto --target XMLSchema
concerto compile --model modelfile.cto --target XMLSchema
```

### Concerto Get
Expand All @@ -104,8 +105,7 @@ Options:
--version Show version number [boolean]
--verbose, -v [default: false]
--help Show help [boolean]
--ctoFiles array of local CTO files [array] [default: "."]
--ctoSystem system model to be used [string]
--model array of concerto (cto) model files [array] [required]
--output output directory path [string] [default: "./"]
```

Expand Down
44 changes: 27 additions & 17 deletions packages/concerto-cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ require('yargs')
.strict()
.usage('$0 <cmd> [args]')
.command('validate', 'validate JSON against model files', (yargs) => {
yargs.option('sample', {
describe: 'sample JSON to validate',
yargs.option('input', {
describe: 'JSON to validate',
type: 'string'
});
yargs.option('ctoFiles', {
describe: 'array of CTO files',
yargs.option('model', {
describe: 'array of concerto (cto) model files',
type: 'string',
array: true
});
Expand All @@ -39,20 +39,30 @@ require('yargs')
type: 'boolean',
default: false
});
yargs.option('functional', {
describe: 'new validation API',
type: 'boolean',
default: false
});
}, (argv) => {
if (argv.verbose) {
Logger.info(`validate sample in ${argv.sample} against the models ${argv.ctoFiles}`);
Logger.info(`validate ${argv.input} against the models ${argv.model}`);
}

try {
argv = Commands.validateValidateArgs(argv);
const options = {};
options.offline = argv.offline;
return Commands.validate(argv.sample, argv.ctoFiles, options)
options.functional = argv.functional;
return Commands.validate(argv.input, argv.model, options)
.then((result) => {
Logger.info(result);
Logger.info('Input is valid');
if (!options.functional) {
Logger.info(result);
}
})
.catch((err) => {
Logger.info('Input is invalid');
Logger.error(err.message);
});
} catch (err){
Expand All @@ -61,9 +71,9 @@ require('yargs')
}
})
.command('compile', 'generate code for a target platform', (yargs) => {
yargs.demandOption(['ctoFiles'], 'Please provide at least the CTO files');
yargs.option('ctoFiles', {
describe: 'array of CTO files',
yargs.demandOption(['model'], 'Please provide CTO models');
yargs.option('model', {
describe: 'array of concerto (cto) model files',
type: 'string',
array: true
});
Expand All @@ -84,12 +94,12 @@ require('yargs')
});
}, (argv) => {
if (argv.verbose) {
Logger.info(`generate code for target ${argv.target} from models ${argv.ctoFiles} into directory: ${argv.output}`);
Logger.info(`generate code for target ${argv.target} from models ${argv.model} into directory: ${argv.output}`);
}

const options = {};
options.offline = argv.offline;
return Commands.compile(argv.target, argv.ctoFiles, argv.output, options)
return Commands.compile(argv.target, argv.model, argv.output, options)
.then((result) => {
Logger.info(result);
})
Expand All @@ -98,9 +108,9 @@ require('yargs')
});
})
.command('get', 'save local copies of external model dependencies', (yargs) => {
yargs.demandOption(['ctoFiles'], 'Please provide at least the CTO files');
yargs.option('ctoFiles', {
describe: 'array of local CTO files',
yargs.demandOption(['model'], 'Please provide CTO models');
yargs.option('model', {
describe: 'array of concerto (cto) model files',
type: 'string',
array: true
});
Expand All @@ -111,10 +121,10 @@ require('yargs')
});
}, (argv) => {
if (argv.verbose) {
Logger.info(`saving external models from ${argv.ctoFiles} into directory: ${argv.output}`);
Logger.info(`saving external models from ${argv.model} into directory: ${argv.output}`);
}

return Commands.get(argv.ctoFiles, argv.output)
return Commands.get(argv.model, argv.output)
.then((result) => {
Logger.info(result);
})
Expand Down
22 changes: 15 additions & 7 deletions packages/concerto-cli/lib/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const Logger = require('@accordproject/concerto-core').Logger;
const ModelLoader = require('@accordproject/concerto-core').ModelLoader;
const Factory = require('@accordproject/concerto-core').Factory;
const Serializer = require('@accordproject/concerto-core').Serializer;
const Concerto = require('@accordproject/concerto-core').Concerto;
const FileWriter = require('@accordproject/concerto-tools').FileWriter;
const CodeGen = require('@accordproject/concerto-tools').CodeGen;

Expand Down Expand Up @@ -83,11 +84,11 @@ class Commands {
* @returns {object} a modfied argument object
*/
static validateValidateArgs(argv) {
argv = Commands.setDefaultFileArg(argv, 'sample', 'sample.json', ((argv, argDefaultName) => { return path.resolve('.',argDefaultName); }));
argv = Commands.setDefaultFileArg(argv, 'ctoFiles', 'model.cto', ((argv, argDefaultName) => { return [path.resolve('.',argDefaultName)]; }));
argv = Commands.setDefaultFileArg(argv, 'input', 'input.json', ((argv, argDefaultName) => { return path.resolve('.',argDefaultName); }));
argv = Commands.setDefaultFileArg(argv, 'model', 'model.cto', ((argv, argDefaultName) => { return [path.resolve('.',argDefaultName)]; }));

if(argv.verbose) {
Logger.info(`parse sample ${argv.sample} using a template ${argv.template}`);
Logger.info(`validate ${argv.input} using a model ${argv.model}`);
}

return argv;
Expand All @@ -106,11 +107,18 @@ class Commands {
const json = JSON.parse(fs.readFileSync(sample, 'utf8'));

const modelManager = await ModelLoader.loadModelManager(ctoFiles, options);
const factory = new Factory(modelManager);
const serializer = new Serializer(factory, modelManager);

const object = serializer.fromJSON(json);
return JSON.stringify(serializer.toJSON(object));
if (options.functional) {
const concerto = new Concerto(modelManager);

concerto.validate(json);
} else {
const factory = new Factory(modelManager);
const serializer = new Serializer(factory, modelManager);

const object = serializer.fromJSON(json);
return JSON.stringify(serializer.toJSON(object));
}
}

/**
Expand Down
25 changes: 0 additions & 25 deletions packages/concerto-cli/test.cto

This file was deleted.

7 changes: 0 additions & 7 deletions packages/concerto-cli/test.json

This file was deleted.

59 changes: 37 additions & 22 deletions packages/concerto-cli/test/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,54 +28,54 @@ const Commands = require('../lib/commands');
describe('cicero-cli', () => {
const models = [path.resolve(__dirname, 'models/dom.cto'),path.resolve(__dirname, 'models/money.cto')];
const offlineModels = [path.resolve(__dirname, 'models/contract.cto'),path.resolve(__dirname, 'models/dom.cto'),path.resolve(__dirname, 'models/money.cto')];
const sample1 = path.resolve(__dirname, 'data/sample1.json');
const sample2 = path.resolve(__dirname, 'data/sample2.json');
const sampleText1 = fs.readFileSync(sample1, 'utf8');
const sampleText2 = fs.readFileSync(sample2, 'utf8');
const input1 = path.resolve(__dirname, 'data/input1.json');
const input2 = path.resolve(__dirname, 'data/input2.json');
const inputText1 = fs.readFileSync(input1, 'utf8');
const inputText2 = fs.readFileSync(input2, 'utf8');

describe('#validateValidateArgs', () => {
it('no args specified', () => {
process.chdir(path.resolve(__dirname, 'data'));
const args = Commands.validateValidateArgs({
_: ['validate'],
});
args.sample.should.match(/sample.json$/);
args.input.should.match(/input.json$/);
});

it('all args specified', () => {
process.chdir(path.resolve(__dirname, 'data'));
const args = Commands.validateValidateArgs({
_: ['validate'],
sample: 'sample1.json'
input: 'input1.json'
});
args.sample.should.match(/sample1.json$/);
args.input.should.match(/input1.json$/);
});
});

describe('#validate', () => {
describe('#validate (classic)', () => {
it('should validate against a model', async () => {
const result = await Commands.validate(sample1, models, {offline:false});
JSON.parse(result).should.deep.equal(JSON.parse(sampleText1));
const result = await Commands.validate(input1, models, {offline:false});
JSON.parse(result).should.deep.equal(JSON.parse(inputText1));
});

it('should fail to validate against a model', async () => {
try {
const result = await Commands.validate(sample2, models, {offline:false});
JSON.parse(result).should.deep.equal(JSON.parse(sampleText2));
const result = await Commands.validate(input2, models, {offline:false});
JSON.parse(result).should.deep.equal(JSON.parse(inputText2));
} catch (err) {
err.message.should.equal('Instance org.accordproject.money.MonetaryAmount#null invalid enum value true for field CurrencyCode');
}
});

it('should validate against a model (offline)', async () => {
const result = await Commands.validate(sample1, offlineModels, {offline:true});
JSON.parse(result).should.deep.equal(JSON.parse(sampleText1));
const result = await Commands.validate(input1, offlineModels, {offline:true});
JSON.parse(result).should.deep.equal(JSON.parse(inputText1));
});

it('should fail to validate against a model (offline)', async () => {
try {
const result = await Commands.validate(sample2, offlineModels, {offline:true});
JSON.parse(result).should.deep.equal(JSON.parse(sampleText2));
const result = await Commands.validate(input2, offlineModels, {offline:true});
JSON.parse(result).should.deep.equal(JSON.parse(inputText2));
} catch (err) {
err.message.should.equal('Instance org.accordproject.money.MonetaryAmount#null invalid enum value true for field CurrencyCode');
}
Expand All @@ -89,20 +89,35 @@ describe('cicero-cli', () => {
});
});

it('bad sample.json', () => {
it('bad input.json', () => {
process.chdir(path.resolve(__dirname, 'data'));
(() => Commands.validateValidateArgs({
_: ['validate'],
sample: 'sample_en.json'
})).should.throw('A sample.json file is required. Try the --sample flag or create a sample.json file.');
input: 'input_en.json'
})).should.throw('A input.json file is required. Try the --input flag or create a input.json file.');
});

it('bad ctoFiles', () => {
it('bad model', () => {
process.chdir(path.resolve(__dirname, 'data'));
(() => Commands.validateValidateArgs({
_: ['validate'],
ctoFiles: ['missing.cto']
})).should.throw('A model.cto file is required. Try the --ctoFiles flag or create a model.cto file.');
model: ['missing.cto']
})).should.throw('A model.cto file is required. Try the --model flag or create a model.cto file.');
});
});

describe('#validate (functional)', () => {
it('should validate against a model', async () => {
const result = await Commands.validate(input1, models, {offline:false, functional: true});
(typeof result === 'undefined').should.equal(true);
});

it('should fail to validate against a model', async () => {
try {
await Commands.validate(input2, models, {offline:false, functional: true});
} catch (err) {
err.message.should.equal('Instance undefined invalid enum value true for field CurrencyCode');
}
});
});

Expand Down
Loading