@accordproject/concerto-core 1.2.2-20220112170439 → 1.2.2-20220222214455

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/changelog.txt CHANGED
@@ -24,7 +24,7 @@
24
24
  # Note that the latest public API is documented using JSDocs and is available in api.txt.
25
25
  #
26
26
 
27
- Version 1.2.2 {fb3110c45d21beac59b99bba03d41197} 2021-11-24
27
+ Version 1.2.2 {859dc5db772867c4591ed1fd70b8f840} 2021-11-24
28
28
  - Remove custom instanceof and add methods to check runtime type
29
29
  - Remove support for Node 12
30
30
  - Generate Typescript definitions from JSDoc
@@ -15,201 +15,22 @@
15
15
  'use strict';
16
16
 
17
17
  const Printer = require('@accordproject/concerto-cto').Printer;
18
+ const MetaModelUtil = require('@accordproject/concerto-metamodel').MetaModelUtil;
19
+
18
20
  const ModelManager = require('../modelmanager');
19
21
  const Factory = require('../factory');
20
22
  const Serializer = require('../serializer');
21
23
 
22
- /**
23
- * The metamodel itself, as a CTO string
24
- */
25
- const metaModelCto = `namespace concerto.metamodel
26
-
27
- concept Position {
28
- o Integer line
29
- o Integer column
30
- o Integer offset
31
- }
32
-
33
- concept Range {
34
- o Position start
35
- o Position end
36
- o String source optional
37
- }
38
-
39
- concept TypeIdentifier {
40
- o String name
41
- o String namespace optional
42
- }
43
-
44
- abstract concept DecoratorLiteral {
45
- o Range location optional
46
- }
47
-
48
- concept DecoratorString extends DecoratorLiteral {
49
- o String value
50
- }
51
-
52
- concept DecoratorNumber extends DecoratorLiteral {
53
- o Double value
54
- }
55
-
56
- concept DecoratorBoolean extends DecoratorLiteral {
57
- o Boolean value
58
- }
59
-
60
- concept DecoratorTypeReference extends DecoratorLiteral {
61
- o TypeIdentifier type
62
- o Boolean isArray default=false
63
- }
64
-
65
- concept Decorator {
66
- o String name
67
- o DecoratorLiteral[] arguments optional
68
- o Range location optional
69
- }
70
-
71
- concept Identified {
72
- }
73
-
74
- concept IdentifiedBy extends Identified {
75
- o String name
76
- }
77
-
78
- abstract concept Declaration {
79
- o String name regex=/^(?!null|true|false)(\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4})(?:\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4}|\\p{Mn}|\\p{Mc}|\\p{Nd}|\\p{Pc}|\\u200C|\\u200D)*$/u
80
- o Decorator[] decorators optional
81
- o Range location optional
82
- }
83
-
84
- concept EnumDeclaration extends Declaration {
85
- o EnumProperty[] properties
86
- }
87
-
88
- concept EnumProperty {
89
- o String name regex=/^(?!null|true|false)(\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4})(?:\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4}|\\p{Mn}|\\p{Mc}|\\p{Nd}|\\p{Pc}|\\u200C|\\u200D)*$/u
90
- o Decorator[] decorators optional
91
- o Range location optional
92
- }
93
-
94
- concept ConceptDeclaration extends Declaration {
95
- o Boolean isAbstract default=false
96
- o Identified identified optional
97
- o TypeIdentifier superType optional
98
- o Property[] properties
99
- }
100
-
101
- concept AssetDeclaration extends ConceptDeclaration {
102
- }
103
-
104
- concept ParticipantDeclaration extends ConceptDeclaration {
105
- }
106
-
107
- concept TransactionDeclaration extends ConceptDeclaration {
108
- }
109
-
110
- concept EventDeclaration extends ConceptDeclaration {
111
- }
112
-
113
- abstract concept Property {
114
- o String name regex=/^(?!null|true|false)(\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4})(?:\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4}|\\p{Mn}|\\p{Mc}|\\p{Nd}|\\p{Pc}|\\u200C|\\u200D)*$/u
115
- o Boolean isArray default=false
116
- o Boolean isOptional default=false
117
- o Decorator[] decorators optional
118
- o Range location optional
119
- }
120
-
121
- concept RelationshipProperty extends Property {
122
- o TypeIdentifier type
123
- }
124
-
125
- concept ObjectProperty extends Property {
126
- o String defaultValue optional
127
- o TypeIdentifier type
128
- }
129
-
130
- concept BooleanProperty extends Property {
131
- o Boolean defaultValue optional
132
- }
133
-
134
- concept DateTimeProperty extends Property {
135
- }
136
-
137
- concept StringProperty extends Property {
138
- o String defaultValue optional
139
- o StringRegexValidator validator optional
140
- }
141
-
142
- concept StringRegexValidator {
143
- o String pattern
144
- o String flags
145
- }
146
-
147
- concept DoubleProperty extends Property {
148
- o Double defaultValue optional
149
- o DoubleDomainValidator validator optional
150
- }
151
-
152
- concept DoubleDomainValidator {
153
- o Double lower optional
154
- o Double upper optional
155
- }
156
-
157
- concept IntegerProperty extends Property {
158
- o Integer defaultValue optional
159
- o IntegerDomainValidator validator optional
160
- }
161
-
162
- concept IntegerDomainValidator {
163
- o Integer lower optional
164
- o Integer upper optional
165
- }
166
-
167
- concept LongProperty extends Property {
168
- o Long defaultValue optional
169
- o LongDomainValidator validator optional
170
- }
171
-
172
- concept LongDomainValidator {
173
- o Long lower optional
174
- o Long upper optional
175
- }
176
-
177
- abstract concept Import {
178
- o String namespace
179
- o String uri optional
180
- }
181
-
182
- concept ImportAll extends Import {
183
- }
184
-
185
- concept ImportType extends Import {
186
- o String name
187
- }
188
-
189
- concept Model {
190
- o String namespace
191
- o String sourceUri optional
192
- o String concertoVersion optional
193
- o Import[] imports optional
194
- o Declaration[] declarations optional
195
- }
196
-
197
- concept Models {
198
- o Model[] models
199
- }
200
- `;
201
-
202
24
  /**
203
25
  * Class to work with the Concerto metamodel
204
26
  */
