@@ -97,9 +97,57 @@ async function copyStream(
9797 } ) ;
9898}
9999
100+ /**
101+ * Unzips a single file from a zip archive.
102+ *
103+ * @param zipFile
104+ * @param entry
105+ * @param rootDestinationPath
106+ */
107+ async function unzipFile (
108+ zipFile : ZipFile ,
109+ entry : ZipEntry ,
110+ rootDestinationPath : string ,
111+ ) : Promise < void > {
112+ const path = join ( rootDestinationPath , entry . fileName ) ;
113+
114+ if ( / \/ $ / . test ( entry . fileName ) ) {
115+ // Directory file names end with '/'
116+
117+ await ensureDir ( path ) ;
118+ } else {
119+ // Ensure the directory exists
120+ await ensureDir ( dirname ( path ) ) ;
121+
122+ const readable = await openZipReadStream ( zipFile , entry ) ;
123+
124+ let mode : number | undefined = entry . externalFileAttributes >>> 16 ;
125+ if ( mode <= 0 ) {
126+ mode = undefined ;
127+ }
128+
129+ const writeStream = createWriteStream ( path , {
130+ autoClose : true ,
131+ mode,
132+ } ) ;
133+
134+ await copyStream ( readable , writeStream ) ;
135+ }
136+ }
137+
138+ /**
139+ * Unzips all files from a zip archive. Please use
140+ * `unzipToDirectoryConcurrently` or `unzipToDirectorySequentially` instead
141+ * of this function.
142+ *
143+ * @param archivePath
144+ * @param destinationPath
145+ * @param taskRunner A function that runs the tasks (either sequentially or concurrently).
146+ */
100147export async function unzipToDirectory (
101148 archivePath : string ,
102149 destinationPath : string ,
150+ taskRunner : ( tasks : Array < ( ) => Promise < void > > ) => Promise < void > ,
103151) : Promise < void > {
104152 const zipFile = await openZip ( archivePath , {
105153 autoClose : false ,
@@ -110,33 +158,29 @@ export async function unzipToDirectory(
110158 try {
111159 const entries = await readZipEntries ( zipFile ) ;
112160
113- for ( const entry of entries ) {
114- const path = join ( destinationPath , entry . fileName ) ;
115-
116- if ( / \/ $ / . test ( entry . fileName ) ) {
117- // Directory file names end with '/'
118-
119- await ensureDir ( path ) ;
120- } else {
121- // Ensure the directory exists
122- await ensureDir ( dirname ( path ) ) ;
123-
124- const readable = await openZipReadStream ( zipFile , entry ) ;
125-
126- let mode : number | undefined = entry . externalFileAttributes >>> 16 ;
127- if ( mode <= 0 ) {
128- mode = undefined ;
129- }
130-
131- const writeStream = createWriteStream ( path , {
132- autoClose : true ,
133- mode,
134- } ) ;
135-
136- await copyStream ( readable , writeStream ) ;
137- }
138- }
161+ await taskRunner (
162+ entries . map ( ( entry ) => ( ) => unzipFile ( zipFile , entry , destinationPath ) ) ,
163+ ) ;
139164 } finally {
140165 zipFile . close ( ) ;
141166 }
142167}
168+
169+ /**
170+ * Sequentially unzips all files from a zip archive. Please use
171+ * `unzipToDirectoryConcurrently` if you can. This function is only
172+ * provided because Jest cannot import `p-queue`.
173+ *
174+ * @param archivePath
175+ * @param destinationPath
176+ */
177+ export async function unzipToDirectorySequentially (
178+ archivePath : string ,
179+ destinationPath : string ,
180+ ) : Promise < void > {
181+ return unzipToDirectory ( archivePath , destinationPath , async ( tasks ) => {
182+ for ( const task of tasks ) {
183+ await task ( ) ;
184+ }
185+ } ) ;
186+ }
0 commit comments