@@ -5,8 +5,6 @@ import { resource } from "lively.resources";
55import { parseQuery } from "lively.resources" ;
66import { arr , obj } from "lively.lang" ;
77const Generator = System . get ( '@jspm_generator' ) . default ;
8- const semver = System . _nodeRequire ( 'semver' ) ;
9- let localDependerIndex ;
108
119// Deps that cannot be resolved via jspm.io CDN:
1210// - native binary packages (platform-specific compiled addons)
@@ -35,89 +33,6 @@ function extractFailingPackage (errMsg) {
3533 return null ;
3634}
3735
38- function extractImportingPackageScope ( errMsg ) {
39- const importerMatch = errMsg . match ( / i m p o r t e d f r o m ( h t t p s : \/ \/ g a \. j s p m \. i o \/ n p m : (?: @ [ ^ / ] + \/ ) ? [ ^ @ \s / ] + @ [ ^ / ] + \/ ) / ) ;
40- return importerMatch ? importerMatch [ 1 ] : null ;
41- }
42-
43- function buildPackageUrl ( name , version ) {
44- return `https://ga.jspm.io/npm:${ name } @${ version } /` ;
45- }
46-
47- function toCachedScopeUrl ( scopeUrl ) {
48- return scopeUrl . replace ( / ^ h t t p s : \/ \/ / , 'esm://' ) ;
49- }
50-
51- function toGeneratorScopeUrl ( scopeUrl ) {
52- return scopeUrl . replace ( / ^ e s m : \/ \/ / , 'https://' ) ;
53- }
54-
55- function indexPackageDependers ( packageJson , index ) {
56- if ( ! packageJson ?. name || ! packageJson ?. version ) return ;
57- const deps = {
58- ...( packageJson . dependencies || { } ) ,
59- ...( packageJson . peerDependencies || { } ) ,
60- ...( packageJson . optionalDependencies || { } )
61- } ;
62- for ( const [ depName , depRange ] of Object . entries ( deps ) ) {
63- if ( typeof depRange !== 'string' ) continue ;
64- ( index [ depName ] ||= [ ] ) . push ( {
65- scopeUrl : buildPackageUrl ( packageJson . name , packageJson . version ) ,
66- range : depRange
67- } ) ;
68- }
69- }
70-
71- function getLocalDependerIndex ( ) {
72- if ( localDependerIndex ) return localDependerIndex ;
73-
74- const index = { } ;
75- const packageRoot = join ( process . cwd ( ) , 'lively.next-node_modules' ) ;
76- if ( ! fs . existsSync ( packageRoot ) ) {
77- localDependerIndex = index ;
78- return index ;
79- }
80-
81- const stack = [ packageRoot ] ;
82- while ( stack . length ) {
83- const dir = stack . pop ( ) ;
84- let entries ;
85- try {
86- entries = fs . readdirSync ( dir , { withFileTypes : true } ) ;
87- } catch {
88- continue ;
89- }
90- for ( const entry of entries ) {
91- const fullPath = join ( dir , entry . name ) ;
92- if ( entry . isDirectory ( ) ) {
93- stack . push ( fullPath ) ;
94- continue ;
95- }
96- if ( ! entry . isFile ( ) || entry . name !== 'package.json' ) continue ;
97- try {
98- indexPackageDependers ( JSON . parse ( fs . readFileSync ( fullPath , 'utf8' ) ) , index ) ;
99- } catch { }
100- }
101- }
102-
103- localDependerIndex = index ;
104- return index ;
105- }
106-
107- function findScopedPinTargets ( pkgName , goodVersion , importerScope = null ) {
108- const scopedPins = new Set ( ) ;
109- if ( importerScope ) scopedPins . add ( importerScope ) ;
110- const dependers = getLocalDependerIndex ( ) [ pkgName ] || [ ] ;
111- for ( const { scopeUrl, range } of dependers ) {
112- try {
113- if ( semver . satisfies ( goodVersion , range , { includePrerelease : true } ) ) {
114- scopedPins . add ( scopeUrl ) ;
115- }
116- } catch { }
117- }
118- return [ ...scopedPins ] ;
119- }
120-
12136/**
12237 * Given a package name and failing version, find a nearby version that
12338 * actually exists on the jspm.io CDN by walking backwards from the failing
@@ -151,26 +66,16 @@ async function findAvailableCDNVersion (name, failingVersion) {
15166 return null ;
15267}
15368
154- function createGenerator ( inputMap , resolutions , scopedResolutions = { } ) {
155- const generator = new Generator ( {
156- env : [ "browser" ] ,
69+ function createGenerator ( inputMap , resolutions ) {
70+ return new Generator ( {
71+ env : [ "browser" , "module" , "import" ] ,
15772 defaultProvider : 'jspm.io' ,
15873 inputMap,
15974 ...( Object . keys ( resolutions ) . length ? { resolutions } : { } )
16075 } ) ;
161- const installs = generator . traceMap . installer . installs ;
162- installs . secondary ||= { } ;
163- installs . flattened ||= { } ;
164- for ( const [ scopeUrl , pins ] of Object . entries ( scopedResolutions ) ) {
165- const scope = installs . secondary [ toGeneratorScopeUrl ( scopeUrl ) ] ||= { } ;
166- for ( const [ pkgName , version ] of Object . entries ( pins || { } ) ) {
167- scope [ pkgName ] = { installUrl : buildPackageUrl ( pkgName , version ) } ;
168- }
169- }
170- return generator ;
17176}
17277
173- async function installDeps ( generator , deps , failed , resolutions , inputMap , scopedResolutions ) {
78+ async function installDeps ( generator , deps , failed , resolutions , inputMap ) {
17479 const depNames = deps . map ( ( [ name ] ) => name ) ;
17580 let needsRestart = false ;
17681
@@ -185,29 +90,12 @@ async function installDeps (generator, deps, failed, resolutions, inputMap, scop
18590 } catch ( firstErr ) {
18691 const errMsg = firstErr . message || String ( firstErr ) ;
18792 const failingPkg = extractFailingPackage ( errMsg ) ;
188- const importingPkgScope = extractImportingPackageScope ( errMsg ) ;
189- const hasGlobalPin = ! ! resolutions [ failingPkg ?. name ] ;
190- const hasPinnedImporterScope = ! ! (
191- failingPkg &&
192- importingPkgScope &&
193- scopedResolutions [ importingPkgScope ] ?. [ failingPkg . name ]
194- ) ;
195- if ( failingPkg && ! hasGlobalPin && ! hasPinnedImporterScope ) {
93+ if ( failingPkg && ! resolutions [ failingPkg . name ] ) {
19694 console . warn ( `\x1b[33m [!] Import map: ${ depSpec } failed — transitive dep ${ failingPkg . name } @${ failingPkg . version } not on CDN, searching for available version...\x1b[0m` ) ;
19795 const goodVersion = await findAvailableCDNVersion ( failingPkg . name , failingPkg . version ) ;
19896 if ( goodVersion ) {
199- const scopedPins = findScopedPinTargets ( failingPkg . name , goodVersion , importingPkgScope )
200- . map ( toCachedScopeUrl )
201- . filter ( scopeUrl => scopedResolutions [ scopeUrl ] ?. [ failingPkg . name ] !== goodVersion ) ;
202- if ( scopedPins . length ) {
203- for ( const scopeUrl of scopedPins ) {
204- ( scopedResolutions [ scopeUrl ] ||= { } ) [ failingPkg . name ] = goodVersion ;
205- }
206- console . log ( `\x1b[32m [✓] Found ${ failingPkg . name } @${ goodVersion } on CDN, pinning via scoped locks for ${ scopedPins . length } requester(s)\x1b[0m` ) ;
207- } else {
208- console . log ( `\x1b[32m [✓] Found ${ failingPkg . name } @${ goodVersion } on CDN, pinning via global resolutions\x1b[0m` ) ;
209- resolutions [ failingPkg . name ] = goodVersion ;
210- }
97+ console . log ( `\x1b[32m [✓] Found ${ failingPkg . name } @${ goodVersion } on CDN, pinning via resolutions\x1b[0m` ) ;
98+ resolutions [ failingPkg . name ] = goodVersion ;
21199 needsRestart = true ;
212100 continue ; // don't mark as failed — will be retried in second pass
213101 } else {
@@ -231,9 +119,8 @@ async function installDeps (generator, deps, failed, resolutions, inputMap, scop
231119 // If we discovered new resolution pins, recreate the generator and
232120 // redo the entire install so all deps benefit from the pins.
233121 if ( needsRestart ) {
234- const scopedPinCount = Object . values ( scopedResolutions ) . reduce ( ( sum , pins ) => sum + Object . keys ( pins || { } ) . length , 0 ) ;
235- console . log ( `\x1b[36m [↻] Restarting import map resolution with ${ Object . keys ( resolutions ) . length } global and ${ scopedPinCount } scoped pinned resolution(s)...\x1b[0m` ) ;
236- generator = createGenerator ( inputMap , resolutions , scopedResolutions ) ;
122+ console . log ( `\x1b[36m [↻] Restarting import map resolution with ${ Object . keys ( resolutions ) . length } pinned resolution(s)...\x1b[0m` ) ;
123+ generator = createGenerator ( inputMap , resolutions ) ;
237124 for ( const key of Object . keys ( failed ) ) delete failed [ key ] ;
238125 for ( let dep of deps ) {
239126 if ( dep [ 0 ] == 'tar-fs' || isUnresolvableOnCDN ( dep ) || ! ! generator . map . imports [ dep [ 0 ] ] ) continue ;
@@ -267,21 +154,18 @@ export async function generateImportMap (packageName) {
267154 inputMap = JSON . parse ( ( await cachedImportMap . read ( ) ) . replace ( / e s m : \/ \/ / g, 'https://' ) ) ; // replace esm to make generator install again
268155 }
269156 const resolutions = { } ;
270- const scopedResolutions = Object . assign ( { } , inputMap ?. _scopedResolutions || { } ) ;
271- let generator = createGenerator ( inputMap , resolutions , scopedResolutions ) ;
157+ let generator = createGenerator ( inputMap , resolutions ) ;
272158 const failed = inputMap ?. _failed || { } ;
273159 generator = await installDeps (
274160 generator ,
275161 Object . entries ( pkg . config . dependencies || { } ) . filter ( ( [ dep ] ) => ! dep . match ( / l i v e l y ( \. | - ) / ) ) ,
276162 failed ,
277163 resolutions ,
278- inputMap ,
279- scopedResolutions
164+ inputMap
280165 ) ;
281166 const importMap = JSON . parse ( JSON . stringify ( generator . getMap ( ) ) . replace ( / h t t p s : \/ \/ / g, 'esm://' ) )
282167 if ( ! obj . isEmpty ( failed ) ) importMap . _failed = failed ;
283168 if ( ! obj . isEmpty ( resolutions ) ) importMap . _resolutions = resolutions ;
284- if ( ! obj . isEmpty ( scopedResolutions ) ) importMap . _scopedResolutions = scopedResolutions ;
285169 if ( ! obj . isEmpty ( importMap ) ) await cachedImportMap . writeJson ( importMap ) ;
286170 else if ( inputMap ) { await cachedImportMap . remove ( ) }
287171 return importMap ;
0 commit comments