205
27
  class MetaModel {
206
-
207
28
  /**
208
29
  * Returns the metamodel CTO
209
30
  * @returns {string} the metamodel as a CTO string
210
31
  */
211
32
  static getMetaModelCto() {
212
- return metaModelCto;
33
+ return MetaModelUtil.metaModelCto;
213
34
  }
214
35
 
215
36
  /**
@@ -218,7 +39,7 @@ class MetaModel {
218
39
  */
219
40
  static createMetaModelManager() {
220
41
  const metaModelManager = new ModelManager();
221
- metaModelManager.addModelFile(metaModelCto, 'concerto.metamodel');
42
+ metaModelManager.addModelFile(MetaModel.getMetaModelCto(), 'concerto.metamodel');
222
43
  return metaModelManager;
223
44
  }
224
45
 
@@ -236,134 +57,6 @@ class MetaModel {
236
57
  return serializer.toJSON(object);
237
58
  }
238
59
 
239
- /**
240
- * Create a name resolution table
241
- * @param {*} modelManager - the model manager
242
- * @param {object} metaModel - the metamodel (JSON)
243
- * @return {object} mapping from a name to its namespace
244
- */
245
- static createNameTable(modelManager, metaModel) {
246
- const table = {
247
- 'Concept': 'concerto',
248
- 'Asset': 'concerto',
249
- 'Participant': 'concerto',
250
- 'Transaction ': 'concerto',
251
- 'Event': 'concerto',
252
- };
253
-
254
- // First list the imported names in order (overriding as we go along)
255
- const imports = metaModel.imports;
256
- imports.forEach((imp) => {
257
- const namespace = imp.namespace;
258
- const modelFile = modelManager.getModelFile(namespace);
259
- if (imp.$class === 'concerto.metamodel.ImportType') {
260
- if (!modelFile.getLocalType(imp.name)) {
261
- throw new Error(`Declaration ${imp.name} in namespace ${namespace} not found`);
262
- }
263
- table[imp.name] = namespace;
264
- } else {
265
- const decls = modelFile.getAllDeclarations();
266
- decls.forEach((decl) => {
267
- table[decl.getName()] = namespace;
268
- });
269
- }
270
- });
271
-
272
- // Then add the names local to this metaModel (overriding as we go along)
273
- if (metaModel.declarations) {
274
- metaModel.declarations.forEach((decl) => {
275
- table[decl.name] = metaModel.namespace;
276
- });
277
- }
278
-
279
- return table;
280
- }
281
-
282
- /**
283
- * Resolve a name using the name table
284
- * @param {string} name - the name of the type to resolve
285
- * @param {object} table - the name table
286
- * @return {string} the namespace for that name
287
- */
288
- static resolveName(name, table) {
289
- if (!table[name]) {
290
- throw new Error(`Name ${name} not found`);
291
- }
292
- return table[name];
293
- }
294
-
295
- /**
296
- * Name resolution for metamodel
297
- * @param {object} metaModel - the metamodel (JSON)
298
- * @param {object} table - the name table
299
- * @return {object} the metamodel with fully qualified names
300
- */
301
- static resolveTypeNames(metaModel, table) {
302
- switch (metaModel.$class) {
303
- case 'concerto.metamodel.Model': {
304
- if (metaModel.declarations) {
305
- metaModel.declarations.forEach((decl) => {
306
- MetaModel.resolveTypeNames(decl, table);
307
- });
308
- }
309
- }
310
- break;
311
- case 'concerto.metamodel.AssetDeclaration':
312
- case 'concerto.metamodel.ConceptDeclaration':
313
- case 'concerto.metamodel.EventDeclaration':
314
- case 'concerto.metamodel.TransactionDeclaration':
315
- case 'concerto.metamodel.ParticipantDeclaration': {
316
- if (metaModel.superType) {
317
- const name = metaModel.superType.name;
318
- metaModel.superType.namespace = MetaModel.resolveName(name, table);
319
- }
320
- metaModel.properties.forEach((property) => {
321
- MetaModel.resolveTypeNames(property, table);
322
- });
323
- if (metaModel.decorators) {
324
- metaModel.decorators.forEach((decorator) => {
325
- MetaModel.resolveTypeNames(decorator, table);
326
- });
327
- }
328
- }
329
- break;
330
- case 'concerto.metamodel.EnumDeclaration': {
331
- if (metaModel.decorators) {
332
- metaModel.decorators.forEach((decorator) => {
333
- MetaModel.resolveTypeNames(decorator, table);
334
- });
335
- }
336
- }
337
- break;
338
- case 'concerto.metamodel.EnumProperty':
339
- case 'concerto.metamodel.ObjectProperty':
340
- case 'concerto.metamodel.RelationshipProperty': {
341
- const name = metaModel.type.name;
342
- metaModel.type.namespace = MetaModel.resolveName(name, table);
343
- if (metaModel.decorators) {
344
- metaModel.decorators.forEach((decorator) => {
345
- MetaModel.resolveTypeNames(decorator, table);
346
- });
347
- }
348
- }
349
- break;
350
- case 'concerto.metamodel.Decorator': {
351
- if (metaModel.arguments) {
352
- metaModel.arguments.forEach((argument) => {
353
- MetaModel.resolveTypeNames(argument, table);
354
- });
355
- }
356
- }
357
- break;
358
- case 'concerto.metamodel.DecoratorTypeReference': {
359
- const name = metaModel.type.name;
360
- metaModel.type.namespace = MetaModel.resolveName(name, table);
361
- }
362
- break;
363
- }
364
- return metaModel;
365
- }
366
-
367
60
  /**
368
61
  * Resolve the namespace for names in the metamodel
369
62
  * @param {object} modelManager - the ModelManager
@@ -375,11 +68,8 @@ class MetaModel {
375
68
  // First, validate the JSON metaModel
376
69
  const mm = validate ? MetaModel.validateMetaModel(metaModel) : metaModel;
377
70
 
378
- const result = JSON.parse(JSON.stringify(mm));
379
- const nameTable = MetaModel.createNameTable(modelManager, mm);
380
- // This adds the fully qualified names to the same object
381
- MetaModel.resolveTypeNames(result, nameTable);
382
- return result;
71
+ const priorModels = modelManager.getAst();
72
+ return MetaModelUtil.resolveLocalNames(priorModels, mm);
383
73
  }
384
74
 
385
75
  /**
@@ -82,11 +82,11 @@ class NumberValidator extends Validator{
82
82
  validate(identifier, value) {
83
83
  if(value !== null) {
84
84
  if(this.lowerBound !== null && value < this.lowerBound) {
85
- this.reportError(identifier, 'Value is outside lower bound ' + value);
85
+ this.reportError(identifier, `Value ${value} is outside lower bound ${this.lowerBound}`);
86
86
  }
87
87
 
88
88
  if(this.upperBound !== null && value > this.upperBound) {
89
- this.reportError(identifier, 'Value is outside upper bound ' + value);
89
+ this.reportError(identifier, `Value ${value} is outside upper bound ${this.upperBound}`);
90
90
  }
91
91
  }
92
92
  }
@@ -14,12 +14,11 @@
14
14
 
15
15
  'use strict';
16
16
 
17
- const fs = require('fs');
18
17
  const fsPath = require('path');
19
- const slash = require('slash');
20
18
 
21
19
  const DefaultFileLoader = require('@accordproject/concerto-util').DefaultFileLoader;
22
20
  const FileDownloader = require('@accordproject/concerto-util').FileDownloader;
21
+ const ModelWriter = require('@accordproject/concerto-util').ModelWriter;
23
22
  const Parser = require('@accordproject/concerto-cto').Parser;
24
23
 
25
24
  const Factory = require('./factory');
@@ -283,7 +282,6 @@ abstract concept Event {}
283
282
  * @return {Promise} a promise when the download and update operation is completed.
284
283
  */
285
284
  async updateExternalModels(options, fileDownloader) {
286
-
287
285
  const NAME = 'updateExternalModels';
288
286
  debug(NAME, 'updateExternalModels', options);
289
287
 
@@ -300,29 +298,7 @@ abstract concept Event {}
300
298
  fileDownloader = new FileDownloader(new DefaultFileLoader(processFile), getExternalImports);
301
299
  }
302
300
 
303
- const externalModelFiles = await fileDownloader.downloadExternalDependencies(this.getModelFiles(), options)
304
- .catch(error => {
305
- // If we're not able to download the latest dependencies, see whether the models all validate based on the available cached models.
306
- if(error.code === 'MISSING_DEPENDENCY'){
307
- try {
308
- this.validateModelFiles();
309
- return [];
310
- } catch (validationError) {
311
- // The validation error tells us the first model that is missing from the model manager, but the dependency download
312
- // will fail at the first external model, regardless of whether there is already a local copy.
313
- // As a hint to the user we display the URL of the external model that can't be found.
314
- const modelFile = this.getModelFileByFileName(validationError.fileName);
315
- const namespaces = modelFile.getExternalImports();
316
- const missingNs = Object.keys(namespaces).find((ns) => validationError.shortMessage.includes(ns));
317
- const url = modelFile.getImportURI(missingNs);
318
- const err = new Error(`Unable to download external model dependency '${url}'`);
319
- err.code = 'MISSING_DEPENDENCY';
320
- throw err;
321
- }
322
- } else {
323
- throw error;
324
- }
325
- });
301
+ const externalModelFiles = await fileDownloader.downloadExternalDependencies(this.getModelFiles(), options);
326
302
  const originalModelFiles = {};
327
303
  Object.assign(originalModelFiles, this.modelFiles);
328
304
 
@@ -356,22 +332,7 @@ abstract concept Event {}
356
332
  * If true, external models are written to the file system. Defaults to true
357
333
  */
358
334
  writeModelsToFileSystem(path, options = {}) {
359
- if(!path){
360
- throw new Error('`path` is a required parameter of writeModelsToFileSystem');
361
- }
362
-
363
- const opts = Object.assign({
364
- includeExternalModels: true,
365
- }, options);
366
-
367
- this.getModelFiles().forEach(function (file) {
368
- if (file.isExternal() && !opts.includeExternalModels) {
369
- return;
370
- }
371
- // Always assume file names have been normalized from `\` to `/`
372
- const filename = slash(file.fileName).split('/').pop();
373
- fs.writeFileSync(path + fsPath.sep + filename, file.definitions);
374
- });
335
+ ModelWriter.writeModelsToFileSystem(this.getModelFiles(), path, options);
375
336
  }
376
337
 
377
338
  /**
@@ -639,6 +600,22 @@ abstract concept Event {}
639
600
  }
640
601
  return false;
641
602
  }
603
+
604
+ /**
605
+ * Get the full ast (metamodel instances) for a modelmanager
606
+ * @returns {*} the metamodel
607
+ */
608
+ getAst() {
609
+ const result = {
610
+ $class: 'concerto.metamodel.Models',
611
+ models: [],
612
+ };
613
+ const modelFiles = this.getModelFiles();
614
+ modelFiles.forEach((thisModelFile) => {
615
+ result.models.push(thisModelFile.getAst());
616
+ });
617
+ return result;
618
+ }
642
619
  }
