zip-lib 1.2.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +295 -204
- package/lib/fs.d.ts +1 -0
- package/lib/fs.js +74 -61
- package/lib/index.d.ts +21 -2
- package/lib/index.js +27 -24
- package/lib/unzip.d.ts +22 -10
- package/lib/unzip.js +189 -129
- package/lib/zip.d.ts +25 -10
- package/lib/zip.js +143 -60
- package/package.json +3 -3
package/lib/fs.js
CHANGED
|
@@ -6,6 +6,7 @@ exports.readdirp = readdirp;
|
|
|
6
6
|
exports.getFileEntry = getFileEntry;
|
|
7
7
|
exports.ensureFolder = ensureFolder;
|
|
8
8
|
exports.pathExists = pathExists;
|
|
9
|
+
exports.statFolder = statFolder;
|
|
9
10
|
exports.rimraf = rimraf;
|
|
10
11
|
exports.isRootPath = isRootPath;
|
|
11
12
|
const fsSync = require("node:fs");
|
|
@@ -25,16 +26,14 @@ async function realpath(target) {
|
|
|
25
26
|
}
|
|
26
27
|
async function readdirp(folder) {
|
|
27
28
|
const result = [];
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const entry = await getFileEntry(file);
|
|
29
|
+
const filePaths = (await fs.readdir(folder)).map((item) => path.join(folder, item));
|
|
30
|
+
const entries = await Promise.all(filePaths.map((filePath) => getFileEntry(filePath)));
|
|
31
|
+
for (const entry of entries) {
|
|
32
32
|
if (!entry.isSymbolicLink && entry.type === "dir") {
|
|
33
|
-
const subFiles = await readdirp(
|
|
33
|
+
const subFiles = await readdirp(entry.path);
|
|
34
34
|
if (subFiles.length > 0) {
|
|
35
35
|
result.push(...subFiles);
|
|
36
36
|
// If the folder is not empty, don't need to add the folder itself.
|
|
37
|
-
// continue and skip the code below
|
|
38
37
|
continue;
|
|
39
38
|
}
|
|
40
39
|
}
|
|
@@ -44,27 +43,32 @@ async function readdirp(folder) {
|
|
|
44
43
|
}
|
|
45
44
|
async function getFileEntry(target) {
|
|
46
45
|
const stat = await fs.lstat(target);
|
|
47
|
-
let isSymbolicLink = false;
|
|
48
|
-
let fileType = "file";
|
|
49
46
|
if (stat.isDirectory()) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
47
|
+
return {
|
|
48
|
+
path: target,
|
|
49
|
+
isSymbolicLink: false,
|
|
50
|
+
type: "dir",
|
|
51
|
+
mtime: stat.mtime,
|
|
52
|
+
mode: stat.mode,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (!stat.isSymbolicLink()) {
|
|
56
|
+
return {
|
|
57
|
+
path: target,
|
|
58
|
+
isSymbolicLink: false,
|
|
59
|
+
type: "file",
|
|
60
|
+
mtime: stat.mtime,
|
|
61
|
+
mode: stat.mode,
|
|
62
|
+
};
|
|
63
63
|
}
|
|
64
|
+
// If the path is a link, we must instead use fs.stat() to find out if the
|
|
65
|
+
// link is a directory or not because lstat will always return the stat of
|
|
66
|
+
// the link which is always a file.
|
|
67
|
+
const actualStat = await fs.stat(target);
|
|
64
68
|
return {
|
|
65
69
|
path: target,
|
|
66
|
-
isSymbolicLink,
|
|
67
|
-
type:
|
|
70
|
+
isSymbolicLink: true,
|
|
71
|
+
type: actualStat.isDirectory() ? "dir" : "file",
|
|
68
72
|
mtime: stat.mtime,
|
|
69
73
|
mode: stat.mode,
|
|
70
74
|
};
|
|
@@ -72,24 +76,23 @@ async function getFileEntry(target) {
|
|
|
72
76
|
async function ensureFolder(folder) {
|
|
73
77
|
// stop at root
|
|
74
78
|
if (folder === path.dirname(folder)) {
|
|
75
|
-
return
|
|
79
|
+
return {
|
|
76
80
|
isDirectory: true,
|
|
77
81
|
isSymbolicLink: false,
|
|
78
|
-
}
|
|
82
|
+
};
|
|
79
83
|
}
|
|
80
84
|
try {
|
|
81
|
-
|
|
82
|
-
return result;
|
|
85
|
+
return await mkdir(folder);
|
|
83
86
|
}
|
|
84
87
|
catch (error) {
|
|
85
88
|
// ENOENT: a parent folder does not exist yet, continue
|
|
86
89
|
// to create the parent folder and then try again.
|
|
87
90
|
if (error.code === "ENOENT") {
|
|
88
91
|
await ensureFolder(path.dirname(folder));
|
|
89
|
-
return mkdir(folder);
|
|
92
|
+
return await mkdir(folder);
|
|
90
93
|
}
|
|
91
94
|
// Any other error
|
|
92
|
-
|
|
95
|
+
throw error;
|
|
93
96
|
}
|
|
94
97
|
}
|
|
95
98
|
async function pathExists(target) {
|
|
@@ -101,10 +104,21 @@ async function pathExists(target) {
|
|
|
101
104
|
return false;
|
|
102
105
|
}
|
|
103
106
|
}
|
|
107
|
+
async function statFolder(folder) {
|
|
108
|
+
try {
|
|
109
|
+
return await statExistingFolder(folder);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
if (error.code === "ENOENT") {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
104
118
|
async function rimraf(target) {
|
|
105
119
|
if (isRootPath(target)) {
|
|
106
120
|
// refuse to recursively delete root
|
|
107
|
-
|
|
121
|
+
throw new Error(`Refuse to recursively delete root, path: "${target}"`);
|
|
108
122
|
}
|
|
109
123
|
try {
|
|
110
124
|
const stat = await fs.lstat(target);
|
|
@@ -115,17 +129,15 @@ async function rimraf(target) {
|
|
|
115
129
|
await Promise.all(children.map((child) => rimraf(path.join(target, child))));
|
|
116
130
|
// Folder
|
|
117
131
|
await fs.rmdir(target);
|
|
132
|
+
return;
|
|
118
133
|
}
|
|
119
134
|
// Single file delete
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
// 128 === 0200
|
|
125
|
-
await fs.chmod(target, mode | 128);
|
|
126
|
-
}
|
|
127
|
-
return fs.unlink(target);
|
|
135
|
+
const mode = stat.mode;
|
|
136
|
+
if (!(mode & 128)) {
|
|
137
|
+
// 128 === 0200
|
|
138
|
+
await fs.chmod(target, mode | 128);
|
|
128
139
|
}
|
|
140
|
+
await fs.unlink(target);
|
|
129
141
|
}
|
|
130
142
|
catch (error) {
|
|
131
143
|
if (error.code !== "ENOENT") {
|
|
@@ -144,39 +156,40 @@ async function mkdir(folder) {
|
|
|
144
156
|
catch (error) {
|
|
145
157
|
// ENOENT: a parent folder does not exist yet or folder name is invalid.
|
|
146
158
|
if (error.code === "ENOENT") {
|
|
147
|
-
|
|
159
|
+
throw error;
|
|
148
160
|
}
|
|
149
161
|
// Any other error: check if folder exists and
|
|
150
162
|
// return normally in that case if its a folder
|
|
151
163
|
try {
|
|
152
|
-
|
|
153
|
-
if (fileStat.isSymbolicLink()) {
|
|
154
|
-
const realFilePath = await realpath(folder);
|
|
155
|
-
const realFileStat = await fs.lstat(realFilePath);
|
|
156
|
-
if (!realFileStat.isDirectory()) {
|
|
157
|
-
return Promise.reject(new Error(`"${folder}" exists and is not a directory.`));
|
|
158
|
-
}
|
|
159
|
-
return {
|
|
160
|
-
isDirectory: false,
|
|
161
|
-
isSymbolicLink: true,
|
|
162
|
-
realpath: realFilePath,
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
else {
|
|
166
|
-
if (!fileStat.isDirectory()) {
|
|
167
|
-
return Promise.reject(new Error(`"${folder}" exists and is not a directory.`));
|
|
168
|
-
}
|
|
169
|
-
return {
|
|
170
|
-
isDirectory: true,
|
|
171
|
-
isSymbolicLink: false,
|
|
172
|
-
};
|
|
173
|
-
}
|
|
164
|
+
return await statExistingFolder(folder);
|
|
174
165
|
}
|
|
175
166
|
catch (_statError) {
|
|
176
167
|
throw error; // rethrow original error
|
|
177
168
|
}
|
|
178
169
|
}
|
|
179
170
|
}
|
|
171
|
+
async function statExistingFolder(folder) {
|
|
172
|
+
const fileStat = await fs.lstat(folder);
|
|
173
|
+
if (!fileStat.isSymbolicLink()) {
|
|
174
|
+
if (!fileStat.isDirectory()) {
|
|
175
|
+
throw new Error(`"${folder}" exists and is not a directory.`);
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
isDirectory: true,
|
|
179
|
+
isSymbolicLink: false,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
const realFilePath = await realpath(folder);
|
|
183
|
+
const realFileStat = await fs.lstat(realFilePath);
|
|
184
|
+
if (!realFileStat.isDirectory()) {
|
|
185
|
+
throw new Error(`"${folder}" exists and is not a directory.`);
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
isDirectory: false,
|
|
189
|
+
isSymbolicLink: true,
|
|
190
|
+
realpath: realFilePath,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
180
193
|
// "A"
|
|
181
194
|
const charA = 65;
|
|
182
195
|
// "Z"
|
package/lib/index.d.ts
CHANGED
|
@@ -3,19 +3,38 @@ import { type IZipOptions } from "./zip";
|
|
|
3
3
|
export * from "./unzip";
|
|
4
4
|
export * from "./zip";
|
|
5
5
|
/**
|
|
6
|
-
* Compress a single file to
|
|
6
|
+
* Compress a single file to a buffer.
|
|
7
|
+
* @param file
|
|
8
|
+
* @param options
|
|
9
|
+
*/
|
|
10
|
+
export declare function archiveFile(file: string, options?: IZipOptions): Promise<Buffer>;
|
|
11
|
+
/**
|
|
12
|
+
* Compress a single file to the specified zip file path.
|
|
7
13
|
* @param file
|
|
8
14
|
* @param zipFile the zip file path.
|
|
9
15
|
* @param options
|
|
10
16
|
*/
|
|
11
17
|
export declare function archiveFile(file: string, zipFile: string, options?: IZipOptions): Promise<void>;
|
|
12
18
|
/**
|
|
13
|
-
* Compress all the contents of the specified folder to
|
|
19
|
+
* Compress all the contents of the specified folder to a buffer.
|
|
20
|
+
* @param folder
|
|
21
|
+
* @param options
|
|
22
|
+
*/
|
|
23
|
+
export declare function archiveFolder(folder: string, options?: IZipOptions): Promise<Buffer>;
|
|
24
|
+
/**
|
|
25
|
+
* Compress all the contents of the specified folder to the specified zip file path.
|
|
14
26
|
* @param folder
|
|
15
27
|
* @param zipFile the zip file path.
|
|
16
28
|
* @param options
|
|
17
29
|
*/
|
|
18
30
|
export declare function archiveFolder(folder: string, zipFile: string, options?: IZipOptions): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Extract the zip buffer to the specified location.
|
|
33
|
+
* @param zipBuffer
|
|
34
|
+
* @param targetFolder
|
|
35
|
+
* @param options
|
|
36
|
+
*/
|
|
37
|
+
export declare function extract(zipBuffer: Buffer, targetFolder: string, options?: IExtractOptions): Promise<void>;
|
|
19
38
|
/**
|
|
20
39
|
* Extract the zip file to the specified location.
|
|
21
40
|
* @param zipFile
|
package/lib/index.js
CHANGED
|
@@ -21,35 +21,38 @@ const unzip_1 = require("./unzip");
|
|
|
21
21
|
const zip_1 = require("./zip");
|
|
22
22
|
__exportStar(require("./unzip"), exports);
|
|
23
23
|
__exportStar(require("./zip"), exports);
|
|
24
|
-
/**
|
|
25
|
-
* Compress a single file to zip.
|
|
26
|
-
* @param file
|
|
27
|
-
* @param zipFile the zip file path.
|
|
28
|
-
* @param options
|
|
29
|
-
*/
|
|
30
24
|
function archiveFile(file, zipFile, options) {
|
|
31
|
-
|
|
25
|
+
let optionsParameter;
|
|
26
|
+
if (typeof zipFile === "string") {
|
|
27
|
+
optionsParameter = options;
|
|
28
|
+
}
|
|
29
|
+
else if (typeof zipFile === "object") {
|
|
30
|
+
optionsParameter = zipFile;
|
|
31
|
+
}
|
|
32
|
+
const zip = new zip_1.Zip(optionsParameter);
|
|
32
33
|
zip.addFile(file);
|
|
33
|
-
|
|
34
|
+
if (typeof zipFile === "string") {
|
|
35
|
+
return zip.archive(zipFile);
|
|
36
|
+
}
|
|
37
|
+
return zip.archive();
|
|
34
38
|
}
|
|
35
|
-
/**
|
|
36
|
-
* Compress all the contents of the specified folder to zip.
|
|
37
|
-
* @param folder
|
|
38
|
-
* @param zipFile the zip file path.
|
|
39
|
-
* @param options
|
|
40
|
-
*/
|
|
41
39
|
function archiveFolder(folder, zipFile, options) {
|
|
42
|
-
|
|
40
|
+
let optionsParameter;
|
|
41
|
+
if (typeof zipFile === "string") {
|
|
42
|
+
optionsParameter = options;
|
|
43
|
+
}
|
|
44
|
+
else if (typeof zipFile === "object") {
|
|
45
|
+
optionsParameter = zipFile;
|
|
46
|
+
}
|
|
47
|
+
const zip = new zip_1.Zip(optionsParameter);
|
|
43
48
|
zip.addFolder(folder);
|
|
44
|
-
|
|
49
|
+
if (typeof zipFile === "string") {
|
|
50
|
+
return zip.archive(zipFile);
|
|
51
|
+
}
|
|
52
|
+
return zip.archive();
|
|
45
53
|
}
|
|
46
|
-
|
|
47
|
-
* Extract the zip file to the specified location.
|
|
48
|
-
* @param zipFile
|
|
49
|
-
* @param targetFolder
|
|
50
|
-
* @param options
|
|
51
|
-
*/
|
|
52
|
-
function extract(zipFile, targetFolder, options) {
|
|
54
|
+
function extract(zipFileOrBuffer, targetFolder, options) {
|
|
53
55
|
const unzip = new unzip_1.Unzip(options);
|
|
54
|
-
|
|
56
|
+
// biome-ignore lint/suspicious/noExplicitAny: <>
|
|
57
|
+
return unzip.extract(zipFileOrBuffer, targetFolder);
|
|
55
58
|
}
|
package/lib/unzip.d.ts
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import { Cancelable } from "./cancelable";
|
|
2
2
|
export interface IExtractOptions {
|
|
3
3
|
/**
|
|
4
|
-
* If it is `true`, the target directory will be deleted before
|
|
4
|
+
* If it is `true`, the target directory will be deleted before extraction.
|
|
5
5
|
* The default value is `false`.
|
|
6
6
|
*/
|
|
7
7
|
overwrite?: boolean;
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* Extracts symbolic links as files on Windows. This value is only available on Windows and is ignored on other platforms.
|
|
10
10
|
* The default value is `true`.
|
|
11
11
|
*
|
|
12
12
|
* If `true`, the symlink in the zip will be extracted as a normal file on Windows.
|
|
13
13
|
*
|
|
14
|
-
* If `false`, the
|
|
14
|
+
* If `false`, the library will try to extract symlinks as real symlinks on Windows.
|
|
15
|
+
* This may fail with an `EPERM` error when the current process is not allowed to create symlinks.
|
|
15
16
|
*
|
|
16
|
-
* > ⚠**WARNING:** On Windows,
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* > ⚠**WARNING:** On Windows, creating symbolic links may require administrator privileges,
|
|
18
|
+
* depending on system policy. If Windows Developer Mode is enabled, non-administrator
|
|
19
|
+
* processes can usually create symlinks as well.
|
|
19
20
|
*/
|
|
20
21
|
symlinkAsFileOnWindows?: boolean;
|
|
21
22
|
/**
|
|
@@ -36,7 +37,7 @@ export interface IExtractOptions {
|
|
|
36
37
|
onEntry?: (event: IEntryEvent) => void;
|
|
37
38
|
}
|
|
38
39
|
/**
|
|
39
|
-
*
|
|
40
|
+
* Represents an event fired before an entry is extracted.
|
|
40
41
|
*/
|
|
41
42
|
export interface IEntryEvent {
|
|
42
43
|
/**
|
|
@@ -48,7 +49,7 @@ export interface IEntryEvent {
|
|
|
48
49
|
*/
|
|
49
50
|
readonly entryCount: number;
|
|
50
51
|
/**
|
|
51
|
-
*
|
|
52
|
+
* Prevents the current entry from being extracted.
|
|
52
53
|
*/
|
|
53
54
|
preventDefault(): void;
|
|
54
55
|
}
|
|
@@ -63,15 +64,25 @@ export declare class Unzip extends Cancelable {
|
|
|
63
64
|
constructor(options?: IExtractOptions | undefined);
|
|
64
65
|
private zipFile;
|
|
65
66
|
private token;
|
|
67
|
+
/**
|
|
68
|
+
* Extract the zip buffer to the specified location.
|
|
69
|
+
* @param zipBuffer
|
|
70
|
+
* @param targetFolder
|
|
71
|
+
*/
|
|
72
|
+
extract(zipBuffer: Buffer, targetFolder: string): Promise<void>;
|
|
66
73
|
/**
|
|
67
74
|
* Extract the zip file to the specified location.
|
|
68
75
|
* @param zipFile
|
|
69
76
|
* @param targetFolder
|
|
70
|
-
* @param options
|
|
71
77
|
*/
|
|
72
78
|
extract(zipFile: string, targetFolder: string): Promise<void>;
|
|
79
|
+
private prepareExtraction;
|
|
80
|
+
private processEntries;
|
|
81
|
+
private readNextEntry;
|
|
82
|
+
private createPromiseSettler;
|
|
83
|
+
private handleZipEntry;
|
|
73
84
|
/**
|
|
74
|
-
* Cancel
|
|
85
|
+
* Cancel extraction.
|
|
75
86
|
* If the cancel method is called after the extract is complete, nothing will happen.
|
|
76
87
|
*/
|
|
77
88
|
cancel(): void;
|
|
@@ -81,6 +92,7 @@ export declare class Unzip extends Cancelable {
|
|
|
81
92
|
private openZipFileStream;
|
|
82
93
|
private extractEntry;
|
|
83
94
|
private writeEntryToFile;
|
|
95
|
+
private readStreamContent;
|
|
84
96
|
private modeFromEntry;
|
|
85
97
|
private createSymlink;
|
|
86
98
|
private isOverwrite;
|