2
2
import * as path from 'path' ;
3
3
import * as fs from 'fs-extra' ;
4
4
import ZipArchive from 'jszip' ;
5
- import { directoryName , fileName as baseName , groupBy } from '@vlocode/util' ;
5
+ import { groupBy } from '@vlocode/util' ;
6
6
import { FileProperties , RetrieveResult } from '../connection' ;
7
7
import { PackageManifest } from './maifest' ;
8
8
import { SalesforcePackageComponentFile } from './package' ;
9
+ import { MetadataExpander } from './metadataExpander' ;
9
10
10
11
/**
11
12
* Extends typings on the JSZipObject with internal _data object
@@ -93,12 +94,6 @@ export class RetrieveResultFile implements SalesforceRetrievedComponentFile {
93
94
*/
94
95
public readonly archivePath : string ;
95
96
96
- /**
97
- * If this file has an associated metadata XML file this is path to that file.
98
- * Undefined if no meta file exists that matches the source file.
99
- */
100
- public readonly metaFilePath ?: string ;
101
-
102
97
/**
103
98
* Uncompressed size of the file in bytes.
104
99
*/
@@ -120,6 +115,32 @@ export class RetrieveResultFile implements SalesforceRetrievedComponentFile {
120
115
return this . file ?. _data ?. crc32
121
116
}
122
117
118
+ /**
119
+ * Gets the base name of the archive file path, excluding any directory components.
120
+ *
121
+ * @returns The file name portion of the archive path.
122
+ */
123
+ public get fileName ( ) {
124
+ return path . basename ( this . archivePath ) ;
125
+ }
126
+
127
+ /**
128
+ * Gets the relative path of the archive file.
129
+ *
130
+ * @returns The directory name of the archive path specified by `this.archivePath`.
131
+ */
132
+ public get folderName ( ) {
133
+ return path . dirname ( this . archivePath ) ;
134
+ }
135
+
136
+ /**
137
+ * Gets the full path of the file in the zip archive.
138
+ * @see {@link archivePath }
139
+ */
140
+ public get fullPath ( ) {
141
+ return this . archivePath
142
+ }
143
+
123
144
constructor (
124
145
properties : FileProperties ,
125
146
private readonly file ?: ZipArchive . JSZipObject )
@@ -131,25 +152,25 @@ export class RetrieveResultFile implements SalesforceRetrievedComponentFile {
131
152
}
132
153
133
154
/**
134
- * Extracts the file to the target folder and optionally the meta file.
135
- * @param {string } targetFolder Target folder to extract the file to.
136
- * @param {object } [options] Additional options.
137
- * @param {boolean } [options.fileOnly] If true only the file will be extracted, otherwise the full path will be used.
138
- * @returns
155
+ * Extracts and writes expanded metadata files to the specified target folder.
156
+ *
157
+ * This method uses the `MetadataExpander` to expand the current metadata object,
158
+ * then writes each expanded file to the given target directory. The method returns
159
+ * a list of the relative file paths that were written.
160
+ *
161
+ * @param targetFolder - The absolute or relative path to the folder where the expanded files will be written.
162
+ * @returns A promise that resolves to an array of file paths representing the files that were written.
139
163
*/
140
- public writeFile ( targetFolder : string , options ?: { fileOnly ?: boolean } ) : Promise < void > {
141
- const targetPath = path . join ( targetFolder ,
142
- options ?. fileOnly
143
- ? path . basename ( this . packagePath )
144
- : this . packagePath
145
- ) ;
146
- return new Promise ( ( resolve , reject ) => {
147
- fs . ensureDir ( path . dirname ( targetPath ) ) . then ( ( ) => {
148
- this . getFile ( ) . nodeStream ( ) . pipe ( fs . createWriteStream ( targetPath , { flags : 'w' } ) )
149
- . on ( 'finish' , ( ) => resolve ( ) )
150
- . on ( 'error' , reject ) ;
151
- } ) . catch ( reject ) ;
152
- } ) ;
164
+ public async extractTo ( targetFolder : string ) {
165
+ const expander = new MetadataExpander ( ) ;
166
+ const result = await expander . expandMetadata ( this ) ;
167
+ const filesWritten : string [ ] = [ ]
168
+ for ( const [ expandedFile , data ] of Object . entries ( result ) ) {
169
+ const expandedFilePath = path . join ( targetFolder , expandedFile ) ;
170
+ await fs . outputFile ( expandedFilePath , data ) ;
171
+ filesWritten . push ( expandedFilePath ) ;
172
+ }
173
+ return filesWritten ;
153
174
}
154
175
155
176
/**
@@ -168,6 +189,15 @@ export class RetrieveResultFile implements SalesforceRetrievedComponentFile {
168
189
return this . getFile ( ) . nodeStream ( ) ;
169
190
}
170
191
192
+ /**
193
+ * Reads and returns the contents as a Buffer.
194
+ *
195
+ * @returns A promise that resolves to a Buffer containing the data.
196
+ */
197
+ public read ( ) : Promise < Buffer > {
198
+ return this . getBuffer ( ) ;
199
+ }
200
+
171
201
private getFile ( ) {
172
202
const file = this . file ;
173
203
if ( ! file ) {
@@ -270,7 +300,7 @@ export class RetrieveResultPackage {
270
300
* Gets all files in the retrieve result package.
271
301
* @returns A list of all files in the retrieve result package.
272
302
*/
273
- public getFiles ( ) : Array < RetrieveResultFile > {
303
+ public getFiles ( predicate ?: ( file : RetrieveResultFile , index : number ) => boolean ) : Array < RetrieveResultFile > {
274
304
if ( this . files ) {
275
305
return this . files ;
276
306
}
@@ -299,7 +329,7 @@ export class RetrieveResultPackage {
299
329
return files ;
300
330
}
301
331
) ;
302
- return this . files ;
332
+ return predicate ? this . files . filter ( predicate ) : this . files ;
303
333
}
304
334
305
335
/**
@@ -317,31 +347,40 @@ export class RetrieveResultPackage {
317
347
return manifests . reduce ( ( manifest , current ) => manifest . merge ( current ) ) ;
318
348
}
319
349
320
- public async unpackFolder ( packageFolder : string , targetPath : string ) : Promise < void > {
321
- const files = this . filterFiles ( file => directoryName ( file ) . endsWith ( packageFolder . toLowerCase ( ) ) ) ;
322
- if ( ! files ) {
323
- throw new Error ( `The specified folder ${ packageFolder } was not found in retrieved package or is empty` ) ;
324
- }
325
- for ( const file of files ) {
326
- await this . streamFileToDisk ( file , path . join ( targetPath , baseName ( file . name ) ) ) ;
327
- }
328
- }
329
-
330
- public unpackFile ( packageFile : string , targetPath : string ) : Promise < void > {
331
- const file = this . file ( file => file . toLowerCase ( ) . endsWith ( packageFile . toLowerCase ( ) ) ) ;
332
- if ( ! file ) {
333
- throw new Error ( `The specified file ${ packageFile } was not found in retrieved package` ) ;
334
- }
335
- return this . streamFileToDisk ( file , targetPath ) ;
336
- }
337
-
338
- public unpackFileToFolder ( packageFile : string , targetPath : string ) : Promise < void > {
339
- const file = this . file ( file => file . toLowerCase ( ) . endsWith ( packageFile . toLowerCase ( ) ) ) ;
340
- if ( ! file ) {
341
- throw new Error ( `The specified file ${ packageFile } was not found in retrieved package` ) ;
342
- }
343
- return this . streamFileToDisk ( file , path . join ( targetPath , baseName ( file . name ) ) ) ;
344
- }
350
+ // /**
351
+ // * @deprecated Use {@link RetrieveResultFile.extractTo} instead.
352
+ // */
353
+ // public async unpackFolder(packageFolder: string, targetPath: string) : Promise<void> {
354
+ // const files = await this.getFiles(file => file.folderName.endsWith(packageFolder.toLowerCase()));
355
+ // if (!files) {
356
+ // throw new Error(`The specified folder ${packageFolder} was not found in retrieved package or is empty`);
357
+ // }
358
+ // for (const file of files) {
359
+ // await file.extractTo(targetPath);
360
+ // }
361
+ // }
362
+
363
+ // /**
364
+ // * @deprecated Use {@link RetrieveResultFile.extractTo} instead.
365
+ // */
366
+ // public unpackFile(packageFile: string, targetPath: string) : Promise<void> {
367
+ // const file = this.file(file => file.toLowerCase().endsWith(packageFile.toLowerCase()));
368
+ // if (!file) {
369
+ // throw new Error(`The specified file ${packageFile} was not found in retrieved package`);
370
+ // }
371
+ // return this.streamFileToDisk(file, targetPath);
372
+ // }
373
+
374
+ // /**
375
+ // * @deprecated Use {@link RetrieveResultFile.extractTo} instead.
376
+ // */
377
+ // public unpackFileToFolder(packageFile: string, targetPath: string) : Promise<void> {
378
+ // const file = this.file(file => file.toLowerCase().endsWith(packageFile.toLowerCase()));
379
+ // if (!file) {
380
+ // throw new Error(`The specified file ${packageFile} was not found in retrieved package`);
381
+ // }
382
+ // return this.streamFileToDisk(file, path.join(targetPath, baseName(file.name)));
383
+ // }
345
384
346
385
private file ( filter : string | ( ( file : string ) => any ) ) : ZipArchive . JSZipObject | undefined {
347
386
for ( const archive of this . archives ?? [ ] ) {
@@ -354,7 +393,7 @@ export class RetrieveResultPackage {
354
393
}
355
394
}
356
395
357
- private filterFiles ( filter : ( file : string ) => any ) : Array < ZipArchive . JSZipObject > {
396
+ private filterFiles ( filter : ( file : string ) => any ) {
358
397
const files = new Array < ZipArchive . JSZipObject > ( ) ;
359
398
for ( const archive of this . archives ?? [ ] ) {
360
399
files . push ( ...archive . filter ( filter ) ) ;
0 commit comments