643
620
 
644
621
  module.exports = ModelManager;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@accordproject/concerto-core",
3
- "version": "1.2.2-20220112170439",
3
+ "version": "1.2.2-20220222214455",
4
4
  "description": "Core Implementation for the Concerto Modeling Language",
5
5
  "homepage": "https://github.com/accordproject/concerto",
6
6
  "engines": {
@@ -58,8 +58,9 @@
58
58
  "yargs": "17.1.0"
59
59
  },
60
60
  "dependencies": {
61
- "@accordproject/concerto-cto": "1.2.2-20220112170439",
62
- "@accordproject/concerto-util": "1.2.2-20220112170439",
61
+ "@accordproject/concerto-cto": "1.2.2-20220222214455",
62
+ "@accordproject/concerto-metamodel": "1.2.2-20220222214455",
63
+ "@accordproject/concerto-util": "1.2.2-20220222214455",
63
64
  "dayjs": "1.10.4",
64
65
  "debug": "4.3.1",
65
66
  "lorem-ipsum": "2.0.3",
@@ -19,27 +19,6 @@ declare class MetaModel {
19
19
  * @return {object} the validated metamodel in JSON
20
20
  */
21
21
  static validateMetaModel(input: object): object;
22
- /**
23
- * Create a name resolution table
24
- * @param {*} modelManager - the model manager
25
- * @param {object} metaModel - the metamodel (JSON)
26
- * @return {object} mapping from a name to its namespace
27
- */
28
- static createNameTable(modelManager: any, metaModel: object): object;
29
- /**
30
- * Resolve a name using the name table
31
- * @param {string} name - the name of the type to resolve
32
- * @param {object} table - the name table
33
- * @return {string} the namespace for that name
34
- */
35
- static resolveName(name: string, table: object): string;
36
- /**
37
- * Name resolution for metamodel
38
- * @param {object} metaModel - the metamodel (JSON)
39
- * @param {object} table - the name table
40
- * @return {object} the metamodel with fully qualified names
41
- */
42
- static resolveTypeNames(metaModel: object, table: object): object;
43
22
  /**
44
23
  * Resolve the namespace for names in the metamodel
45
24
  * @param {object} modelManager - the ModelManager
@@ -244,6 +244,11 @@ declare class ModelManager {
244
244
  * qualified type name, false otherwise.
245
245
  */
246
246
  derivesFrom(fqt1: string, fqt2: string): boolean;
247
+ /**
248
+ * Get the full metamodel for a modelmanager
249
+ * @returns {*} the metamodel
250
+ */
251
+ getMetaModel(): any;
247
252
  }
248
253
  import Factory = require("./factory");
249
254
  import Serializer = require("./serializer");