|
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