1+ const CACHE_VERSION = 2
2+
13// Maximum file size to fetch and highlight (500KB)
24const MAX_FILE_SIZE = 500 * 1024
35
6+ // Languages that benefit from import linking
7+ const IMPORT_LANGUAGES = new Set ( [
8+ 'javascript' , 'typescript' , 'jsx' , 'tsx' ,
9+ 'vue' , 'svelte' , 'astro' ,
10+ ] )
11+
12+ interface PackageJson {
13+ dependencies ?: Record < string , string >
14+ devDependencies ?: Record < string , string >
15+ peerDependencies ?: Record < string , string >
16+ optionalDependencies ?: Record < string , string >
17+ }
18+
19+ /**
20+ * Fetch package.json from jsDelivr to get dependency info
21+ */
22+ async function fetchPackageJson ( packageName : string , version : string ) : Promise < PackageJson | null > {
23+ try {
24+ const url = `https://cdn.jsdelivr.net/npm/${ packageName } @${ version } /package.json`
25+ const response = await fetch ( url )
26+ if ( ! response . ok ) return null
27+ return await response . json ( ) as PackageJson
28+ }
29+ catch {
30+ return null
31+ }
32+ }
33+
434/**
535 * Fetch file content from jsDelivr CDN.
636 */
@@ -73,7 +103,45 @@ export default defineCachedEventHandler(
73103 try {
74104 const content = await fetchFileContent ( packageName , version , filePath )
75105 const language = getLanguageFromPath ( filePath )
76- const html = await highlightCode ( content , language )
106+
107+ // For JS/TS files, resolve dependency versions and relative imports for linking
108+ let dependencies : Record < string , { version : string } > | undefined
109+ let resolveRelative : ( ( specifier : string ) => string | null ) | undefined
110+
111+ if ( IMPORT_LANGUAGES . has ( language ) ) {
112+ // Fetch package.json and file tree in parallel
113+ const [ pkgJson , fileTreeResponse ] = await Promise . all ( [
114+ fetchPackageJson ( packageName , version ) ,
115+ getPackageFileTree ( packageName , version ) . catch ( ( ) => null ) ,
116+ ] )
117+
118+ // Resolve npm dependency versions
119+ if ( pkgJson ) {
120+ // Merge all dependency types
121+ const allDeps : Record < string , string > = {
122+ ...pkgJson . dependencies ,
123+ ...pkgJson . peerDependencies ,
124+ ...pkgJson . optionalDependencies ,
125+ // Note: excluding devDependencies as they're less likely to be imported in dist files
126+ }
127+
128+ if ( Object . keys ( allDeps ) . length > 0 ) {
129+ const resolved : Record < string , string > = await resolveDependencyVersions ( allDeps )
130+ dependencies = { }
131+ for ( const [ name , ver ] of Object . entries ( resolved ) ) {
132+ dependencies [ name ] = { version : ver }
133+ }
134+ }
135+ }
136+
137+ // Create resolver for relative imports
138+ if ( fileTreeResponse ) {
139+ const files = flattenFileTree ( fileTreeResponse . tree )
140+ resolveRelative = createImportResolver ( files , filePath , packageName , version )
141+ }
142+ }
143+
144+ const html = await highlightCode ( content , language , { dependencies, resolveRelative } )
77145
78146 return {
79147 package : packageName ,
@@ -96,7 +164,7 @@ export default defineCachedEventHandler(
96164 maxAge : 60 * 60 , // Cache for 1 hour (files don't change for a given version)
97165 getKey : ( event ) => {
98166 const pkg = getRouterParam ( event , 'pkg' ) ?? ''
99- return `file:${ pkg } `
167+ return `file:v ${ CACHE_VERSION } : ${ pkg } `
100168 } ,
101169 } ,
102170)
0 commit comments