Skip to content

Commit

Permalink
refactor(core) ModelFile now takes AST rather than CTO
Browse files Browse the repository at this point in the history
Signed-off-by: jeromesimeon <[email protected]>
  • Loading branch information
jeromesimeon committed Nov 29, 2021
1 parent 85fc556 commit 215dbb3
Show file tree
Hide file tree
Showing 20 changed files with 163 additions and 110 deletions.
3 changes: 2 additions & 1 deletion packages/concerto-core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class MetaModel {
+ object modelManagerFromMetaModel(object,boolean?)
}
class ModelFile {
+ void constructor(ModelManager,string,string?) throws IllegalModelException
+ void constructor(ModelManager,object,string,string?) throws IllegalModelException
+ boolean isModelFile()
+ Boolean isSystemModelFile()
+ boolean isExternal()
Expand All @@ -131,6 +131,7 @@ class ModelFile {
+ ClassDeclaration[] getDeclarations(Function)
+ ClassDeclaration[] getAllDeclarations()
+ string getDefinitions()
+ object getAst()
+ string getConcertoVersion()
+ void isCompatibleVersion()
}
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 {4b91a8a710904bba73520f67c016d006} 2021-11-24
Version 1.2.2 {a17601f3c2c7e81f521c8779093b03fa} 2021-11-24
- Remove custom instanceof and add methods to check runtime type
- Remove support for Node 12
- Generate Typescript definitions from JSDoc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
const axios = require('axios');
const ModelFile = require('../modelfile');
const url = require('url');
const Parser = require('@accordproject/concerto-cto').Parser;

/**
* Loads ModelFiles from an HTTP(S) URL using the axios library.
Expand Down Expand Up @@ -67,7 +68,8 @@ class HTTPModelFileLoader {
// external ModelFiles have a name that starts with '@'
// (so that they are identified as external when an archive is read back in)
const name = (parsedUrl.host + parsedUrl.pathname).replace(/\//g, '.');
return new ModelFile(this.modelManager, response.data, '@' + name);
const ast = Parser.parse(response.data, '@' + name);
return new ModelFile(this.modelManager, ast, response.data, '@' + name);
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion 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 { Printer } = require('@accordproject/concerto-cto');
const Printer = require('@accordproject/concerto-cto').Printer;
const ModelManager = require('../modelmanager');
const Factory = require('../factory');
const Serializer = require('../serializer');
Expand Down
23 changes: 17 additions & 6 deletions packages/concerto-core/lib/introspect/modelfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const EventDeclaration = require('./eventdeclaration');
const IllegalModelException = require('./illegalmodelexception');
const ModelUtil = require('../modelutil');
const Globalize = require('../globalize');
const { Parser } = require('@accordproject/concerto-cto');

/**
* Class representing a Model File. A Model File contains a single namespace
Expand All @@ -40,11 +39,12 @@ class ModelFile {
* Use the ModelManager to manage ModelFiles.
* @param {ModelManager} modelManager - the ModelManager that manages this
* ModelFile
* @param {object} ast - The DSL model as a string.
* @param {string} definitions - The DSL model as a string.
* @param {string} [fileName] - The optional filename for this modelfile
* @throws {IllegalModelException}
*/
constructor(modelManager, definitions, fileName) {
constructor(modelManager, ast, definitions, fileName) {
this.modelManager = modelManager;
this.external = false;
this.declarations = [];
Expand All @@ -56,8 +56,13 @@ class ModelFile {
this.fileName = 'UNKNOWN';
this.concertoVersion = null;

if(!definitions || typeof definitions !== 'string') {
throw new Error('ModelFile expects a Concerto model as a string as input.');
if(!ast || typeof ast !== 'object') {
throw new Error('ModelFile expects a Concerto model AST as input.');
}
this.ast = ast;

if(definitions && typeof definitions !== 'string') {
throw new Error('ModelFile expects an (optional) Concerto model definition as a string.');
}
this.definitions = definitions;

Expand All @@ -70,8 +75,6 @@ class ModelFile {
this.external = fileName.startsWith('@');
}

this.ast = Parser.parse(definitions, fileName);

// Populate from the AST
this.fromAst(this.ast);
// Check version compatibility
Expand Down Expand Up @@ -547,6 +550,14 @@ class ModelFile {
return this.definitions;
}

/**
* Get the ast for this model.
* @return {object} The definitions for this model.
*/
getAst() {
return this.ast;
}

/**
* Get the expected concerto version
* @return {string} The semver range for compatible concerto versions
Expand Down
4 changes: 3 additions & 1 deletion packages/concerto-core/lib/modelloader.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

const fs = require('fs');

const Parser = require('@accordproject/concerto-cto').Parser;
const DefaultModelFileLoader = require('./introspect/loaders/defaultmodelfileloader');
const ModelFile = require('./introspect/modelfile');
const ModelManager = require('./modelmanager');
Expand Down Expand Up @@ -44,7 +45,8 @@ class ModelLoader {
modelFile = await modelFileLoader.load(ctoFile);
} else {
const content = fs.readFileSync(ctoFile, 'utf8');
modelFile = new ModelFile(modelManager, content, ctoFile);
const ast = Parser.parse(content, ctoFile);
modelFile = new ModelFile(modelManager, ast, content, ctoFile);
}

modelManager.addModelFile(modelFile, modelFile.getName(), true);
Expand Down
18 changes: 14 additions & 4 deletions packages/concerto-core/lib/modelmanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const fs = require('fs');
const fsPath = require('path');
const slash = require('slash');

const Parser = require('@accordproject/concerto-cto').Parser;
const DefaultModelFileLoader = require('./introspect/loaders/defaultmodelfileloader');
const Factory = require('./factory');
const Globalize = require('./globalize');
Expand Down Expand Up @@ -104,7 +105,8 @@ abstract concept Event {}
*/
validateModelFile(modelFile, fileName) {
if (typeof modelFile === 'string') {
let m = new ModelFile(this, modelFile, fileName);
const ast = Parser.parse(modelFile, fileName);
let m = new ModelFile(this, ast, modelFile, fileName);
m.validate();
} else {
modelFile.validate();
Expand Down Expand Up @@ -145,7 +147,8 @@ abstract concept Event {}
let m = null;

if (typeof modelFile === 'string') {
m = new ModelFile(this, modelFile, fileName);
const ast = Parser.parse(modelFile, fileName);
m = new ModelFile(this, ast, modelFile, fileName);
} else {
m = modelFile;
}
Expand Down Expand Up @@ -177,7 +180,8 @@ abstract concept Event {}
const NAME = 'updateModelFile';
debug(NAME, 'updateModelFile', modelFile, fileName);
if (typeof modelFile === 'string') {
let m = new ModelFile(this, modelFile, fileName);
const ast = Parser.parse(modelFile, fileName);
let m = new ModelFile(this, ast, modelFile, fileName);
return this.updateModelFile(m,fileName,disableValidation);
} else {
let existing = this.modelFiles[modelFile.getNamespace()];
Expand Down Expand Up @@ -228,7 +232,13 @@ abstract concept Event {}
fileName = fileNames[n];
}

const m = typeof modelFile === 'string' ? new ModelFile(this, modelFile, fileName) : modelFile;
let m;
if (typeof modelFile === 'string') {
const ast = Parser.parse(modelFile, fileName);
m = new ModelFile(this, ast, modelFile, fileName);
} else {
m = modelFile;
}
if (!this.modelFiles[m.getNamespace()]) {
this.modelFiles[m.getNamespace()] = m;
newModelFiles.push(m);
Expand Down
2 changes: 1 addition & 1 deletion packages/concerto-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@
"check-coverage": true,
"statements": 98,
"branches": 97,
"functions": 99,
"functions": 98,
"lines": 98
}
}
25 changes: 25 additions & 0 deletions packages/concerto-core/test/composer/parserutility.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

const Parser = require('@accordproject/concerto-cto').Parser;
const ModelFile = require('../../lib/introspect/modelfile');

module.exports = {
newModelFile: (modelManager, definitions, fileName) => {
const ast = Parser.parse(definitions, fileName);
return new ModelFile(modelManager, ast, definitions, fileName);
},
};
6 changes: 3 additions & 3 deletions packages/concerto-core/test/introspect/assetdeclaration.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

const IllegalModelException = require('../../lib/introspect/illegalmodelexception');
const AssetDeclaration = require('../../lib/introspect/assetdeclaration');
const ModelFile = require('../../lib/introspect/modelfile');
const ModelManager = require('../../lib/modelmanager');
const ParserUtil = require('../composer/parserutility');
const fs = require('fs');

const should = require('chai').should();
Expand Down Expand Up @@ -46,7 +46,7 @@ describe('AssetDeclaration', () => {

let loadAssetDeclaration = (modelFileName) => {
let modelDefinitions = fs.readFileSync(modelFileName, 'utf8');
let modelFile = new ModelFile(mockModelManager, modelDefinitions);
let modelFile = ParserUtil.newModelFile(mockModelManager, modelDefinitions);
let assets = modelFile.getAssetDeclarations();
assets.should.have.lengthOf(1);

Expand All @@ -55,7 +55,7 @@ describe('AssetDeclaration', () => {

let loadLastAssetDeclaration = (modelFileName) => {
let modelDefinitions = fs.readFileSync(modelFileName, 'utf8');
let modelFile = new ModelFile(mockModelManager, modelDefinitions);
let modelFile = ParserUtil.newModelFile(mockModelManager, modelDefinitions);
let assets = modelFile.getAssetDeclarations();
return assets[assets.length - 1];
};
Expand Down
4 changes: 2 additions & 2 deletions packages/concerto-core/test/introspect/classdeclaration.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ const ConceptDeclaration = require('../../lib/introspect/conceptdeclaration');
const ParticipantDeclaration = require('../../lib/introspect/participantdeclaration');
const TransactionDeclaration = require('../../lib/introspect/transactiondeclaration');
const IntrospectUtils = require('./introspectutils');
const ParserUtil = require('../composer/parserutility');

const ModelFile = require('../../lib/introspect/modelfile');
const ModelManager = require('../../lib/modelmanager');
const Util = require('../composer/composermodelutility');

Expand All @@ -40,7 +40,7 @@ describe('ClassDeclaration', () => {
modelManager = new ModelManager();
Util.addComposerModel(modelManager);
introspectUtils = new IntrospectUtils(modelManager);
modelFile = new ModelFile(modelManager, 'namespace com.hyperledger.testing', 'org.acme.cto');
modelFile = ParserUtil.newModelFile(modelManager, 'namespace com.hyperledger.testing', 'org.acme.cto');
});

describe('#constructor', () => {
Expand Down
10 changes: 5 additions & 5 deletions packages/concerto-core/test/introspect/concertoVersion.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

'use strict';

const ModelFile = require('../../lib/introspect/modelfile');
const ModelManager = require('../../lib/modelmanager');
const ParserUtil = require('../composer/parserutility');
const fs = require('fs');
const path = require('path');
const sinon = require('sinon');
Expand Down Expand Up @@ -45,25 +45,25 @@ describe('ModelFile', () => {

it('should throw when concerto version is not compatible with model', () => {
(() => {
new ModelFile(modelManager, versionInvalid);
ParserUtil.newModelFile(modelManager, versionInvalid);
}).should.throw(/ModelFile expects Concerto version/);
});

it('should return when concerto version is compatible with model', () => {
let mf = new ModelFile(modelManager, versionValid);
let mf = ParserUtil.newModelFile(modelManager, versionValid);
mf.getConcertoVersion().should.equal('^1.0.0');
});

it('should return when concerto version is compatible with model with a pre-release version', () => {
const version = pkgJSON.version;
const newVersion = `${version}-unittest.${new Date().getTime()}`;
sinon.replace(pkgJSON, 'version', newVersion);
let mf = new ModelFile(modelManager, versionValid);
let mf = ParserUtil.newModelFile(modelManager, versionValid);
mf.getConcertoVersion().should.equal('^1.0.0');
});

it('should return when model has no concerto version range', () => {
let mf = new ModelFile(modelManager, versionMissing);
let mf = ParserUtil.newModelFile(modelManager, versionMissing);
(mf.getConcertoVersion() === null).should.equal(true);
});
});
Expand Down
4 changes: 2 additions & 2 deletions packages/concerto-core/test/introspect/enumdeclaration.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
'use strict';

const EnumDeclaration = require('../../lib/introspect/enumdeclaration');
const ModelFile = require('../../lib/introspect/modelfile');
const ModelManager = require('../../lib/modelmanager');
const ParserUtil = require('../composer/parserutility');
const fs = require('fs');

require('chai').should();
Expand All @@ -35,7 +35,7 @@ describe('EnumDeclaration', () => {
const modelFiles = [];
for (let modelFileName of modelFileNames) {
const modelDefinitions = fs.readFileSync(modelFileName, 'utf8');
const modelFile = new ModelFile(modelManager, modelDefinitions);
const modelFile = ParserUtil.newModelFile(modelManager, modelDefinitions);
modelFiles.push(modelFile);
}
modelManager.addModelFiles(modelFiles, modelFileNames);
Expand Down
4 changes: 2 additions & 2 deletions packages/concerto-core/test/introspect/introspectutils.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
*/

'use strict';
const ModelFile = require('../../lib/introspect/modelfile');
const ModelManager = require('../../lib/modelmanager');
const ParserUtil = require('../composer/parserutility');
const fs = require('fs');

/**
Expand Down Expand Up @@ -46,7 +46,7 @@ class IntrospectUtils {
const modelFiles = [];
for (let modelFileName of modelFileNames) {
const modelDefinitions = fs.readFileSync(modelFileName, 'utf8');
const modelFile = new ModelFile(this.modelManager, modelDefinitions);
const modelFile = ParserUtil.newModelFile(this.modelManager, modelDefinitions);
modelFiles.push(modelFile);
}
return modelFiles;
Expand Down
Loading

0 comments on commit 215dbb3

Please sign in to comment.