@@ -28,6 +28,7 @@ const FIXTURE_PATHS = {
2828 esmTypes : 'esm-sh:types' ,
2929 githubContributors : 'github:contributors.json' ,
3030 githubContributorsStats : 'github:contributors-stats.json' ,
31+ jsdelivr : 'jsdelivr' ,
3132} as const
3233
3334type FixtureType = keyof typeof FIXTURE_PATHS
@@ -101,12 +102,8 @@ function parseScopedPackageWithVersion(input: string): { name: string; version?:
101102}
102103
103104function getMockForUrl ( url : string ) : MockResult | null {
104- let urlObj : URL
105- try {
106- urlObj = new URL ( url )
107- } catch {
108- return null
109- }
105+ const urlObj = URL . parse ( url )
106+ if ( ! urlObj ) return null
110107
111108 const { host, pathname, searchParams } = urlObj
112109
@@ -140,33 +137,6 @@ function getMockForUrl(url: string): MockResult | null {
140137 }
141138 }
142139
143- // jsdelivr CDN - return 404 for README files, etc.
144- if ( host === 'cdn.jsdelivr.net' ) {
145- // Return null data which will cause a 404 - README files are optional
146- return { data : null }
147- }
148-
149- // jsdelivr data API - return mock file listing
150- if ( host === 'data.jsdelivr.com' ) {
151- const packageMatch = decodeURIComponent ( pathname ) . match ( / ^ \/ v 1 \/ p a c k a g e s \/ n p m \/ ( .+ ) $ / )
152- if ( packageMatch ?. [ 1 ] ) {
153- const pkgWithVersion = packageMatch [ 1 ]
154- const parsed = parseScopedPackageWithVersion ( pkgWithVersion )
155- return {
156- data : {
157- type : 'npm' ,
158- name : parsed . name ,
159- version : parsed . version || 'latest' ,
160- files : [
161- { name : 'package.json' , hash : 'abc123' , size : 1000 } ,
162- { name : 'index.js' , hash : 'def456' , size : 500 } ,
163- { name : 'README.md' , hash : 'ghi789' , size : 2000 } ,
164- ] ,
165- } ,
166- }
167- }
168- }
169-
170140 // Gravatar API - return 404 (avatars not needed in tests)
171141 if ( host === 'www.gravatar.com' ) {
172142 return { data : null }
@@ -362,12 +332,8 @@ async function handleFastNpmMeta(
362332 url : string ,
363333 storage : ReturnType < typeof useStorage > ,
364334) : Promise < MockResult | null > {
365- let urlObj : URL
366- try {
367- urlObj = new URL ( url )
368- } catch {
369- return null
370- }
335+ const urlObj = URL . parse ( url )
336+ if ( ! urlObj ) return null
371337
372338 const { host, pathname, searchParams } = urlObj
373339
@@ -407,12 +373,8 @@ async function handleGitHubApi(
407373 url : string ,
408374 storage : ReturnType < typeof useStorage > ,
409375) : Promise < MockResult | null > {
410- let urlObj : URL
411- try {
412- urlObj = new URL ( url )
413- } catch {
414- return null
415- }
376+ const urlObj = URL . parse ( url )
377+ if ( ! urlObj ) return null
416378
417379 const { host, pathname } = urlObj
418380
@@ -463,12 +425,8 @@ interface FixtureMatchWithVersion extends FixtureMatch {
463425}
464426
465427function matchUrlToFixture ( url : string ) : FixtureMatchWithVersion | null {
466- let urlObj : URL
467- try {
468- urlObj = new URL ( url )
469- } catch {
470- return null
471- }
428+ const urlObj = URL . parse ( url )
429+ if ( ! urlObj ) return null
472430
473431 const { host, pathname, searchParams } = urlObj
474432
@@ -548,6 +506,42 @@ function logUnmockedRequest(type: string, detail: string, url: string): void {
548506 )
549507}
550508
509+ async function handleJsdelivrDataApi (
510+ url : string ,
511+ storage : ReturnType < typeof useStorage > ,
512+ ) : Promise < MockResult | null > {
513+ const urlObj = URL . parse ( url )
514+ if ( ! urlObj ) return null
515+
516+ if ( urlObj . host !== 'data.jsdelivr.com' ) return null
517+
518+ const packageMatch = decodeURIComponent ( urlObj . pathname ) . match ( / ^ \/ v 1 \/ p a c k a g e s \/ n p m \/ ( .+ ) $ / )
519+ if ( ! packageMatch ?. [ 1 ] ) return null
520+
521+ const parsed = parseScopedPackageWithVersion ( packageMatch [ 1 ] )
522+
523+ // Try per-package fixture first
524+ const fixturePath = getFixturePath ( 'jsdelivr' , parsed . name )
525+ const fixture = await storage . getItem < unknown > ( fixturePath )
526+ if ( fixture ) {
527+ return { data : fixture }
528+ }
529+
530+ // Fall back to generic stub (no declaration files)
531+ return {
532+ data : {
533+ type : 'npm' ,
534+ name : parsed . name ,
535+ version : parsed . version || 'latest' ,
536+ files : [
537+ { name : 'package.json' , hash : 'abc123' , size : 1000 } ,
538+ { name : 'index.js' , hash : 'def456' , size : 500 } ,
539+ { name : 'README.md' , hash : 'ghi789' , size : 2000 } ,
540+ ] ,
541+ } ,
542+ }
543+ }
544+
551545/**
552546 * Shared fixture-backed fetch implementation.
553547 * This is used by both cachedFetch and the global $fetch override.
@@ -570,6 +564,12 @@ async function fetchFromFixtures<T>(
570564 return { data : fastNpmMetaResult . data as T , isStale : false , cachedAt : Date . now ( ) }
571565 }
572566
567+ const jsdelivrResult = await handleJsdelivrDataApi ( url , storage )
568+ if ( jsdelivrResult ) {
569+ if ( VERBOSE ) process . stdout . write ( `[test-fixtures] jsDelivr Data API: ${ url } \n` )
570+ return { data : jsdelivrResult . data as T , isStale : false , cachedAt : Date . now ( ) }
571+ }
572+
573573 // Check for GitHub API
574574 const githubResult = await handleGitHubApi ( url , storage )
575575 if ( githubResult ) {
0 commit comments