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 range-based versioning (supports x-ranges like 1.x, 1.1.x)
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 version 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/**
0 commit comments