diff --git a/packages/concerto-core/api.txt b/packages/concerto-core/api.txt index 3ca5ea538b..324dca587e 100644 --- a/packages/concerto-core/api.txt +++ b/packages/concerto-core/api.txt @@ -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() @@ -131,6 +131,7 @@ class ModelFile { + ClassDeclaration[] getDeclarations(Function) + ClassDeclaration[] getAllDeclarations() + string getDefinitions() + + object getAst() + string getConcertoVersion() + void isCompatibleVersion() } diff --git a/packages/concerto-core/changelog.txt b/packages/concerto-core/changelog.txt index 9689aa11aa..2fb9c0d22e 100644 --- a/packages/concerto-core/changelog.txt +++ b/packages/concerto-core/changelog.txt @@ -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 diff --git a/packages/concerto-core/lib/introspect/loaders/httpmodelfileloader.js b/packages/concerto-core/lib/introspect/loaders/httpmodelfileloader.js index 653fc1f7d5..9bc5c6f9dd 100644 --- a/packages/concerto-core/lib/introspect/loaders/httpmodelfileloader.js +++ b/packages/concerto-core/lib/introspect/loaders/httpmodelfileloader.js @@ -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. @@ -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); }); } } diff --git a/packages/concerto-core/lib/introspect/metamodel.js b/packages/concerto-core/lib/introspect/metamodel.js index 23175d0eb6..6e0bb9a066 100644 --- a/packages/concerto-core/lib/introspect/metamodel.js +++ b/packages/concerto-core/lib/introspect/metamodel.js @@ -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'); diff --git a/packages/concerto-core/lib/introspect/modelfile.js b/packages/concerto-core/lib/introspect/modelfile.js index 74f831ffba..551a6c9e14 100644 --- a/packages/concerto-core/lib/introspect/modelfile.js +++ b/packages/concerto-core/lib/introspect/modelfile.js @@ -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 @@ -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 = []; @@ -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; @@ -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 @@ -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 diff --git a/packages/concerto-core/lib/modelloader.js b/packages/concerto-core/lib/modelloader.js index 8df4399410..01eea7cb11 100644 --- a/packages/concerto-core/lib/modelloader.js +++ b/packages/concerto-core/lib/modelloader.js @@ -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'); @@ -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); diff --git a/packages/concerto-core/lib/modelmanager.js b/packages/concerto-core/lib/modelmanager.js index f2613ed1ca..e621490cf9 100644 --- a/packages/concerto-core/lib/modelmanager.js +++ b/packages/concerto-core/lib/modelmanager.js @@ -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'); @@ -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(); @@ -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; } @@ -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()]; @@ -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); diff --git a/packages/concerto-core/package.json b/packages/concerto-core/package.json index 04296600b0..21800b7a83 100644 --- a/packages/concerto-core/package.json +++ b/packages/concerto-core/package.json @@ -133,7 +133,7 @@ "check-coverage": true, "statements": 98, "branches": 97, - "functions": 99, + "functions": 98, "lines": 98 } } diff --git a/packages/concerto-core/test/composer/parserutility.js b/packages/concerto-core/test/composer/parserutility.js new file mode 100644 index 0000000000..f1ed2c2665 --- /dev/null +++ b/packages/concerto-core/test/composer/parserutility.js @@ -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); + }, +}; diff --git a/packages/concerto-core/test/introspect/assetdeclaration.js b/packages/concerto-core/test/introspect/assetdeclaration.js index 5b49040018..2578fc4a4e 100644 --- a/packages/concerto-core/test/introspect/assetdeclaration.js +++ b/packages/concerto-core/test/introspect/assetdeclaration.js @@ -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(); @@ -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); @@ -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]; }; diff --git a/packages/concerto-core/test/introspect/classdeclaration.js b/packages/concerto-core/test/introspect/classdeclaration.js index 4fddc9b32a..6da1550236 100644 --- a/packages/concerto-core/test/introspect/classdeclaration.js +++ b/packages/concerto-core/test/introspect/classdeclaration.js @@ -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'); @@ -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', () => { diff --git a/packages/concerto-core/test/introspect/concertoVersion.js b/packages/concerto-core/test/introspect/concertoVersion.js index cd2ba40071..914e9bcbc1 100644 --- a/packages/concerto-core/test/introspect/concertoVersion.js +++ b/packages/concerto-core/test/introspect/concertoVersion.js @@ -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'); @@ -45,12 +45,12 @@ 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'); }); @@ -58,12 +58,12 @@ describe('ModelFile', () => { 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); }); }); diff --git a/packages/concerto-core/test/introspect/enumdeclaration.js b/packages/concerto-core/test/introspect/enumdeclaration.js index c93aa6b4bc..ee1189477a 100644 --- a/packages/concerto-core/test/introspect/enumdeclaration.js +++ b/packages/concerto-core/test/introspect/enumdeclaration.js @@ -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(); @@ -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); diff --git a/packages/concerto-core/test/introspect/introspectutils.js b/packages/concerto-core/test/introspect/introspectutils.js index 67392641a8..89ffae97b9 100644 --- a/packages/concerto-core/test/introspect/introspectutils.js +++ b/packages/concerto-core/test/introspect/introspectutils.js @@ -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'); /** @@ -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; diff --git a/packages/concerto-core/test/introspect/metamodel.js b/packages/concerto-core/test/introspect/metamodel.js index 9985639c27..e2105070d0 100644 --- a/packages/concerto-core/test/introspect/metamodel.js +++ b/packages/concerto-core/test/introspect/metamodel.js @@ -16,8 +16,8 @@ const ModelManager = require('../../lib/modelmanager'); const ModelLoader = require('../../lib/modelloader'); -const ModelFile = require('../../lib/introspect/modelfile'); const MetaModel = require('../../lib/introspect/metamodel'); +const ParserUtil = require('../composer/parserutility'); const { Parser, Printer } = require('@accordproject/concerto-cto'); @@ -54,24 +54,24 @@ describe('MetaModel (Person)', () => { it('should convert a ModelFile to its metamodel', () => { const modelManager1 = new ModelManager(); - const mf1 = new ModelFile(modelManager1, personModel); + const mf1 = ParserUtil.newModelFile(modelManager1, personModel); const mm1 = MetaModel.modelFileToMetaModel(mf1, false); mm1.should.deep.equal(personMetaModel); const model2 = Printer.toCTO(mm1); const modelManager2 = new ModelManager(); - const mf2 = new ModelFile(modelManager2, model2); + const mf2 = ParserUtil.newModelFile(modelManager2, model2); const mm2 = MetaModel.modelFileToMetaModel(mf2, false); mm2.should.deep.equal(personMetaModel); }); it('should convert and validate a ModelFile to its metamodel', () => { const modelManager1 = new ModelManager(); - const mf1 = new ModelFile(modelManager1, personModel); + const mf1 = ParserUtil.newModelFile(modelManager1, personModel); const mm1 = MetaModel.modelFileToMetaModel(mf1); mm1.should.deep.equal(personMetaModel); const model2 = Printer.toCTO(mm1); const modelManager2 = new ModelManager(); - const mf2 = new ModelFile(modelManager2, model2); + const mf2 = ParserUtil.newModelFile(modelManager2, model2); const mm2 = MetaModel.modelFileToMetaModel(mf2); mm2.should.deep.equal(personMetaModel); }); @@ -104,24 +104,24 @@ describe('MetaModel (Empty)', () => { it('should convert a ModelFile to its metamodel', () => { const modelManager1 = new ModelManager(); - const mf1 = new ModelFile(modelManager1, emptyModel); + const mf1 = ParserUtil.newModelFile(modelManager1, emptyModel); const mm1 = MetaModel.modelFileToMetaModel(mf1, false); mm1.should.deep.equal(emptyMetaModel); const model2 = Printer.toCTO(mm1); const modelManager2 = new ModelManager(); - const mf2 = new ModelFile(modelManager2, model2); + const mf2 = ParserUtil.newModelFile(modelManager2, model2); const mm2 = MetaModel.modelFileToMetaModel(mf2, false); mm2.should.deep.equal(emptyMetaModel); }); it('should convert and validate a ModelFile to its metamodel', () => { const modelManager1 = new ModelManager(); - const mf1 = new ModelFile(modelManager1, emptyModel); + const mf1 = ParserUtil.newModelFile(modelManager1, emptyModel); const mm1 = MetaModel.modelFileToMetaModel(mf1); mm1.should.deep.equal(emptyMetaModel); const model2 = Printer.toCTO(mm1); const modelManager2 = new ModelManager(); - const mf2 = new ModelFile(modelManager2, model2); + const mf2 = ParserUtil.newModelFile(modelManager2, model2); const mm2 = MetaModel.modelFileToMetaModel(mf2); mm2.should.deep.equal(emptyMetaModel); }); diff --git a/packages/concerto-core/test/introspect/modelfile.js b/packages/concerto-core/test/introspect/modelfile.js index 71c12c26c4..24fad65405 100644 --- a/packages/concerto-core/test/introspect/modelfile.js +++ b/packages/concerto-core/test/introspect/modelfile.js @@ -26,6 +26,7 @@ const ModelManager = require('../../lib/modelmanager'); const fs = require('fs'); const path = require('path'); const Util = require('../composer/composermodelutility'); +const ParserUtil = require('../composer/parserutility'); const { Parser } = require('@accordproject/concerto-cto'); @@ -52,21 +53,21 @@ describe('ModelFile', () => { describe('#constructor', () => { - it('should throw when null definitions provided', () => { + it('should throw when non object ast provided', () => { (() => { new ModelFile(modelManager, null); - }).should.throw(/as a string as input/); + }).should.throw(/model AST as input/); }); it('should throw when invalid definitions provided', () => { (() => { - new ModelFile(modelManager, [{}]); - }).should.throw(/as a string as input/); + new ModelFile(modelManager, {}, {}); + }).should.throw(/definition as a string/); }); it('should throw when invalid filename provided', () => { (() => { - new ModelFile(modelManager, 'fake', {}); + new ModelFile(modelManager, {}, 'fake', {}); }).should.throw(/filename as a string/); }); @@ -76,7 +77,7 @@ describe('ModelFile', () => { body: [ ] }; sandbox.stub(Parser, 'parse').returns(ast); - let mf = new ModelFile(modelManager, 'fake definitions'); + let mf = ParserUtil.newModelFile(modelManager, 'fake definitions'); mf.ast.should.equal(ast); mf.namespace.should.equal('org.acme'); }); @@ -98,7 +99,7 @@ describe('ModelFile', () => { declarations: [ ] }; sandbox.stub(Parser, 'parse').returns(ast); - let mf = new ModelFile(modelManager, 'fake definitions'); + let mf = ParserUtil.newModelFile(modelManager, 'fake definitions'); mf.getImports().should.deep.equal(['org.freddos.Bar', 'org.doge.Foo', 'concerto.Concept', 'concerto.Asset', 'concerto.Transaction', 'concerto.Participant', 'concerto.Event']); }); @@ -119,7 +120,7 @@ describe('ModelFile', () => { declarations: [ ] }; sandbox.stub(Parser, 'parse').returns(ast); - let mf = new ModelFile(modelManager, 'fake definitions'); + let mf = ParserUtil.newModelFile(modelManager, 'fake definitions'); mf.getImports().should.deep.equal(['org.doge.Foo', 'org.freddos.*', 'concerto.Concept', 'concerto.Asset', 'concerto.Transaction', 'concerto.Participant', 'concerto.Event']); mf.getImportURI('org.freddos.*').should.equal('https://freddos.org/model.cto'); (mf.getImportURI('org.doge.Foo') === null).should.be.true; @@ -135,7 +136,7 @@ describe('ModelFile', () => { }; sandbox.stub(Parser, 'parse').returns(ast); (() => { - new ModelFile(modelManager, 'fake definitions'); + ParserUtil.newModelFile(modelManager, 'fake definitions'); }).should.throw(/BlahType/); }); @@ -144,7 +145,7 @@ describe('ModelFile', () => { describe('#accept', () => { it('should call the visitor', () => { - let mf = new ModelFile(modelManager, carLeaseModel); + let mf = ParserUtil.newModelFile(modelManager, carLeaseModel); let visitor = { visit: sinon.stub() }; @@ -164,7 +165,7 @@ describe('ModelFile', () => { asset MyAsset identified by assetId { o String assetId }`; - let modelFile = new ModelFile(modelManager, model); + let modelFile = ParserUtil.newModelFile(modelManager, model); (() => { modelFile.validate(); }).should.throw(IllegalModelException, /org.acme.ext/); @@ -177,7 +178,7 @@ describe('ModelFile', () => { asset MyAsset identified by assetId { o String assetId }`; - let modelFile = new ModelFile(modelManager, model); + let modelFile = ParserUtil.newModelFile(modelManager, model); (() => { modelFile.validate(); }).should.throw(IllegalModelException, /org.acme.ext/); @@ -195,9 +196,9 @@ describe('ModelFile', () => { asset MyAsset identified by assetId { o String assetId }`; - let modelFile1 = new ModelFile(modelManager, model1); + let modelFile1 = ParserUtil.newModelFile(modelManager, model1); modelManager.addModelFile(modelFile1); - let modelFile2 = new ModelFile(modelManager, model2); + let modelFile2 = ParserUtil.newModelFile(modelManager, model2); (() => { modelFile2.validate(); }).should.throw(IllegalModelException, /MyAsset3/); @@ -215,9 +216,9 @@ describe('ModelFile', () => { asset MyAsset identified by assetId { o String assetId }`; - let modelFile1 = new ModelFile(modelManager, model1); + let modelFile1 = ParserUtil.newModelFile(modelManager, model1); modelManager.addModelFile(modelFile1); - let modelFile2 = new ModelFile(modelManager, model2); + let modelFile2 = ParserUtil.newModelFile(modelManager, model2); (() => modelFile2.validate()).should.not.throw(); }); @@ -233,9 +234,9 @@ describe('ModelFile', () => { asset MyAsset identified by assetId { o String assetId }`; - let modelFile1 = new ModelFile(modelManager, model1); + let modelFile1 = ParserUtil.newModelFile(modelManager, model1); modelManager.addModelFile(modelFile1); - let modelFile2 = new ModelFile(modelManager, model2); + let modelFile2 = ParserUtil.newModelFile(modelManager, model2); (() => modelFile2.validate()).should.not.throw(); }); @@ -244,7 +245,7 @@ describe('ModelFile', () => { describe('#getDefinitions', () => { it('should return the definitions for the model', () => { - let modelFile = new ModelFile(modelManager, carLeaseModel); + let modelFile = ParserUtil.newModelFile(modelManager, carLeaseModel); modelFile.getDefinitions().should.equal(carLeaseModel); }); @@ -253,7 +254,7 @@ describe('ModelFile', () => { describe('#getName', () => { it('should return the name of the model', () => { - let modelFile = new ModelFile(modelManager, carLeaseModel, 'car lease'); + let modelFile = ParserUtil.newModelFile(modelManager, carLeaseModel, 'car lease'); modelFile.getName().should.equal('car lease'); }); @@ -267,7 +268,7 @@ describe('ModelFile', () => { asset MyAsset identified by assetId { o String assetId }`; - let modelFile = new ModelFile(modelManager, model); + let modelFile = ParserUtil.newModelFile(modelManager, model); modelFile.isImportedType('Fred').should.be.false; }); @@ -277,7 +278,7 @@ describe('ModelFile', () => { asset MyAsset identified by assetId { o String assetId }`; - let modelFile = new ModelFile(modelManager, model); + let modelFile = ParserUtil.newModelFile(modelManager, model); modelFile.isImportedType('MyAsset').should.be.false; }); @@ -288,7 +289,7 @@ describe('ModelFile', () => { asset MyAsset identified by assetId { o String assetId }`; - let modelFile = new ModelFile(modelManager, model); + let modelFile = ParserUtil.newModelFile(modelManager, model); modelFile.isImportedType('MyAsset2').should.be.true; }); @@ -304,9 +305,9 @@ describe('ModelFile', () => { asset MyAsset identified by assetId { o String assetId }`; - let modelFile1 = new ModelFile(modelManager, model1); + let modelFile1 = ParserUtil.newModelFile(modelManager, model1); modelManager.addModelFile(modelFile1); - let modelFile2 = new ModelFile(modelManager, model2); + let modelFile2 = ParserUtil.newModelFile(modelManager, model2); modelFile2.isImportedType('MyAsset2').should.be.true; }); @@ -322,9 +323,9 @@ describe('ModelFile', () => { asset MyAsset identified by assetId { o String assetId }`; - let modelFile1 = new ModelFile(modelManager, model1); + let modelFile1 = ParserUtil.newModelFile(modelManager, model1); modelManager.addModelFile(modelFile1); - let modelFile2 = new ModelFile(modelManager, model2); + let modelFile2 = ParserUtil.newModelFile(modelManager, model2); modelFile2.isImportedType('MyAsset3').should.be.false; }); @@ -340,9 +341,9 @@ describe('ModelFile', () => { asset MyAsset identified by assetId { o String assetId }`; - let modelFile1 = new ModelFile(modelManager, model1); + let modelFile1 = ParserUtil.newModelFile(modelManager, model1); modelManager.addModelFile(modelFile1); - let modelFile2 = new ModelFile(modelManager, model2); + let modelFile2 = ParserUtil.newModelFile(modelManager, model2); modelFile2.isImportedType('MyAsset3').should.be.false; }); @@ -354,7 +355,7 @@ describe('ModelFile', () => { const model = ` namespace org.acme import org.doge.Coin`; - let modelFile = new ModelFile(modelManager, model); + let modelFile = ParserUtil.newModelFile(modelManager, model); modelFile.resolveImport('Coin').should.equal('org.doge.Coin'); }); @@ -370,9 +371,9 @@ describe('ModelFile', () => { asset MyAsset identified by assetId { o String assetId }`; - let modelFile1 = new ModelFile(modelManager, model1); + let modelFile1 = ParserUtil.newModelFile(modelManager, model1); modelManager.addModelFile(modelFile1); - let modelFile2 = new ModelFile(modelManager, model2); + let modelFile2 = ParserUtil.newModelFile(modelManager, model2); modelFile2.resolveImport('MyAsset2').should.equal('org.acme.ext.MyAsset2'); }); @@ -380,7 +381,7 @@ describe('ModelFile', () => { const model = ` namespace org.acme import org.doge.Wow`; - let modelFile = new ModelFile(modelManager, model); + let modelFile = ParserUtil.newModelFile(modelManager, model); (() => { modelFile.resolveImport('Coin'); }).should.throw(/Coin/); @@ -398,9 +399,9 @@ describe('ModelFile', () => { asset MyAsset identified by assetId { o String assetId }`; - let modelFile1 = new ModelFile(modelManager, model1); + let modelFile1 = ParserUtil.newModelFile(modelManager, model1); modelManager.addModelFile(modelFile1); - let modelFile2 = new ModelFile(modelManager, model2); + let modelFile2 = ParserUtil.newModelFile(modelManager, model2); (() => { modelFile2.resolveImport('Coin'); }).should.throw(/Coin/); @@ -418,9 +419,9 @@ describe('ModelFile', () => { asset MyAsset identified by assetId { o String assetId }`; - let modelFile1 = new ModelFile(modelManager, model1); + let modelFile1 = ParserUtil.newModelFile(modelManager, model1); modelManager.addModelFile(modelFile1); - let modelFile2 = new ModelFile(modelManager, model2); + let modelFile2 = ParserUtil.newModelFile(modelManager, model2); (() => { modelFile2.resolveImport('Coin'); }).should.throw(/Coin/); @@ -435,7 +436,7 @@ describe('ModelFile', () => { --> DontExist relationship }`; - let modelFile2 = new ModelFile(modelManager, model2); + let modelFile2 = ParserUtil.newModelFile(modelManager, model2); (() => { modelFile2.validate(); }).should.throw(/DontExist/); @@ -480,7 +481,7 @@ describe('ModelFile', () => { body: [ ] }; sandbox.stub(Parser, 'parse').returns(ast); - let mf = new ModelFile(modelManager, 'fake definitions'); + let mf = ParserUtil.newModelFile(modelManager, 'fake definitions'); mf.getType('String').should.equal('String'); }); @@ -490,7 +491,7 @@ describe('ModelFile', () => { body: [ ] }; sandbox.stub(Parser, 'parse').returns(ast); - let mf = new ModelFile(modelManager, 'fake'); + let mf = ParserUtil.newModelFile(modelManager, 'fake'); mf.isImportedType = () => { return true; }; mf.resolveImport = () => { return 'org.acme'; }; should.not.exist(mf.getType('TNTAsset')); @@ -500,13 +501,13 @@ describe('ModelFile', () => { describe('#getAssetDeclaration', () => { it('should return the specified asset declaration', () => { - let modelFile = new ModelFile(modelManager, carLeaseModel); + let modelFile = ParserUtil.newModelFile(modelManager, carLeaseModel); let asset = modelFile.getAssetDeclaration('Vehicle'); asset.should.be.an.instanceOf(AssetDeclaration); }); it('should return null if it cannot find the specified asset declaration', () => { - let modelFile = new ModelFile(modelManager, carLeaseModel); + let modelFile = ParserUtil.newModelFile(modelManager, carLeaseModel); let asset = modelFile.getAssetDeclaration('Blobby'); should.equal(asset, null); }); @@ -516,13 +517,13 @@ describe('ModelFile', () => { describe('#getParticipantDeclaration', () => { it('should return the specified Participant declaration', () => { - let modelFile = new ModelFile(modelManager, carLeaseModel); + let modelFile = ParserUtil.newModelFile(modelManager, carLeaseModel); let participant = modelFile.getParticipantDeclaration('Regulator'); participant.should.be.an.instanceOf(ParticipantDeclaration); }); it('should return null if it cannot find the specified Participant declaration', () => { - let modelFile = new ModelFile(modelManager, carLeaseModel); + let modelFile = ParserUtil.newModelFile(modelManager, carLeaseModel); let participant = modelFile.getParticipantDeclaration('Blobby'); should.equal(participant, null); }); @@ -532,13 +533,13 @@ describe('ModelFile', () => { describe('#getTransactionDeclaration', () => { it('should return the specified Transaction declaration', () => { - let modelFile = new ModelFile(modelManager, carLeaseModel); + let modelFile = ParserUtil.newModelFile(modelManager, carLeaseModel); let transaction = modelFile.getTransactionDeclaration('VehicleCreated'); transaction.should.be.an.instanceOf(TransactionDeclaration); }); it('should return null if it cannot find the specified Transaction declaration', () => { - let modelFile = new ModelFile(modelManager, carLeaseModel); + let modelFile = ParserUtil.newModelFile(modelManager, carLeaseModel); let transaction = modelFile.getTransactionDeclaration('Blobby'); should.equal(transaction, null); }); @@ -548,13 +549,13 @@ describe('ModelFile', () => { describe('#getEventDeclaration', () => { it('should return the specified Event declaration', () => { - let modelFile = new ModelFile(modelManager, carLeaseModel); + let modelFile = ParserUtil.newModelFile(modelManager, carLeaseModel); let event = modelFile.getEventDeclaration('TestEvent'); event.should.be.an.instanceOf(EventDeclaration); }); it('should return null if it cannot find the specified Event declaration', () => { - let modelFile = new ModelFile(modelManager, carLeaseModel); + let modelFile = ParserUtil.newModelFile(modelManager, carLeaseModel); let transaction = modelFile.getEventDeclaration('Blobby'); should.equal(transaction, null); }); @@ -564,19 +565,19 @@ describe('ModelFile', () => { describe('#getEventDeclarations', () => { it('should return the expected number of Event declarations with system types', () => { - let modelFile = new ModelFile(modelManager, carLeaseModel); + let modelFile = ParserUtil.newModelFile(modelManager, carLeaseModel); let events = modelFile.getEventDeclarations(); events.length.should.equal(1); }); it('should return the expected number of Event declarations with system types', () => { - let modelFile = new ModelFile(modelManager, carLeaseModel); + let modelFile = ParserUtil.newModelFile(modelManager, carLeaseModel); let events = modelFile.getEventDeclarations(true); events.length.should.equal(1); }); it('should return the expected number of Event declarations without system types', () => { - let modelFile = new ModelFile(modelManager, carLeaseModel); + let modelFile = ParserUtil.newModelFile(modelManager, carLeaseModel); let events = modelFile.getEventDeclarations(); events.length.should.equal(1); }); @@ -585,7 +586,7 @@ describe('ModelFile', () => { describe('#getEnumDeclarations', () => { it('should return the expected number of Enum declarations', () => { - let modelFile = new ModelFile(modelManager, carLeaseModel); + let modelFile = ParserUtil.newModelFile(modelManager, carLeaseModel); let decls = modelFile.getEnumDeclarations(); decls.should.all.be.an.instanceOf(EnumDeclaration); decls.length.should.equal(1); @@ -600,7 +601,7 @@ describe('ModelFile', () => { body: [ ] }; sandbox.stub(Parser, 'parse').returns(ast); - let mf = new ModelFile(modelManager, 'fake'); + let mf = ParserUtil.newModelFile(modelManager, 'fake'); mf.isImportedType = () => { return false; }; mf.isLocalType = () => { return false; }; should.not.exist(mf.getFullyQualifiedTypeName('TNTAsset')); @@ -612,7 +613,7 @@ describe('ModelFile', () => { body: [ ] }; sandbox.stub(Parser, 'parse').returns(ast); - let modelFile = new ModelFile(modelManager, 'something'); + let modelFile = ParserUtil.newModelFile(modelManager, 'something'); modelFile.getFullyQualifiedTypeName('String').should.equal('String'); }); diff --git a/packages/concerto-core/test/introspect/semantic_validation.js b/packages/concerto-core/test/introspect/semantic_validation.js index 2b33d90d2c..2fe8840003 100644 --- a/packages/concerto-core/test/introspect/semantic_validation.js +++ b/packages/concerto-core/test/introspect/semantic_validation.js @@ -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'); @@ -38,7 +38,7 @@ describe('ModelFile semantic validation', () => { it('should throw and include file location', () => { try { - const mf = new ModelFile(modelManager,invalidModel, 'invalid.cto'); + const mf = ParserUtil.newModelFile(modelManager,invalidModel, 'invalid.cto'); mf.validate(); } catch(error) { diff --git a/packages/concerto-core/test/introspect/transactiondeclaration.js b/packages/concerto-core/test/introspect/transactiondeclaration.js index 98425367a3..71d97e710e 100644 --- a/packages/concerto-core/test/introspect/transactiondeclaration.js +++ b/packages/concerto-core/test/introspect/transactiondeclaration.js @@ -15,9 +15,9 @@ 'use strict'; const ClassDeclaration = require('../../lib/introspect/classdeclaration'); -const ModelFile = require('../../lib/introspect/modelfile'); const ModelManager = require('../../lib/modelmanager'); const Util = require('../composer/composermodelutility'); +const ParserUtil = require('../composer/parserutility'); require('chai').should(); const sinon = require('sinon'); @@ -47,7 +47,7 @@ describe('TransactionDeclaration', () => { transaction T {} `; - const modelFile = new ModelFile(modelManager, model); + const modelFile = ParserUtil.newModelFile(modelManager, model); let td = modelFile.getTransactionDeclaration('T'); td.validate(); diff --git a/packages/concerto-core/test/introspect/types.js b/packages/concerto-core/test/introspect/types.js index 3cf518504b..6c00625500 100644 --- a/packages/concerto-core/test/introspect/types.js +++ b/packages/concerto-core/test/introspect/types.js @@ -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'); @@ -37,7 +37,7 @@ describe('ModelFile type parsing', () => { describe('#constructor', () => { it('should be valid', () => { - const mf = new ModelFile(modelManager,invalidModel, 'types.cto'); + const mf = ParserUtil.newModelFile(modelManager,invalidModel, 'types.cto'); mf.validate(); }); @@ -50,7 +50,7 @@ describe('ModelFile type parsing', () => { } `; (() => { - const mf = new ModelFile(modelManager, model, 'test.cto'); + const mf = ParserUtil.newModelFile(modelManager, model, 'test.cto'); mf.validate(); }).should.throw(); }); @@ -64,7 +64,7 @@ describe('ModelFile type parsing', () => { } `; (() => { - const mf = new ModelFile(modelManager, model, 'test.cto'); + const mf = ParserUtil.newModelFile(modelManager, model, 'test.cto'); mf.validate(); }).should.throw(); }); @@ -78,7 +78,7 @@ describe('ModelFile type parsing', () => { } `; (() => { - const mf = new ModelFile(modelManager, model, 'test.cto'); + const mf = ParserUtil.newModelFile(modelManager, model, 'test.cto'); mf.validate(); }).should.throw(); }); @@ -92,7 +92,7 @@ describe('ModelFile type parsing', () => { } `; (() => { - const mf = new ModelFile(modelManager, model, 'test.cto'); + const mf = ParserUtil.newModelFile(modelManager, model, 'test.cto'); mf.validate(); }).should.throw(); }); @@ -106,7 +106,7 @@ describe('ModelFile type parsing', () => { } `; (() => { - const mf = new ModelFile(modelManager, model, 'test.cto'); + const mf = ParserUtil.newModelFile(modelManager, model, 'test.cto'); mf.validate(); }).should.throw(); }); diff --git a/packages/concerto-core/test/modelmanager.js b/packages/concerto-core/test/modelmanager.js index d068f0ce61..e0348be90f 100644 --- a/packages/concerto-core/test/modelmanager.js +++ b/packages/concerto-core/test/modelmanager.js @@ -30,6 +30,7 @@ const Serializer = require('../lib/serializer'); const TypeNotFoundException = require('../lib/typenotfoundexception'); const Util = require('./composer/composermodelutility'); const COMPOSER_MODEL = require('./composer/composermodel'); +const ParserUtil = require('./composer/parserutility'); const chai = require('chai'); const should = chai.should(); @@ -255,7 +256,7 @@ describe('ModelManager', () => { }); it('should be able to add model files without validation', () => { - modelManager.addModelFiles([composerModel, new ModelFile(modelManager, 'namespace foo concept Foo{o Missing m}', 'invalid.cto')], ['1.cto', '2.cto'], true); + modelManager.addModelFiles([composerModel, ParserUtil.newModelFile(modelManager, 'namespace foo concept Foo{o Missing m}', 'invalid.cto')], ['1.cto', '2.cto'], true); }); it('should add to existing model files from objects', () => { @@ -528,7 +529,7 @@ describe('ModelManager', () => { it('should update external models', () => { - const externalModelFile = new ModelFile(modelManager, `namespace org.external + const externalModelFile = ParserUtil.newModelFile(modelManager, `namespace org.external concept Foo{ o String baz }`, '@external.cto'); const mfd = sinon.createStubInstance(ModelFileDownloader); mfd.downloadExternalDependencies.returns(Promise.resolve([externalModelFile])); @@ -568,7 +569,7 @@ concept Bar { it('should rollback changes on error', () => { - const externalModelFile = new ModelFile(modelManager, `namespace org.external + const externalModelFile = ParserUtil.newModelFile(modelManager, `namespace org.external concept Foo{ o String baz }`, '@external.cto'); const mfd = sinon.createStubInstance(ModelFileDownloader); mfd.downloadExternalDependencies.returns(Promise.resolve([externalModelFile])); @@ -646,7 +647,7 @@ concept Foo { describe('#writeModelsToFileSystem', () => { beforeEach(async () => { - const externalModelFile = new ModelFile(modelManager, `namespace org.external + const externalModelFile = ParserUtil.newModelFile(modelManager, `namespace org.external concept Foo{ o String baz }`, '@external.cto'); const mfd = sinon.createStubInstance(ModelFileDownloader); mfd.downloadExternalDependencies.returns(Promise.resolve([externalModelFile])); @@ -717,7 +718,7 @@ concept Bar { }); }); it('should return a list of name / content pairs, with External Models', async () => { - const externalModelFile = new ModelFile(modelManager, `namespace org.external + const externalModelFile = ParserUtil.newModelFile(modelManager, `namespace org.external concept Foo{ o String baz }`, '@external.cto'); const mfd = sinon.createStubInstance(ModelFileDownloader); mfd.downloadExternalDependencies.returns(Promise.resolve([externalModelFile])); @@ -739,7 +740,7 @@ concept Bar { }); it('should return a list of name / content pairs, without External Models', async () => { - const externalModelFile = new ModelFile(modelManager, `namespace org.external + const externalModelFile = ParserUtil.newModelFile(modelManager, `namespace org.external concept Foo{ o String baz }`, '@external.cto'); const mfd = sinon.createStubInstance(ModelFileDownloader); mfd.downloadExternalDependencies.returns(Promise.resolve([externalModelFile]));