@@ -682,11 +682,8 @@ describe("extract", () => {
682682 const createdPath = path . join ( destDir , "my-file.txt" ) ;
683683
684684 const stats = await fs . stat ( createdPath ) ;
685- expect ( stats . isFile ( ) ) . toBe ( true ) ;
686- expect ( stats . isDirectory ( ) ) . toBe ( false ) ;
687-
688- const content = await fs . readFile ( createdPath , "utf-8" ) ;
689- expect ( content ) . toBe ( "content" ) ;
685+ expect ( stats . isDirectory ( ) ) . toBe ( true ) ;
686+ expect ( stats . isFile ( ) ) . toBe ( false ) ;
690687 } ) ;
691688
692689 it ( "should handle multiple trailing slashes on files" , async ( ) => {
@@ -709,13 +706,10 @@ describe("extract", () => {
709706
710707 await pipeline ( Readable . from ( [ tarBuffer ] ) , unpackStream ) ;
711708
712- // Should create file without trailing slashes
709+ // Should create directory without trailing slashes
713710 const filePath = path . join ( destDir , "document.pdf" ) ;
714711 const stats = await fs . stat ( filePath ) ;
715- expect ( stats . isFile ( ) ) . toBe ( true ) ;
716-
717- const content = await fs . readFile ( filePath , "utf-8" ) ;
718- expect ( content ) . toBe ( "PDF content\n" ) ;
712+ expect ( stats . isDirectory ( ) ) . toBe ( true ) ;
719713 } ) ;
720714
721715 it ( "should handle trailing slashes on directories (which is valid)" , async ( ) => {
@@ -764,13 +758,108 @@ describe("extract", () => {
764758
765759 await pipeline ( Readable . from ( [ tarBuffer ] ) , unpackStream ) ;
766760
767- // Should create the nested file structure correctly
761+ // Should create the nested directory structure correctly
768762 const filePath = path . join ( destDir , "nested" , "path" , "file.txt" ) ;
769763 const stats = await fs . stat ( filePath ) ;
770- expect ( stats . isFile ( ) ) . toBe ( true ) ;
764+ expect ( stats . isDirectory ( ) ) . toBe ( true ) ;
765+ } ) ;
766+
767+ it ( "converts to directory when PAX header overrides name with trailing slash" , async ( ) => {
768+ const destDir = path . join ( tmpDir , "pax-override" ) ;
769+ await fs . mkdir ( destDir , { recursive : true } ) ;
770+
771+ const entries = [
772+ {
773+ header : {
774+ name : "original-name" , // No slash in standard header
775+ type : "file" as const ,
776+ size : 0 ,
777+ pax : {
778+ path : "overridden-name/" , // Slash in PAX override
779+ } ,
780+ } ,
781+ } ,
782+ ] ;
783+
784+ const tarBuffer = await packTarWeb ( entries ) ;
785+ const unpackStream = unpackTar ( destDir ) ;
786+ await pipeline ( Readable . from ( [ tarBuffer ] ) , unpackStream ) ;
787+
788+ const createdPath = path . join ( destDir , "overridden-name" ) ;
789+ const stats = await fs . stat ( createdPath ) ;
790+ expect ( stats . isDirectory ( ) ) . toBe ( true ) ;
791+ } ) ;
792+
793+ it ( "does NOT convert symlinks to directories even with trailing slash" , async ( ) => {
794+ const destDir = path . join ( tmpDir , "symlink-slash" ) ;
795+ await fs . mkdir ( destDir , { recursive : true } ) ;
796+
797+ // Create a target for the symlink
798+ await fs . writeFile ( path . join ( destDir , "target" ) , "target content" ) ;
799+
800+ const entries = [
801+ {
802+ header : {
803+ name : "mylink/" , // Trailing slash
804+ type : "symlink" as const , // But type is SYMLINK
805+ linkname : "target" ,
806+ size : 0 ,
807+ } ,
808+ } ,
809+ ] ;
810+
811+ const tarBuffer = await packTarWeb ( entries ) ;
812+ const unpackStream = unpackTar ( destDir ) ;
813+ await pipeline ( Readable . from ( [ tarBuffer ] ) , unpackStream ) ;
814+
815+ const createdPath = path . join ( destDir , "mylink" ) ;
816+ const stats = await fs . lstat ( createdPath ) ;
817+
818+ expect ( stats . isSymbolicLink ( ) ) . toBe ( true ) ;
819+ expect ( stats . isDirectory ( ) ) . toBe ( false ) ;
820+ } ) ;
821+
822+ it ( "discards body content when a FILE is converted to a DIRECTORY" , async ( ) => {
823+ const destDir = path . join ( tmpDir , "content-discard" ) ;
824+ await fs . mkdir ( destDir , { recursive : true } ) ;
825+
826+ const bodyContent = "this content should be discarded" ;
827+ const entries = [
828+ {
829+ header : {
830+ name : "weird-dir/" ,
831+ type : "file" as const ,
832+ size : bodyContent . length , // Header claims it has size
833+ } ,
834+ body : bodyContent ,
835+ } ,
836+ {
837+ header : {
838+ name : "next-file.txt" ,
839+ type : "file" as const ,
840+ size : 5 ,
841+ } ,
842+ body : "hello" ,
843+ } ,
844+ ] ;
845+
846+ const tarBuffer = await packTarWeb ( entries ) ;
847+ const unpackStream = unpackTar ( destDir ) ;
848+ await pipeline ( Readable . from ( [ tarBuffer ] ) , unpackStream ) ;
849+
850+ // Check weird-dir is a directory
851+ const dirPath = path . join ( destDir , "weird-dir" ) ;
852+ const dirStats = await fs . stat ( dirPath ) ;
853+ expect ( dirStats . isDirectory ( ) ) . toBe ( true ) ;
854+
855+ // Verify no file was created inside (content was discarded, not treated as file-in-dir)
856+ const dirContents = await fs . readdir ( dirPath ) ;
857+ expect ( dirContents ) . toHaveLength ( 0 ) ;
771858
772- const readContent = await fs . readFile ( filePath , "utf-8" ) ;
773- expect ( readContent ) . toBe ( content ) ;
859+ // Verify stream continued correctly to next file
860+ const nextFilePath = path . join ( destDir , "next-file.txt" ) ;
861+ const nextFileContent = await fs . readFile ( nextFilePath , "utf-8" ) ;
862+ expect ( nextFileContent ) . toBe ( "hello" ) ;
774863 } ) ;
775864
776865 it ( "map filters out empty directory names" , async ( ) => {
0 commit comments