|
5 | 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause |
6 | 6 | */ |
7 | 7 | /* eslint-disable class-methods-use-this */ |
8 | | -import { join, dirname, basename, normalize, sep } from 'node:path'; |
| 8 | +import { join, dirname, basename, sep, posix } from 'node:path'; |
9 | 9 | import { Readable } from 'node:stream'; |
10 | 10 | import { statSync, existsSync, readdirSync, createReadStream, readFileSync } from 'graceful-fs'; |
11 | 11 | import JSZip from 'jszip'; |
@@ -126,10 +126,18 @@ export class NodeFSTreeContainer extends TreeContainer { |
126 | 126 | */ |
127 | 127 | export class ZipTreeContainer extends TreeContainer { |
128 | 128 | private zip: JSZip; |
| 129 | + private zipKeyMap: Map<string, string> = new Map<string, string>(); |
129 | 130 |
|
130 | 131 | private constructor(zip: JSZip) { |
131 | 132 | super(); |
132 | 133 | this.zip = zip; |
| 134 | + for (const key of Object.keys(this.zip.files)) { |
| 135 | + if (key.endsWith('/')) { |
| 136 | + this.zipKeyMap.set(key.slice(0, -1), key); |
| 137 | + } else { |
| 138 | + this.zipKeyMap.set(key, key); |
| 139 | + } |
| 140 | + } |
133 | 141 | } |
134 | 142 |
|
135 | 143 | public static async create(buffer: Buffer): Promise<ZipTreeContainer> { |
@@ -191,23 +199,15 @@ export class ZipTreeContainer extends TreeContainer { |
191 | 199 | throw new SfError(messages.getMessage('error_expected_file_path', [fsPath]), 'LibraryError'); |
192 | 200 | } |
193 | 201 |
|
194 | | - // Finds a matching entry in the zip by first comparing basenames, then dirnames. |
195 | | - // Note that zip files always use forward slash separators, so paths within the |
196 | | - // zip files are normalized for the OS file system before comparing. |
| 202 | + // Finds a matching entry in the map of zip keys (that have trailing /'s removed). |
| 203 | + // Note that zip files always use forward slash separators, so the provided path |
| 204 | + // is converted to use posix forward slash separators before comparing. |
197 | 205 | private match(fsPath: string): string | undefined { |
198 | 206 | // "dot" has a special meaning as a directory name and always matches. Just return it. |
199 | 207 | if (fsPath === '.') { |
200 | 208 | return fsPath; |
201 | 209 | } |
202 | | - |
203 | | - const fsPathBasename = basename(fsPath); |
204 | | - const fsPathDirname = dirname(fsPath); |
205 | | - return Object.keys(this.zip.files).find((filePath) => { |
206 | | - const normFilePath = normalize(filePath); |
207 | | - if (basename(normFilePath) === fsPathBasename) { |
208 | | - return dirname(normFilePath) === fsPathDirname; |
209 | | - } |
210 | | - }); |
| 210 | + return this.zipKeyMap.get(posix.normalize(fsPath.replaceAll('\\', '/'))); |
211 | 211 | } |
212 | 212 |
|
213 | 213 | private ensureDirectory(dirPath: string): boolean { |
|
0 commit comments