Skip to content

Commit

Permalink
WIP(parser) Move CTO parser/printer out of core into its own package
Browse files Browse the repository at this point in the history
Signed-off-by: jeromesimeon <[email protected]>
  • Loading branch information
jeromesimeon committed Nov 22, 2021
1 parent b448360 commit 88aac16
Show file tree
Hide file tree
Showing 28 changed files with 941 additions and 259 deletions.
2 changes: 1 addition & 1 deletion packages/concerto-core/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Concerto Core

Main library for Concerto model parsing, model manager, JSON instance validation and serialization.
Main library for Concerto models, model manager, JSON instance validation and serialization.

# Installation

Expand Down
5 changes: 0 additions & 5 deletions packages/concerto-core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,6 @@ class MetaModel {
+ object resolveMetaModel(object,object)
+ object modelFileToMetaModel(object,boolean)
+ object modelManagerToMetaModel(object,boolean,boolean)
+ string decoratorArgFromMetaModel(object)
+ string decoratorFromMetaModel(object)
+ string decoratorsFromMetaModel(object,string)
+ string propertyFromMetaModel(object)
+ string declFromMetaModel(object)
+ string ctoFromMetaModel(object,boolean)
+ object modelManagerFromMetaModel(object,boolean)
+ object ctoToMetaModel(string,boolean)
Expand Down
2 changes: 1 addition & 1 deletion packages/concerto-core/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
# Note that the latest public API is documented using JSDocs and is available in api.txt.
#

Version 1.2.2 {cee5678990e1f3db03f2c419d2246267} 2021-11-17
Version 1.2.2 {1901d674477ccf6e22d7fde0d8114446} 2021-11-17
- Parser directly constructs metamodel instance
- Convert MetaModel to a class for Typescript + Webpack compatability
- Update Acorn to latest and refactor the JavaScript parser so we can use static class members
Expand Down
241 changes: 10 additions & 231 deletions packages/concerto-core/lib/introspect/metamodel.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

'use strict';

const parser = require('./parser');
const { Parser, Printer } = require('@accordproject/concerto-parser');
const ModelManager = require('../modelmanager');
const Factory = require('../factory');
const Serializer = require('../serializer');
Expand Down Expand Up @@ -402,210 +402,6 @@ concept Models {
return result;
}

/**
* Create decorator argument string from a metamodel
* @param {object} mm - the metamodel
* @return {string} the string for the decorator argument
*/
static decoratorArgFromMetaModel(mm) {
let result = '';
switch (mm.$class) {
case 'concerto.metamodel.DecoratorTypeReference':
result += `${mm.type.name}${mm.isArray ? '[]' : ''}`;
break;
case 'concerto.metamodel.DecoratorString':
result += `"${mm.value}"`;
break;
default:
result += `${mm.value}`;
break;
}
return result;
}

/**
* Create decorator string from a metamodel
* @param {object} mm - the metamodel
* @return {string} the string for the decorator
*/
static decoratorFromMetaModel(mm) {
let result = '';
result += `@${mm.name}`;
if (mm.arguments) {
result += '(';
result += mm.arguments.map(MetaModel.decoratorArgFromMetaModel).join(',');
result += ')';
}
return result;
}

/**
* Create decorators string from a metamodel
* @param {object} mm - the metamodel
* @param {string} prefix - indentation
* @return {string} the string for the decorators
*/
static decoratorsFromMetaModel(mm, prefix) {
let result = '';
result += mm.map(MetaModel.decoratorFromMetaModel).join(`\n${prefix}`);
result += `\n${prefix}`;
return result;
}

/**
* Create a property string from a metamodel
* @param {object} mm - the metamodel
* @return {string} the string for that property
*/
static propertyFromMetaModel(mm) {
let result = '';
let defaultString = '';
let validatorString = '';

if (mm.decorators) {
result += MetaModel.decoratorsFromMetaModel(mm.decorators, ' ');
}
if (mm.$class === 'concerto.metamodel.RelationshipProperty') {
result += '-->';
} else {
result += 'o';
}

switch (mm.$class) {
case 'concerto.metamodel.EnumProperty':
break;
case 'concerto.metamodel.BooleanProperty':
result += ' Boolean';
if (mm.defaultValue === true || mm.defaultValue === false) {
if (mm.defaultValue) {
defaultString += ' default=true';
} else {
defaultString += ' default=false';
}
}
break;
case 'concerto.metamodel.DateTimeProperty':
result += ' DateTime';
break;
case 'concerto.metamodel.DoubleProperty':
result += ' Double';
if (mm.defaultValue) {
const doubleString = mm.defaultValue.toFixed(Math.max(1, (mm.defaultValue.toString().split('.')[1] || []).length));

defaultString += ` default=${doubleString}`;
}
if (mm.validator) {
const lowerString = mm.validator.lower ? mm.validator.lower : '';
const upperString = mm.validator.upper ? mm.validator.upper : '';
validatorString += ` range=[${lowerString},${upperString}]`;
}
break;
case 'concerto.metamodel.IntegerProperty':
result += ' Integer';
if (mm.defaultValue) {
defaultString += ` default=${mm.defaultValue.toString()}`;
}
if (mm.validator) {
const lowerString = mm.validator.lower ? mm.validator.lower : '';
const upperString = mm.validator.upper ? mm.validator.upper : '';
validatorString += ` range=[${lowerString},${upperString}]`;
}
break;
case 'concerto.metamodel.LongProperty':
result += ' Long';
if (mm.defaultValue) {
defaultString += ` default=${mm.defaultValue.toString()}`;
}
if (mm.validator) {
const lowerString = mm.validator.lower ? mm.validator.lower : '';
const upperString = mm.validator.upper ? mm.validator.upper : '';
validatorString += ` range=[${lowerString},${upperString}]`;
}
break;
case 'concerto.metamodel.StringProperty':
result += ' String';
if (mm.defaultValue) {
defaultString += ` default="${mm.defaultValue}"`;
}
if (mm.validator) {
validatorString += ` regex=/${mm.validator.pattern}/${mm.validator.flags}`;
}
break;
case 'concerto.metamodel.ObjectProperty':
result += ` ${mm.type.name}`;
if (mm.defaultValue) {
defaultString += ` default="${mm.defaultValue}"`;
}
break;
case 'concerto.metamodel.RelationshipProperty':
result += ` ${mm.type.name}`;
break;
}
if (mm.isArray) {
result += '[]';
}
result += ` ${mm.name}`;
if (mm.isOptional) {
result += ' optional';
}
result += defaultString;
result += validatorString;
return result;
}

/**
* Create a declaration string from a metamodel
* @param {object} mm - the metamodel
* @return {string} the string for that declaration
*/
static declFromMetaModel(mm) {
let result = '';
if (mm.decorators) {
result += MetaModel.decoratorsFromMetaModel(mm.decorators, '');
}

if (mm.isAbstract) {
result += 'abstract ';
}
switch (mm.$class) {
case 'concerto.metamodel.AssetDeclaration':
result += `asset ${mm.name} `;
break;
case 'concerto.metamodel.ConceptDeclaration':
result += `concept ${mm.name} `;
break;
case 'concerto.metamodel.EventDeclaration':
result += `event ${mm.name} `;
break;
case 'concerto.metamodel.ParticipantDeclaration':
result += `participant ${mm.name} `;
break;
case 'concerto.metamodel.TransactionDeclaration':
result += `transaction ${mm.name} `;
break;
case 'concerto.metamodel.EnumDeclaration':
result += `enum ${mm.name} `;
break;
}
if (mm.superType) {
result += `extends ${mm.superType.name} `;
}
// XXX Needs to be fixed to support `identified`
if (mm.identified) {
if (mm.identified.$class === 'concerto.metamodel.IdentifiedBy') {
result += `identified by ${mm.identified.name} `;
} else {
result += 'identified ';
}
}
result += '{';
mm.properties.forEach((property) => {
result += `\n ${MetaModel.propertyFromMetaModel(property)}`;
});
result += '\n}';
return result;
}

/**
* Create a model string from a metamodel
* @param {object} metaModel - the metamodel
Expand All @@ -615,28 +411,7 @@ concept Models {
static ctoFromMetaModel(metaModel, validate = true) {
// First, validate the JSON metaModel
const mm = validate ? MetaModel.validateMetaModel(metaModel) : metaModel;

let result = '';
result += `namespace ${mm.namespace}`;
if (mm.imports && mm.imports.length > 0) {
result += '\n';
mm.imports.forEach((imp) => {
let name = '*';
if (imp.$class === 'concerto.metamodel.ImportType') {
name = imp.name;
}
result += `\nimport ${imp.namespace}.${name}`;
if (imp.uri) {
result += ` from ${imp.uri}`;
}
});
}
if (mm.declarations && mm.declarations.length > 0) {
mm.declarations.forEach((decl) => {
result += `\n\n${MetaModel.declFromMetaModel(decl)}`;
});
}
return result;
return Printer.toCTO(mm);
}

/**
Expand All @@ -652,7 +427,7 @@ concept Models {
const modelManager = new ModelManager();

mm.models.forEach((mm) => {
const cto = MetaModel.ctoFromMetaModel(mm, false); // No need to re-validate
const cto = Printer.toCTO(mm); // No need to re-validate
modelManager.addModelFile(cto, null, false);
});

Expand All @@ -667,7 +442,7 @@ concept Models {
* @return {object} the metamodel for this model
*/
static ctoToMetaModel(model, validate) {
return parser.parse(model);
return Parser.parse(model);
}

/**
Expand All @@ -678,8 +453,12 @@ concept Models {
* @return {object} the metamodel for this model
*/
static ctoToMetaModelAndResolve(modelManager, model, validate) {
const metaModel = parser.parse(model);
const result = MetaModel.resolveMetaModel(modelManager, metaModel);
const metaModel = Parser.parse(model);

// First, validate the JSON metaModel
const mm = validate ? MetaModel.validateMetaModel(metaModel) : metaModel;

const result = MetaModel.resolveMetaModel(modelManager, mm);
return result;
}
}
Expand Down
5 changes: 2 additions & 3 deletions packages/concerto-core/lib/introspect/modelfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

