Skip to content

Commit ac70543

Browse files
dselmansanketshevkarmttrbrts
authored
feat(vocabulary) : support multiple terms per concept/property (#664)
* feat(vocabulary) : support multiple terms per concept/property Signed-off-by: Dan Selman <[email protected]> Signed-off-by: sanketshevkar <[email protected]> * feat(vocabulary): resolved bug for properties and added more test cases (#666) * feat(vocabulary): resolved bug for properties and added more test cases Signed-off-by: sanketshevkar <[email protected]> * feat(vocabulary): fix to support vocab attributes without '.' Signed-off-by: sanketshevkar <[email protected]> --------- Signed-off-by: sanketshevkar <[email protected]> * feat(vocabulary): old breaking test fixed (#667) * feat(vocabulary): resolved bug for properties and added more test cases Signed-off-by: sanketshevkar <[email protected]> * feat(vocabulary): fix to support vocab attributes without '.' Signed-off-by: sanketshevkar <[email protected]> * feat(vocabulary): old breaking test fixed Signed-off-by: sanketshevkar <[email protected]> --------- Signed-off-by: sanketshevkar <[email protected]> * chore(vocabulary): merge conflict resolution Signed-off-by: sanketshevkar <[email protected]> --------- Signed-off-by: Dan Selman <[email protected]> Signed-off-by: sanketshevkar <[email protected]> Co-authored-by: sanket Shevkar <[email protected]> Co-authored-by: sanketshevkar <[email protected]> Co-authored-by: Matt Roberts <[email protected]>
1 parent a8f797b commit ac70543

File tree

9 files changed

+14698
-4489
lines changed

9 files changed

+14698
-4489
lines changed

package-lock.json

Lines changed: 12332 additions & 4230 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/concerto-vocabulary/lib/vocabulary.js

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,19 +100,40 @@ class Vocabulary {
100100
* Gets the term for a concept, enum or property
101101
* @param {string} declarationName the name of a concept or enum
102102
* @param {string} [propertyName] the name of a property (optional)
103+
* @param {string} [identifier] the identifier of the term (optional)
103104
* @returns {string} the term or null if it does not exist
104105
*/
105-
getTerm(declarationName, propertyName) {
106+
getTerm(declarationName, propertyName, identifier) {
106107
const decl = this.content.declarations.find(d => Object.keys(d)[0] === declarationName);
107108
if(!decl) {
108109
return null;
109110
}
110111
if(!propertyName) {
111-
return decl[declarationName];
112+
return identifier ? decl[identifier] : decl[declarationName];
112113
}
113114
else {
114115
const property = decl.properties ? decl.properties.find(d => d[propertyName]) : null;
115-
return property ? property[propertyName] : null;
116+
return property ? identifier ? property[identifier] : property[propertyName] : null;
117+
}
118+
}
119+
120+
/**
121+
* Gets the terms for a concept, enum or property
122+
* @param {string} declarationName the name of a concept or enum
123+
* @param {string} [propertyName] the name of a property (optional)
124+
* @returns {string} the term or null if it does not exist
125+
*/
126+
getElementTerms(declarationName, propertyName) {
127+
const decl = this.content.declarations.find(d => Object.keys(d)[0] === declarationName);
128+
if(!decl) {
129+
return null;
130+
}
131+
if(!propertyName) {
132+
return decl;
133+
}
134+
else {
135+
const property = decl.properties ? decl.properties.find(d => d[propertyName]) : null;
136+
return property;
116137
}
117138
}
118139

packages/concerto-vocabulary/lib/vocabularymanager.js

Lines changed: 143 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,32 @@ class VocabularyManager {
179179
* @param {string} locale the BCP-47 locale identifier
180180
* @param {string} declarationName the name of a concept or enum
181181
* @param {string} [propertyName] the name of a property (optional)
182+
* @param {string} [identifier] the identifier of the term (optional)
182183
* @returns {string} the term or null if it does not exist
183184
*/
184-
resolveTerm(modelManager, namespace, locale, declarationName, propertyName) {
185+
resolveTerm(modelManager, namespace, locale, declarationName, propertyName, identifier) {
185186
const modelFile = modelManager.getModelFile(namespace);
186187
const classDecl = modelFile ? modelFile.getType(declarationName) : null;
187188
const property = propertyName ? classDecl ? classDecl.getProperty(propertyName) : null : null;
188-
return this.getTerm(property ? property.getNamespace() : namespace, locale, property ? property.getParent().getName() : declarationName, propertyName);
189+
return this.getTerm(property ? property.getNamespace() : namespace, locale, property ? property.getParent().getName() : declarationName, propertyName, identifier);
190+
}
191+
192+
/**
193+
* Resolve the terms for a property, looking up terms from a more general vocabulary
194+
* if required, and resolving properties using an object manager, allowing terms defined
195+
* on super types to be automatically resolved.
196+
* @param {ModelManager} modelManager the model manager
197+
* @param {string} namespace the namespace
198+
* @param {string} locale the BCP-47 locale identifier
199+
* @param {string} declarationName the name of a concept or enum
200+
* @param {string} [propertyName] the name of a property (optional)
201+
* @returns {*} the terms or null if it does not exist
202+
*/
203+
resolveTerms(modelManager, namespace, locale, declarationName, propertyName) {
204+
const modelFile = modelManager.getModelFile(namespace);
205+
const classDecl = modelFile ? modelFile.getType(declarationName) : null;
206+
const property = propertyName ? classDecl ? classDecl.getProperty(propertyName) : null : null;
207+
return this.getTerms(property ? property.getNamespace() : namespace, locale, property ? property.getParent().getName() : declarationName, propertyName);
189208
}
190209

191210
/**
@@ -195,28 +214,59 @@ class VocabularyManager {
195214
* @param {string} locale the BCP-47 locale identifier
196215
* @param {string} declarationName the name of a concept or enum
197216
* @param {string} [propertyName] the name of a property (optional)
217+
* @param {string} [identifier] the identifier of the term (optional)
198218
* @returns {string} the term or null if it does not exist
199219
*/
200-
getTerm(namespace, locale, declarationName, propertyName) {
220+
getTerm(namespace, locale, declarationName, propertyName, identifier) {
201221
const voc = this.getVocabulary(namespace, locale);
202222
let term = null;
203223
if (voc) {
204-
term = voc.getTerm(declarationName, propertyName);
224+
term = voc.getTerm(declarationName, propertyName, identifier);
205225
}
206226
if (term) {
207227
return term;
208228
}
209229
else {
210230
const dashIndex = locale.lastIndexOf('-');
211231
if (dashIndex >= 0) {
212-
return this.getTerm(namespace, locale.substring(0, dashIndex), declarationName, propertyName);
232+
return this.getTerm(namespace, locale.substring(0, dashIndex), declarationName, propertyName, identifier);
213233
}
214234
else {
215235
return this.missingTermGenerator ? this.missingTermGenerator(namespace, locale, declarationName, propertyName) : null;
216236
}
217237
}
218238
}
219239

240+
/**
241+
* Gets the term for a concept, enum or property, looking up terms
242+
* from a more general vocabulary if required
243+
* @param {string} namespace the namespace
244+
* @param {string} locale the BCP-47 locale identifier
245+
* @param {string} declarationName the name of a concept or enum
246+
* @param {string} [propertyName] the name of a property (optional)
247+
* @returns {*} the terms or null if it does not exist
248+
*/
249+
getTerms(namespace, locale, declarationName, propertyName) {
250+
const voc = this.getVocabulary(namespace, locale);
251+
let term = null;
252+
if (voc) {
253+
term = voc.getElementTerms(declarationName, propertyName);
254+
}
255+
if (term) {
256+
return term;
257+
}
258+
else {
259+
const dashIndex = locale.lastIndexOf('-');
260+
if (dashIndex >= 0) {
261+
return this.getTerms(namespace, locale.substring(0, dashIndex), declarationName, propertyName);
262+
}
263+
else {
264+
const missingKey = propertyName ? propertyName : declarationName;
265+
return this.missingTermGenerator ? { [missingKey]: this.missingTermGenerator(namespace, locale, declarationName, propertyName) } : null;
266+
}
267+
}
268+
}
269+
220270
/**
221271
* Creates a DecoractorCommandSet with @Term decorators
222272
* to decorate all model elements based on the vocabulary for a locale.
@@ -236,51 +286,101 @@ class VocabularyManager {
236286

237287
modelManager.getModelFiles().forEach(model => {
238288
model.getAllDeclarations().forEach(decl => {
239-
const term = this.resolveTerm(modelManager, model.getNamespace(), locale, decl.getName());
240-
if (term) {
241-
decoratorCommandSet.commands.push({
242-
'$class': 'org.accordproject.decoratorcommands.Command',
243-
'type': 'UPSERT',
244-
'target': {
245-
'$class': 'org.accordproject.decoratorcommands.CommandTarget',
246-
'namespace': model.getNamespace(),
247-
'declaration': decl.getName(),
248-
},
249-
'decorator': {
250-
'$class': `${MetaModelNamespace}.Decorator`,
251-
'name': 'Term',
252-
'arguments': [
253-
{
254-
'$class': `${MetaModelNamespace}.DecoratorString`,
255-
'value': term
289+
const terms = this.resolveTerms(modelManager, model.getNamespace(), locale, decl.getName());
290+
if (terms) {
291+
Object.keys(terms).forEach( term => {
292+
if(term === decl.getName()) {
293+
decoratorCommandSet.commands.push({
294+
'$class': 'org.accordproject.decoratorcommands.Command',
295+
'type': 'UPSERT',
296+
'target': {
297+
'$class': 'org.accordproject.decoratorcommands.CommandTarget',
298+
'namespace': model.getNamespace(),
299+
'declaration': decl.getName(),
256300
},
257-
]
301+
'decorator': {
302+
'$class': `${MetaModelNamespace}.Decorator`,
303+
'name': 'Term',
304+
'arguments': [
305+
{
306+
'$class': `${MetaModelNamespace}.DecoratorString`,
307+
'value': terms[term]
308+
},
309+
]
310+
}
311+
});
312+
}
313+
else if(term.localeCompare('properties')) {
314+
decoratorCommandSet.commands.push({
315+
'$class': 'org.accordproject.decoratorcommands.Command',
316+
'type': 'UPSERT',
317+
'target': {
318+
'$class': 'org.accordproject.decoratorcommands.CommandTarget',
319+
'namespace': model.getNamespace(),
320+
'declaration': decl.getName(),
321+
},
322+
'decorator': {
323+
'$class': `${MetaModelNamespace}.Decorator`,
324+
'name': `Term_${term}`,
325+
'arguments': [
326+
{
327+
'$class': `${MetaModelNamespace}.DecoratorString`,
328+
'value': terms[term]
329+
},
330+
]
331+
}
332+
});
258333
}
259334
});
260335
}
261336

262337
decl.getProperties?.().forEach(property => {
263-
const propertyTerm = this.resolveTerm(modelManager, model.getNamespace(), locale, decl.getName(), property.getName());
264-
265-
if (propertyTerm) {
266-
decoratorCommandSet.commands.push({
267-
'$class': 'org.accordproject.decoratorcommands.Command',
268-
'type': 'UPSERT',
269-
'target': {
270-
'$class': 'org.accordproject.decoratorcommands.CommandTarget',
271-
'namespace': model.getNamespace(),
272-
'declaration': decl.getName(),
273-
'property': property.getName()
274-
},
275-
'decorator': {
276-
'$class': `${MetaModelNamespace}.Decorator`,
277-
'name': 'Term',
278-
'arguments': [
279-
{
280-
'$class': `${MetaModelNamespace}.DecoratorString`,
281-
'value': propertyTerm
338+
const propertyTerms = this.resolveTerms(modelManager, model.getNamespace(), locale, decl.getName(), property.getName());
339+
if (propertyTerms) {
340+
Object.keys(propertyTerms).forEach( term => {
341+
if(term === property.getName()) {
342+
decoratorCommandSet.commands.push({
343+
'$class': 'org.accordproject.decoratorcommands.Command',
344+
'type': 'UPSERT',
345+
'target': {
346+
'$class': 'org.accordproject.decoratorcommands.CommandTarget',
347+
'namespace': model.getNamespace(),
348+
'declaration': decl.getName(),
349+
'property': property.getName()
350+
},
351+
'decorator': {
352+
'$class': `${MetaModelNamespace}.Decorator`,
353+
'name': 'Term',
354+
'arguments': [
355+
{
356+
'$class': `${MetaModelNamespace}.DecoratorString`,
357+
'value': propertyTerms[term]
358+
},
359+
]
360+
}
361+
});
362+
}
363+
else {
364+
decoratorCommandSet.commands.push({
365+
'$class': 'org.accordproject.decoratorcommands.Command',
366+
'type': 'UPSERT',
367+
'target': {
368+
'$class': 'org.accordproject.decoratorcommands.CommandTarget',
369+
'namespace': model.getNamespace(),
370+
'declaration': decl.getName(),
371+
'property': property.getName()
282372
},
283-
]
373+
'decorator': {
374+
'$class': `${MetaModelNamespace}.Decorator`,
375+
'name': `Term_${term}`,
376+
'arguments': [
377+
{
378+
'$class': `${MetaModelNamespace}.DecoratorString`,
379+
'value': propertyTerms[term]
380+
},
381+
]
382+
}
383+
});
284384
}
285385
});
286386
}

0 commit comments

Comments
 (0)