@@ -22,23 +22,45 @@ const { MetaModelNamespace } = require('@accordproject/concerto-metamodel');
2222 * Utility functions to work with
2323 * [DecoratorCommandSet](https://models.accordproject.org/concerto/decorators.cto)
2424 * @memberof module:concerto-core
25+ * @private
2526 */
2627class DecoratorExtractor {
28+ /**
29+ * The action to be performed to extract all, only vocab or only non-vocab decorators
30+ */
31+ static Action = {
32+ EXTRACT_ALL : 0 ,
33+ EXTRACT_VOCAB : 1 ,
34+ EXTRACT_NON_VOCAB : 2
35+ } ;
36+
2737 /**
2838 * Create the DecoratorExtractor.
2939 * @constructor
3040 * @param {boolean } removeDecoratorsFromModel - flag to determine whether to remove decorators from source model
3141 * @param {string } locale - locale for extracted vocabularies
3242 * @param {string } dcs_version - version string
3343 * @param {Object } sourceModelAst - the ast of source models
44+ * @param {int } [action=DecoratorExtractor.Action.EXTRACT_ALL] - the action to be performed
3445 */
35- constructor ( removeDecoratorsFromModel , locale , dcs_version , sourceModelAst ) {
46+ constructor ( removeDecoratorsFromModel , locale , dcs_version , sourceModelAst , action = DecoratorExtractor . Action . EXTRACT_ALL ) {
3647 this . extractionDictionary = { } ;
3748 this . removeDecoratorsFromModel = removeDecoratorsFromModel ;
3849 this . locale = locale ;
3950 this . dcs_version = dcs_version ;
4051 this . sourceModelAst = sourceModelAst ;
4152 this . updatedModelAst = sourceModelAst ;
53+ this . action = Object . values ( DecoratorExtractor . Action ) . includes ( action ) ? action : DecoratorExtractor . Action . EXTRACT_ALL ;
54+ }
55+
56+ /**
57+ * Returns if the decorator is vocab or not
58+ * @param {string } decoractorName - the name of decorator
59+ * @returns {boolean } - returns true if the decorator is a vocabulary decorator else false
60+ * @private
61+ */
62+ isVocabDecorator ( decoractorName ) {
63+ return decoractorName === 'Term' || decoractorName . startsWith ( 'Term_' ) ;
4264 }
4365 /**
4466 * Adds a key-value pair to a dictionary (object) if the key exists,
@@ -105,18 +127,24 @@ class DecoratorExtractor {
105127 Object . keys ( vocabObject ) . forEach ( decl => {
106128 if ( vocabObject [ decl ] . term ) {
107129 strVoc += ` - ${ decl } : ${ vocabObject [ decl ] . term } \n` ;
108- const otherProps = Object . keys ( vocabObject [ decl ] ) . filter ( ( str ) => str !== 'term' && str !== 'propertyVocabs' ) ;
130+ }
131+ const otherProps = Object . keys ( vocabObject [ decl ] ) . filter ( ( str ) => str !== 'term' && str !== 'propertyVocabs' ) ;
132+ //If a declaration does not have any Term decorator, then add Term_ decorators to yaml
133+ if ( otherProps . length > 0 ) {
134+ if ( ! vocabObject [ decl ] . term ) {
135+ strVoc += ` - ${ decl } : ${ decl } \n` ;
136+ }
109137 otherProps . forEach ( key => {
110138 strVoc += ` ${ key } : ${ vocabObject [ decl ] [ key ] } \n` ;
111139 } ) ;
112140 }
113141 if ( vocabObject [ decl ] . propertyVocabs && Object . keys ( vocabObject [ decl ] . propertyVocabs ) . length > 0 ) {
114- if ( ! vocabObject [ decl ] . term ) {
142+ if ( ! vocabObject [ decl ] . term && otherProps . length === 0 ) {
115143 strVoc += ` - ${ decl } : ${ decl } \n` ;
116144 }
117145 strVoc += ' properties:\n' ;
118146 Object . keys ( vocabObject [ decl ] . propertyVocabs ) . forEach ( prop => {
119- strVoc += ` - ${ prop } : ${ vocabObject [ decl ] . propertyVocabs [ prop ] . term } \n` ;
147+ strVoc += ` - ${ prop } : ${ vocabObject [ decl ] . propertyVocabs [ prop ] . term || '' } \n` ;
120148 const otherProps = Object . keys ( vocabObject [ decl ] . propertyVocabs [ prop ] ) . filter ( ( str ) => str !== 'term' ) ;
121149 otherProps . forEach ( key => {
122150 strVoc += ` ${ key } : ${ vocabObject [ decl ] . propertyVocabs [ prop ] [ key ] } \n` ;
@@ -205,6 +233,18 @@ class DecoratorExtractor {
205233 dictVoc [ decl . declaration ] . propertyVocabs [ decl . property ] [ extensionKey ] = dcs . arguments [ 0 ] . value ;
206234 }
207235 }
236+ else if ( decl . mapElement !== '' ) {
237+ if ( ! dictVoc [ decl . declaration ] . propertyVocabs [ decl . mapElement ] ) {
238+ dictVoc [ decl . declaration ] . propertyVocabs [ decl . mapElement ] = { } ;
239+ }
240+ if ( dcs . name === 'Term' ) {
241+ dictVoc [ decl . declaration ] . propertyVocabs [ decl . mapElement ] . term = dcs . arguments [ 0 ] . value ;
242+ }
243+ else {
244+ const extensionKey = dcs . name . split ( 'Term_' ) [ 1 ] ;
245+ dictVoc [ decl . declaration ] . propertyVocabs [ decl . mapElement ] [ extensionKey ] = dcs . arguments [ 0 ] . value ;
246+ }
247+ }
208248 else {
209249 if ( dcs . name === 'Term' ) {
210250 dictVoc [ decl . declaration ] . term = dcs . arguments [ 0 ] . value ;
@@ -227,30 +267,54 @@ class DecoratorExtractor {
227267 let vocabData = [ ] ;
228268 Object . keys ( this . extractionDictionary ) . forEach ( namespace => {
229269 const jsonData = this . extractionDictionary [ namespace ] ;
230- const patternToDetermineVocab = / ^ T e r m _ / i;
231270 let dcsObjects = [ ] ;
232271 let vocabObject = { } ;
233272 jsonData . forEach ( obj => {
234273 const decos = JSON . parse ( obj . dcs ) ;
235274 const target = this . constructTarget ( namespace , obj ) ;
236275 decos . forEach ( dcs => {
237- if ( dcs . name !== 'Term' && ! patternToDetermineVocab . test ( dcs . name ) ) {
276+ const isVocab = this . isVocabDecorator ( dcs . name ) ;
277+ if ( ! isVocab && this . action !== DecoratorExtractor . Action . EXTRACT_VOCAB ) {
238278 dcsObjects = this . parseNonVocabularyDecorators ( dcsObjects , dcs , this . dcs_version , target ) ;
239279 }
240- else {
280+ if ( isVocab && this . action !== DecoratorExtractor . Action . EXTRACT_NON_VOCAB ) {
241281 vocabObject = this . parseVocabularies ( vocabObject , obj , dcs ) ;
242282 }
243283 } ) ;
244284 } ) ;
245- decoratorData = this . transformNonVocabularyDecorators ( dcsObjects , namespace , decoratorData ) ;
246- vocabData = this . transformVocabularyDecorators ( vocabObject , namespace , vocabData ) ;
285+ if ( this . action !== DecoratorExtractor . Action . EXTRACT_VOCAB ) {
286+ decoratorData = this . transformNonVocabularyDecorators ( dcsObjects , namespace , decoratorData ) ;
287+ }
288+ if ( this . action !== DecoratorExtractor . Action . EXTRACT_NON_VOCAB ) {
289+ vocabData = this . transformVocabularyDecorators ( vocabObject , namespace , vocabData ) ;
290+ }
247291 } ) ;
248292 return {
249293 decoratorCommandSet : decoratorData ,
250294 vocabularies : vocabData
251295 } ;
252296 }
297+ /**
298+ * Filter vocab or non-vocab decorators
299+ * @param {Object } decorators - the collection of decorators
300+ * @returns {Object } - the collection of filtered decorators
301+ * @private
302+ */
303+ filterOutDecorators ( decorators ) {
304+ if ( ! this . removeDecoratorsFromModel ) {
305+ return decorators ;
306+ }
253307
308+ if ( this . action === DecoratorExtractor . Action . EXTRACT_ALL ) {
309+ return undefined ;
310+ }
311+ else if ( this . action === DecoratorExtractor . Action . EXTRACT_VOCAB ) {
312+ return decorators . filter ( ( dcs ) => ! this . isVocabDecorator ( dcs . name ) ) ;
313+ }
314+ else {
315+ return decorators . filter ( ( dcs ) => this . isVocabDecorator ( dcs . name ) ) ;
316+ }
317+ }
254318 /**
255319 * Process the map declarations to extract the decorators.
256320 *
@@ -267,9 +331,7 @@ class DecoratorExtractor {
267331 mapElement : 'KEY'
268332 } ;
269333 this . constructDCSDictionary ( namespace , declaration . key . decorators , constructOptions ) ;
270- if ( this . removeDecoratorsFromModel ) {
271- declaration . key . decorators = undefined ;
272- }
334+ declaration . key . decorators = this . filterOutDecorators ( declaration . key . decorators ) ;
273335 }
274336 }
275337 if ( declaration . value ) {
@@ -279,9 +341,7 @@ class DecoratorExtractor {
279341 mapElement : 'VALUE'
280342 } ;
281343 this . constructDCSDictionary ( namespace , declaration . value . decorators , constructOptions ) ;
282- if ( this . removeDecoratorsFromModel ) {
283- declaration . value . decorators = undefined ;
284- }
344+ declaration . value . decorators = this . filterOutDecorators ( declaration . value . decorators ) ;
285345 }
286346 }
287347 return declaration ;
@@ -304,9 +364,7 @@ class DecoratorExtractor {
304364 property : property . name
305365 } ;
306366 this . constructDCSDictionary ( namespace , property . decorators , constructOptions ) ;
307- }
308- if ( this . removeDecoratorsFromModel ) {
309- property . decorators = undefined ;
367+ property . decorators = this . filterOutDecorators ( property . decorators ) ;
310368 }
311369 return property ;
312370 } ) ;
@@ -328,9 +386,7 @@ class DecoratorExtractor {
328386 declaration : decl . name ,
329387 } ;
330388 this . constructDCSDictionary ( namespace , decl . decorators , constructOptions ) ;
331- }
332- if ( this . removeDecoratorsFromModel ) {
333- decl . decorators = undefined ;
389+ decl . decorators = this . filterOutDecorators ( decl . decorators ) ;
334390 }
335391 if ( decl . $class === `${ MetaModelNamespace } .MapDeclaration` ) {
336392 const processedMapDecl = this . processMapDeclaration ( decl , namespace ) ;
@@ -352,11 +408,9 @@ class DecoratorExtractor {
352408 */
353409 processModels ( ) {
354410 const processedModels = this . sourceModelAst . models . map ( model => {
355- if ( ( model ?. decorators . length > 0 ) ) {
411+ if ( ( model ?. decorators ? .length > 0 ) ) {
356412 this . constructDCSDictionary ( model . namespace , model . decorators , { } ) ;
357- if ( this . removeDecoratorsFromModel ) {
358- model . decorators = undefined ;
359- }
413+ model . decorators = this . filterOutDecorators ( model . decorators ) ;
360414 }
361415 const processedDecl = this . processDeclarations ( model . declarations , model . namespace ) ;
362416 model . declarations = processedDecl ;
0 commit comments