const packageJson = require('../../package.json');
const semver = require('semver');
const parser = require('./parser');
const AssetDeclaration = require('./assetdeclaration');
const EnumDeclaration = require('./enumdeclaration');
const ConceptDeclaration = require('./conceptdeclaration');
Expand All @@ -27,6 +26,7 @@ const IllegalModelException = require('./illegalmodelexception');
const ParseException = require('./parseexception');
const ModelUtil = require('../modelutil');
const Globalize = require('../globalize');
const { Parser } = require('@accordproject/concerto-parser');

/**
* Class representing a Model File. A Model File contains a single namespace
Expand Down Expand Up @@ -73,8 +73,7 @@ class ModelFile {
}

try {
this.ast = parser.parse(definitions);
// console.log(`AST ${JSON.stringify(this.ast, null, 2)}`);
this.ast = Parser.parse(definitions);
}
catch(err) {
if(err.location && err.location.start) {
Expand Down
6 changes: 1 addition & 5 deletions packages/concerto-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"main": "index.js",
"typings": "types/index.d.ts",
"scripts": {
"prepare": "peggy ./lib/introspect/parser.pegjs",
"pretest": "npm run lint",
"lint": "eslint .",
"postlint": "npm run licchk",
Expand Down Expand Up @@ -58,6 +57,7 @@
"yargs": "17.1.0"
},
"dependencies": {
"@accordproject/concerto-parser": "1.2.1",
"@supercharge/promise-pool": "1.7.0",
"axios": "0.23.0",
"colors": "1.4.0",
Expand All @@ -82,7 +82,6 @@
"coverage",
"index.d.ts",
"./system",
"./introspect/parser.js",
"LICENSE",
"node_modules",
".nyc-output",
Expand Down Expand Up @@ -128,9 +127,6 @@
"lib/**/*.js"
],
"exclude": [
"lib/codegen/parsejs.js",
"lib/codegen/javascriptparser.js",
"lib/introspect/parser.js"
],
"all": true,
"check-coverage": true,
Expand Down
Loading

0 comments on commit 88aac16

Please sign in to comment.