1414
1515'use strict' ;
1616
17+ const semver = require ( 'semver' ) ;
18+
1719/**
1820 * The metamodel itself, as an AST.
1921 * @type unknown
@@ -37,7 +39,54 @@ const metaModelCto = require('./metamodel.js');
3739 * @return {* } the model
3840 */
3941function findNamespace ( priorModels , namespace ) {
40- return priorModels . models . find ( ( thisModel ) => thisModel . namespace === namespace ) ;
42+ // Exact match fast-path
43+ const exact = priorModels . models . find (
44+ ( thisModel ) => thisModel . namespace === namespace
45+ ) ;
46+ if ( exact ) {
47+ return exact ;
48+ }
49+
50+ // Parse "name@versionOrRange"
51+ const atIndex = namespace . lastIndexOf ( '@' ) ;
52+ if ( atIndex <= 0 ) {
53+ return undefined ;
54+ }
55+ const baseName = namespace . substring ( 0 , atIndex ) ;
56+ const wanted = namespace . substring ( atIndex + 1 ) ;
57+
58+ // Collect candidates with the same base name
59+ const candidates = priorModels . models
60+ . filter ( ( m ) => {
61+ const idx = m . namespace . lastIndexOf ( '@' ) ;
62+ if ( idx <= 0 ) {
63+ return false ;
64+ }
65+ const name = m . namespace . substring ( 0 , idx ) ;
66+ return name === baseName ;
67+ } )
68+ . map ( ( m ) => {
69+ const v = m . namespace . substring ( m . namespace . lastIndexOf ( '@' ) + 1 ) ;
70+ return { model : m , version : v } ;
71+ } ) ;
72+
73+ if ( candidates . length === 0 ) {
74+ return undefined ;
75+ }
76+
77+ // Treat requested as a range (supports x-ranges like 1.x, 1.1.x)
78+ // Pick the highest version that satisfies the range
79+ const satisfying = candidates
80+ . filter ( ( c ) => semver . valid ( c . version ) )
81+ . filter ( ( c ) =>
82+ semver . satisfies ( c . version , wanted , {
83+ includePrerelease : false ,
84+ loose : true ,
85+ } )
86+ )
87+ . sort ( ( a , b ) => semver . rcompare ( a . version , b . version ) ) ;
88+
89+ return satisfying . length > 0 ? satisfying [ 0 ] . model : undefined ;
4190}
4291
4392/**
@@ -59,11 +108,11 @@ function findDeclaration(thisModel, name) {
59108function createNameTable ( priorModels , metaModel ) {
60109 const concertoNs = '[email protected] ' ; 61110 const table = {
62- ' Concept' : { namespace : concertoNs , name : 'Concept' } ,
63- ' Asset' : { namespace : concertoNs , name : 'Asset' } ,
64- ' Participant' : { namespace : concertoNs , name : 'Participant' } ,
65- ' Transaction' : { namespace : concertoNs , name : 'Transaction' } ,
66- ' Event' : { namespace : concertoNs , name : 'Event' } ,
111+ Concept : { namespace : concertoNs , name : 'Concept' } ,
112+ Asset : { namespace : concertoNs , name : 'Asset' } ,
113+ Participant : { namespace : concertoNs , name : 'Participant' } ,
114+ Transaction : { namespace : concertoNs , name : 'Transaction' } ,
115+ Event : { namespace : concertoNs , name : 'Event' } ,
67116 } ;
68117
69118 // First list the imported names in order (overriding as we go along)
@@ -72,13 +121,17 @@ function createNameTable(priorModels, metaModel) {
72121 const modelFile = findNamespace ( priorModels , namespace ) ;
73122 if ( imp . $class === `${ MetaModelNamespace } .ImportType` ) {
74123 if ( ! findDeclaration ( modelFile , imp . name ) ) {
75- throw new Error ( `Declaration ${ imp . name } in namespace ${ namespace } not found` ) ;
124+ throw new Error (
125+ `Declaration ${ imp . name } in namespace ${ namespace } not found`
126+ ) ;
76127 }
77- table [ imp . name ] = { namespace, name : imp . name } ;
128+ table [ imp . name ] = { namespace, name : imp . name } ;
78129 } else if ( imp . $class === `${ MetaModelNamespace } .ImportTypes` ) {
79130 // Create a map of aliased types if they exist, otherwise initialize an empty map.
80131 const aliasedMap = imp . aliasedTypes
81- ? new Map ( imp . aliasedTypes . map ( ( { name, aliasedName } ) => [ name , aliasedName ] ) )
132+ ? new Map (
133+ imp . aliasedTypes . map ( ( { name, aliasedName } ) => [ name , aliasedName ] )
134+ )
82135 : new Map ( ) ;
83136 imp . types . forEach ( ( type ) => {
84137 // 'localName' is the identifier used to refer to the imported type, as it can be aliased..
@@ -87,20 +140,25 @@ function createNameTable(priorModels, metaModel) {
87140 // Verify if the type declaration exists in the model file.
88141 // Here, 'type' refers to the actual declaration name within the model file that is being imported.
89142 if ( ! findDeclaration ( modelFile , type ) ) {
90- throw new Error ( `Declaration ${ type } in namespace ${ namespace } not found` ) ;
143+ throw new Error (
144+ `Declaration ${ type } in namespace ${ namespace } not found`
145+ ) ;
91146 }
92- table [ localName ] = localName !== type ? { namespace, name : localName , resolvedName : type } : { namespace, name : type } ;
147+ table [ localName ] =
148+ localName !== type
149+ ? { namespace, name : localName , resolvedName : type }
150+ : { namespace, name : type } ;
93151 } ) ;
94152 } else {
95153 ( modelFile . declarations || [ ] ) . forEach ( ( decl ) => {
96- table [ decl . name ] = { namespace, name : decl . name } ;
154+ table [ decl . name ] = { namespace, name : decl . name } ;
97155 } ) ;
98156 }
99157 } ) ;
100158
101159 // Then add the names local to this metaModel (overriding as we go along)
102160 ( metaModel . declarations || [ ] ) . forEach ( ( decl ) => {
103- table [ decl . name ] = { namespace : metaModel . namespace , name : decl . name } ;
161+ table [ decl . name ] = { namespace : metaModel . namespace , name : decl . name } ;
104162 } ) ;
105163
106164 return table ;
@@ -132,64 +190,70 @@ function resolveTypeNames(metaModel, table) {
132190 } ) ;
133191
134192 switch ( metaModel . $class ) {
135- case `${ MetaModelNamespace } .Model` : {
136- ( metaModel . declarations || [ ] ) . forEach ( ( decl ) => {
137- resolveTypeNames ( decl , table ) ;
138- } ) ;
139- }
193+ case `${ MetaModelNamespace } .Model` :
194+ {
195+ ( metaModel . declarations || [ ] ) . forEach ( ( decl ) => {
196+ resolveTypeNames ( decl , table ) ;
197+ } ) ;
198+ }
140199 break ;
141200 case `${ MetaModelNamespace } .EnumDeclaration` :
142201 case `${ MetaModelNamespace } .AssetDeclaration` :
143202 case `${ MetaModelNamespace } .ConceptDeclaration` :
144203 case `${ MetaModelNamespace } .EventDeclaration` :
145204 case `${ MetaModelNamespace } .TransactionDeclaration` :
146- case `${ MetaModelNamespace } .ParticipantDeclaration` : {
147- if ( metaModel . superType ) {
148- const name = metaModel . superType . name ;
149- metaModel . superType . namespace = resolveName ( name , table ) ;
150- metaModel . superType . name = table [ name ] . name ;
151- if ( table [ name ] ?. resolvedName ) {
152- metaModel . superType . resolvedName = table [ name ] . resolvedName ;
205+ case `${ MetaModelNamespace } .ParticipantDeclaration` :
206+ {
207+ if ( metaModel . superType ) {
208+ const name = metaModel . superType . name ;
209+ metaModel . superType . namespace = resolveName ( name , table ) ;
210+ metaModel . superType . name = table [ name ] . name ;
211+ if ( table [ name ] ?. resolvedName ) {
212+ metaModel . superType . resolvedName = table [ name ] . resolvedName ;
213+ }
153214 }
215+ ( metaModel . properties || [ ] ) . forEach ( ( property ) => {
216+ resolveTypeNames ( property , table ) ;
217+ } ) ;
154218 }
155- ( metaModel . properties || [ ] ) . forEach ( ( property ) => {
156- resolveTypeNames ( property , table ) ;
157- } ) ;
158- }
159219 break ;
160- case `${ MetaModelNamespace } .MapDeclaration` : {
161- resolveTypeNames ( metaModel . key , table ) ;
162- resolveTypeNames ( metaModel . value , table ) ;
163- }
220+ case `${ MetaModelNamespace } .MapDeclaration` :
221+ {
222+ resolveTypeNames ( metaModel . key , table ) ;
223+ resolveTypeNames ( metaModel . value , table ) ;
224+ }
164225 break ;
165- case `${ MetaModelNamespace } .Decorator` : {
166- ( metaModel . arguments || [ ] ) . forEach ( ( argument ) => {
167- resolveTypeNames ( argument , table ) ;
168- } ) ;
169- }
226+ case `${ MetaModelNamespace } .Decorator` :
227+ {
228+ ( metaModel . arguments || [ ] ) . forEach ( ( argument ) => {
229+ resolveTypeNames ( argument , table ) ;
230+ } ) ;
231+ }
170232 break ;
171233 case `${ MetaModelNamespace } .ObjectProperty` :
172234 case `${ MetaModelNamespace } .RelationshipProperty` :
173235 case `${ MetaModelNamespace } .DecoratorTypeReference` :
174236 case `${ MetaModelNamespace } .ObjectMapKeyType` :
175237 case `${ MetaModelNamespace } .ObjectMapValueType` :
176- case `${ MetaModelNamespace } .RelationshipMapValueType` : {
177- metaModel . type . namespace = resolveName ( metaModel . type . name , table ) ;
178- metaModel . type . name = table [ metaModel . type . name ] . name ;
179- if ( table [ metaModel . type . name ] ?. resolvedName ) {
180- metaModel . type . resolvedName = table [ metaModel . type . name ] . resolvedName ;
238+ case `${ MetaModelNamespace } .RelationshipMapValueType` :
239+ {
240+ metaModel . type . namespace = resolveName ( metaModel . type . name , table ) ;
241+ metaModel . type . name = table [ metaModel . type . name ] . name ;
242+ if ( table [ metaModel . type . name ] ?. resolvedName ) {
243+ metaModel . type . resolvedName = table [ metaModel . type . name ] . resolvedName ;
244+ }
181245 }
182- }
183246 break ;
184247 case `${ MetaModelNamespace } .StringScalar` :
185248 case `${ MetaModelNamespace } .BooleanScalar` :
186249 case `${ MetaModelNamespace } .DateTimeScalar` :
187250 case `${ MetaModelNamespace } .DoubleScalar` :
188251 case `${ MetaModelNamespace } .LongScalar` :
189- case `${ MetaModelNamespace } .IntegerScalar` : {
190- metaModel . namespace = resolveName ( metaModel . name , table ) ;
191- metaModel . name = table [ metaModel . name ] . name ;
192- }
252+ case `${ MetaModelNamespace } .IntegerScalar` :
253+ {
254+ metaModel . namespace = resolveName ( metaModel . name , table ) ;
255+ metaModel . name = table [ metaModel . name ] . name ;
256+ }
193257 break ;
194258 }
195259 return metaModel ;
@@ -242,11 +306,12 @@ function importFullyQualifiedNames(imp) {
242306 case `${ MetaModelNamespace } .ImportType` :
243307 result . push ( `${ imp . namespace } .${ imp . name } ` ) ;
244308 break ;
245- case `${ MetaModelNamespace } .ImportTypes` : {
246- imp . types . forEach ( type => {
247- result . push ( `${ imp . namespace } .${ type } ` ) ;
248- } ) ;
249- }
309+ case `${ MetaModelNamespace } .ImportTypes` :
310+ {
311+ imp . types . forEach ( ( type ) => {
312+ result . push ( `${ imp . namespace } .${ type } ` ) ;
313+ } ) ;
314+ }
250315 break ;
251316 default :
252317 throw new Error ( `Unrecognized imports ${ imp . $class } ` ) ;
0 commit comments