@@ -607,5 +607,88 @@ describe("extract", () => {
607607 const readContent = await fs . readFile ( filePath , "utf-8" ) ;
608608 expect ( readContent ) . toBe ( content ) ;
609609 } ) ;
610+
611+ it ( "map filters out empty directory names" , async ( ) => {
612+ const sourceDir = path . join ( tmpDir , "source" ) ;
613+ await fs . mkdir ( path . join ( sourceDir , "dir" ) , { recursive : true } ) ;
614+
615+ const packStream = packTar ( sourceDir ) ;
616+ const packData : Buffer [ ] = [ ] ;
617+ for await ( const chunk of packStream ) {
618+ packData . push ( Buffer . from ( chunk ) ) ;
619+ }
620+
621+ const extractDir = path . join ( tmpDir , "extract" ) ;
622+ const readStream = Readable . from ( [ Buffer . concat ( packData ) ] ) ;
623+
624+ const unpackStream = unpackTar ( extractDir , {
625+ map ( entry ) {
626+ if ( entry . name === "dir/" ) entry . name = "" ; // Creates empty name
627+ return entry ;
628+ } ,
629+ } ) ;
630+
631+ // Should complete without hanging (empty entries are filtered out)
632+ await pipeline ( readStream , unpackStream ) ;
633+
634+ // Should have no files since the only directory entry was filtered out
635+ try {
636+ const files = await fs . readdir ( extractDir ) ;
637+ expect ( files ) . toHaveLength ( 0 ) ;
638+ } catch ( error ) {
639+ // If directory doesn't exist because no entries were extracted, that's fine
640+ expect ( ( error as NodeJS . ErrnoException ) . code ) . toBe ( "ENOENT" ) ;
641+ }
642+ } , 2000 ) ;
643+
644+ it ( "handles mapping with subdir extraction" , async ( ) => {
645+ // Create a test archive that mimics GitHub tarball structure
646+ const sourceDir = path . join ( tmpDir , "source" ) ;
647+ const rootDir = path . join ( sourceDir , "withastro-starlight-abc123" ) ;
648+ const examplesDir = path . join ( rootDir , "examples" ) ;
649+ const basicsDir = path . join ( examplesDir , "basics" ) ;
650+ const srcDir = path . join ( basicsDir , "src" ) ;
651+ const pagesDir = path . join ( srcDir , "pages" ) ;
652+
653+ await fs . mkdir ( pagesDir , { recursive : true } ) ;
654+ await fs . writeFile (
655+ path . join ( basicsDir , "package.json" ) ,
656+ '{"name": "@example/basics", "type": "module"}' ,
657+ ) ;
658+ await fs . writeFile ( path . join ( pagesDir , "index.mdx" ) , "# Welcome" ) ;
659+
660+ const packStream = packTar ( sourceDir ) ;
661+ const packData : Buffer [ ] = [ ] ;
662+ for await ( const chunk of packStream ) {
663+ packData . push ( Buffer . from ( chunk ) ) ;
664+ }
665+
666+ // Reproduce exact giget-core extraction logic
667+ const extractDir = path . join ( tmpDir , "starlight-unpack" ) ;
668+ const readStream = Readable . from ( [ Buffer . concat ( packData ) ] ) ;
669+ const subdir = "examples/basics/" ;
670+
671+ const unpackStream = unpackTar ( extractDir , {
672+ filter ( entry ) {
673+ const path = entry . name . split ( "/" ) . slice ( 1 ) . join ( "/" ) ;
674+ if ( path === "" ) return false ;
675+ return path . startsWith ( subdir ) ;
676+ } ,
677+ map ( entry ) {
678+ let path = entry . name . split ( "/" ) . slice ( 1 ) . join ( "/" ) ;
679+ if ( subdir ) path = path . slice ( subdir . length ) ;
680+ entry . name = path ;
681+ return entry ;
682+ } ,
683+ } ) ;
684+
685+ // This should now work without hanging
686+ await pipeline ( readStream , unpackStream ) ;
687+
688+ // Verify extraction worked correctly
689+ const files = await fs . readdir ( extractDir , { recursive : true } ) ;
690+ expect ( files ) . toContain ( "package.json" ) ;
691+ expect ( files . some ( ( f ) => f . includes ( "pages" ) ) ) . toBe ( true ) ;
692+ } ) ;
610693 } ) ;
611694} ) ;
0 commit comments