@@ -55,7 +55,7 @@ export function createNpmFileSystem(
5555
5656 return {
5757 async stat ( uri ) {
58- const path = getCdnPath ( uri )
58+ const path = normalizePath ( getCdnPath ( uri ) )
5959 if ( path === undefined ) {
6060 return
6161 }
@@ -70,14 +70,14 @@ export function createNpmFileSystem(
7070 return await _stat ( path )
7171 } ,
7272 async readFile ( uri ) {
73- const path = getCdnPath ( uri )
73+ const path = normalizePath ( getCdnPath ( uri ) )
7474 if ( path === undefined ) {
7575 return
7676 }
7777 return await _readFile ( path )
7878 } ,
7979 readDirectory ( uri ) {
80- const path = getCdnPath ( uri )
80+ const path = normalizePath ( getCdnPath ( uri ) )
8181 if ( path === undefined ) {
8282 return [ ]
8383 }
@@ -86,6 +86,9 @@ export function createNpmFileSystem(
8686 }
8787
8888 async function _stat ( path : string ) {
89+ if ( hasNodeModulesSegment ( path ) ) {
90+ return
91+ }
8992 if ( statCache . has ( path ) ) {
9093 return {
9194 ...statCache . get ( path ) ,
@@ -142,6 +145,9 @@ export function createNpmFileSystem(
142145 }
143146
144147 async function _readDirectory ( path : string ) : Promise < [ string , FileType ] [ ] > {
148+ if ( hasNodeModulesSegment ( path ) ) {
149+ return [ ]
150+ }
145151 if ( dirCache . has ( path ) ) {
146152 return dirCache . get ( path ) !
147153 }
@@ -182,17 +188,7 @@ export function createNpmFileSystem(
182188 return [ ]
183189 }
184190
185- const result : [ string , FileType ] [ ] = data . files . map ( ( file ) => {
186- const type =
187- file . type === 'directory'
188- ? ( 2 as FileType . Directory )
189- : ( 1 as FileType . File )
190-
191- const fullPath = file . path
192- statCache . set ( fullPath , { type } )
193-
194- return [ _getNameFromPath ( file . path ) , type ]
195- } )
191+ const result = getDirectDirectoryEntries ( path , pkgPath , data . files )
196192
197193 dirCache . set ( path , result )
198194 return result
@@ -201,26 +197,53 @@ export function createNpmFileSystem(
201197 }
202198 }
203199
204- function _getNameFromPath ( path : string ) : string {
205- if ( ! path ) return ''
206-
207- const trimmedPath = path . endsWith ( '/' ) ? path . slice ( 0 , - 1 ) : path
208-
209- const lastSlashIndex = trimmedPath . lastIndexOf ( '/' )
210-
211- if (
212- lastSlashIndex === - 1 ||
213- ( lastSlashIndex === 0 && trimmedPath . length === 1 )
214- ) {
215- return trimmedPath
200+ function getDirectDirectoryEntries (
201+ path : string ,
202+ pkgPath : string ,
203+ files : {
204+ path : string
205+ type : 'file' | 'directory'
206+ size ?: number
207+ } [ ] ,
208+ ) : [ string , FileType ] [ ] {
209+ const entries = new Map < string , FileType > ( )
210+ const prefix = trimSlashes ( pkgPath )
211+
212+ for ( const file of files ) {
213+ const isRootedPath = file . path . startsWith ( '/' )
214+ const filePath = trimSlashes ( file . path )
215+ if ( ! filePath ) continue
216+
217+ const relativePath =
218+ prefix && filePath . startsWith ( `${ prefix } /` )
219+ ? filePath . slice ( prefix . length + 1 )
220+ : prefix && isRootedPath
221+ ? undefined
222+ : filePath
223+
224+ if ( ! relativePath ) continue
225+
226+ const [ name , ...rest ] = relativePath . split ( '/' )
227+ const type =
228+ rest . length > 0 || file . type === 'directory'
229+ ? ( 2 as FileType . Directory )
230+ : ( 1 as FileType . File )
231+
232+ entries . set ( name , type )
233+ statCache . set ( joinPath ( path , name ) , { type } )
216234 }
217235
218- return trimmedPath . slice ( lastSlashIndex + 1 )
236+ return [ ... entries ]
219237 }
220238
221239 async function _readFile ( path : string ) : Promise < string | undefined > {
222240 const [ _modName , pkgName , _version , pkgFilePath ] = resolvePackageName ( path )
223- if ( ! pkgName || ! pkgFilePath || ! ( await isValidPackageName ( pkgName ) ) ) {
241+ if (
242+ ! pkgName ||
243+ ! pkgFilePath ||
244+ hasNodeModulesSegment ( pkgFilePath ) ||
245+ ! ( await isValidPackageName ( pkgName ) )
246+ ) {
224247 return
225248 }
226249
@@ -245,9 +268,25 @@ export function createNpmFileSystem(
245268 return await fetchResults . get ( path ) !
246269 }
247270
271+ function hasNodeModulesSegment ( path : string ) {
272+ return path . split ( '/' ) . includes ( 'node_modules' )
273+ }
274+
275+ function joinPath ( base : string , path : string ) {
276+ return [ trimSlashes ( base ) , trimSlashes ( path ) ] . filter ( Boolean ) . join ( '/' )
277+ }
278+
279+ function normalizePath ( path : string | undefined ) {
280+ return path === undefined ? undefined : trimSlashes ( path )
281+ }
282+
283+ function trimSlashes ( path : string ) {
284+ return path . replace ( / ^ \/ + | \/ + $ / g, '' )
285+ }
286+
248287 async function isValidPackageName ( pkgName : string ) {
249- // ignore @aaa /node_modules
250- if ( pkgName . endsWith ( '/node_modules' ) ) {
288+ // ignore nested node_modules probes like /node_modules /node_modules
289+ if ( pkgName === 'node_modules' || pkgName . endsWith ( '/node_modules' ) ) {
251290 return false
252291 }
253292 // hard code to skip known invalid package
0 commit comments