isomorphic-git 1.32.3 → 1.33.1

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.
@@ -0,0 +1,365 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
+
7
+ var pify = _interopDefault(require('pify'));
8
+ var pathBrowserify = require('path-browserify');
9
+
10
+ function compareStrings(a, b) {
11
+ // https://stackoverflow.com/a/40355107/2168416
12
+ return -(a < b) || +(a > b)
13
+ }
14
+
15
+ function dirname(path) {
16
+ const last = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
17
+ if (last === -1) return '.'
18
+ if (last === 0) return '/'
19
+ return path.slice(0, last)
20
+ }
21
+
22
+ /**
23
+ * Removes the directory at the specified filepath recursively. Used internally to replicate the behavior of
24
+ * fs.promises.rm({ recursive: true, force: true }) from Node.js 14 and above when not available. If the provided
25
+ * filepath resolves to a file, it will be removed.
26
+ *
27
+ * @param {import('../models/FileSystem.js').FileSystem} fs
28
+ * @param {string} filepath - The file or directory to remove.
29
+ */
30
+ async function rmRecursive(fs, filepath) {
31
+ const entries = await fs.readdir(filepath);
32
+ if (entries == null) {
33
+ await fs.rm(filepath);
34
+ } else if (entries.length) {
35
+ await Promise.all(
36
+ entries.map(entry => {
37
+ const subpath = pathBrowserify.join(filepath, entry);
38
+ return fs.lstat(subpath).then(stat => {
39
+ if (!stat) return
40
+ return stat.isDirectory() ? rmRecursive(fs, subpath) : fs.rm(subpath)
41
+ })
42
+ })
43
+ ).then(() => fs.rmdir(filepath));
44
+ } else {
45
+ await fs.rmdir(filepath);
46
+ }
47
+ }
48
+
49
+ function isPromiseLike(obj) {
50
+ return isObject(obj) && isFunction(obj.then) && isFunction(obj.catch)
51
+ }
52
+
53
+ function isObject(obj) {
54
+ return obj && typeof obj === 'object'
55
+ }
56
+
57
+ function isFunction(obj) {
58
+ return typeof obj === 'function'
59
+ }
60
+
61
+ function isPromiseFs(fs) {
62
+ const test = targetFs => {
63
+ try {
64
+ // If readFile returns a promise then we can probably assume the other
65
+ // commands do as well
66
+ return targetFs.readFile().catch(e => e)
67
+ } catch (e) {
68
+ return e
69
+ }
70
+ };
71
+ return isPromiseLike(test(fs))
72
+ }
73
+
74
+ // List of commands all filesystems are expected to provide. `rm` is not
75
+ // included since it may not exist and must be handled as a special case
76
+ const commands = [
77
+ 'readFile',
78
+ 'writeFile',
79
+ 'mkdir',
80
+ 'rmdir',
81
+ 'unlink',
82
+ 'stat',
83
+ 'lstat',
84
+ 'readdir',
85
+ 'readlink',
86
+ 'symlink',
87
+ ];
88
+
89
+ function bindFs(target, fs) {
90
+ if (isPromiseFs(fs)) {
91
+ for (const command of commands) {
92
+ target[`_${command}`] = fs[command].bind(fs);
93
+ }
94
+ } else {
95
+ for (const command of commands) {
96
+ target[`_${command}`] = pify(fs[command].bind(fs));
97
+ }
98
+ }
99
+
100
+ // Handle the special case of `rm`
101
+ if (isPromiseFs(fs)) {
102
+ if (fs.rm) target._rm = fs.rm.bind(fs);
103
+ else if (fs.rmdir.length > 1) target._rm = fs.rmdir.bind(fs);
104
+ else target._rm = rmRecursive.bind(null, target);
105
+ } else {
106
+ if (fs.rm) target._rm = pify(fs.rm.bind(fs));
107
+ else if (fs.rmdir.length > 2) target._rm = pify(fs.rmdir.bind(fs));
108
+ else target._rm = rmRecursive.bind(null, target);
109
+ }
110
+ }
111
+
112
+ /**
113
+ * A wrapper class for file system operations, providing a consistent API for both promise-based
114
+ * and callback-based file systems. It includes utility methods for common file system tasks.
115
+ */
116
+ class FileSystem {
117
+ /**
118
+ * Creates an instance of FileSystem.
119
+ *
120
+ * @param {Object} fs - A file system implementation to wrap.
121
+ */
122
+ constructor(fs) {
123
+ if (typeof fs._original_unwrapped_fs !== 'undefined') return fs
124
+
125
+ const promises = Object.getOwnPropertyDescriptor(fs, 'promises');
126
+ if (promises && promises.enumerable) {
127
+ bindFs(this, fs.promises);
128
+ } else {
129
+ bindFs(this, fs);
130
+ }
131
+ this._original_unwrapped_fs = fs;
132
+ }
133
+
134
+ /**
135
+ * Return true if a file exists, false if it doesn't exist.
136
+ * Rethrows errors that aren't related to file existence.
137
+ *
138
+ * @param {string} filepath - The path to the file.
139
+ * @param {Object} [options] - Additional options.
140
+ * @returns {Promise<boolean>} - `true` if the file exists, `false` otherwise.
141
+ */
142
+ async exists(filepath, options = {}) {
143
+ try {
144
+ await this._stat(filepath);
145
+ return true
146
+ } catch (err) {
147
+ if (
148
+ err.code === 'ENOENT' ||
149
+ err.code === 'ENOTDIR' ||
150
+ (err.code || '').includes('ENS')
151
+ ) {
152
+ return false
153
+ } else {
154
+ console.log('Unhandled error in "FileSystem.exists()" function', err);
155
+ throw err
156
+ }
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Return the contents of a file if it exists, otherwise returns null.
162
+ *
163
+ * @param {string} filepath - The path to the file.
164
+ * @param {Object} [options] - Options for reading the file.
165
+ * @returns {Promise<Buffer|string|null>} - The file contents, or `null` if the file doesn't exist.
166
+ */
167
+ async read(filepath, options = {}) {
168
+ try {
169
+ let buffer = await this._readFile(filepath, options);
170
+ if (options.autocrlf === 'true') {
171
+ try {
172
+ buffer = new TextDecoder('utf8', { fatal: true }).decode(buffer);
173
+ buffer = buffer.replace(/\r\n/g, '\n');
174
+ buffer = new TextEncoder().encode(buffer);
175
+ } catch (error) {
176
+ // non utf8 file
177
+ }
178
+ }
179
+ // Convert plain ArrayBuffers to Buffers
180
+ if (typeof buffer !== 'string') {
181
+ buffer = Buffer.from(buffer);
182
+ }
183
+ return buffer
184
+ } catch (err) {
185
+ return null
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Write a file (creating missing directories if need be) without throwing errors.
191
+ *
192
+ * @param {string} filepath - The path to the file.
193
+ * @param {Buffer|Uint8Array|string} contents - The data to write.
194
+ * @param {Object|string} [options] - Options for writing the file.
195
+ * @returns {Promise<void>}
196
+ */
197
+ async write(filepath, contents, options = {}) {
198
+ try {
199
+ await this._writeFile(filepath, contents, options);
200
+ return
201
+ } catch (err) {
202
+ // Hmm. Let's try mkdirp and try again.
203
+ await this.mkdir(dirname(filepath));
204
+ await this._writeFile(filepath, contents, options);
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Make a directory (or series of nested directories) without throwing an error if it already exists.
210
+ *
211
+ * @param {string} filepath - The path to the directory.
212
+ * @param {boolean} [_selfCall=false] - Internal flag to prevent infinite recursion.
213
+ * @returns {Promise<void>}
214
+ */
215
+ async mkdir(filepath, _selfCall = false) {
216
+ try {
217
+ await this._mkdir(filepath);
218
+ return
219
+ } catch (err) {
220
+ // If err is null then operation succeeded!
221
+ if (err === null) return
222
+ // If the directory already exists, that's OK!
223
+ if (err.code === 'EEXIST') return
224
+ // Avoid infinite loops of failure
225
+ if (_selfCall) throw err
226
+ // If we got a "no such file or directory error" backup and try again.
227
+ if (err.code === 'ENOENT') {
228
+ const parent = dirname(filepath);
229
+ // Check to see if we've gone too far
230
+ if (parent === '.' || parent === '/' || parent === filepath) throw err
231
+ // Infinite recursion, what could go wrong?
232
+ await this.mkdir(parent);
233
+ await this.mkdir(filepath, true);
234
+ }
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Delete a file without throwing an error if it is already deleted.
240
+ *
241
+ * @param {string} filepath - The path to the file.
242
+ * @returns {Promise<void>}
243
+ */
244
+ async rm(filepath) {
245
+ try {
246
+ await this._unlink(filepath);
247
+ } catch (err) {
248
+ if (err.code !== 'ENOENT') throw err
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Delete a directory without throwing an error if it is already deleted.
254
+ *
255
+ * @param {string} filepath - The path to the directory.
256
+ * @param {Object} [opts] - Options for deleting the directory.
257
+ * @returns {Promise<void>}
258
+ */
259
+ async rmdir(filepath, opts) {
260
+ try {
261
+ if (opts && opts.recursive) {
262
+ await this._rm(filepath, opts);
263
+ } else {
264
+ await this._rmdir(filepath);
265
+ }
266
+ } catch (err) {
267
+ if (err.code !== 'ENOENT') throw err
268
+ }
269
+ }
270
+
271
+ /**
272
+ * Read a directory without throwing an error is the directory doesn't exist
273
+ *
274
+ * @param {string} filepath - The path to the directory.
275
+ * @returns {Promise<string[]|null>} - An array of file names, or `null` if the path is not a directory.
276
+ */
277
+ async readdir(filepath) {
278
+ try {
279
+ const names = await this._readdir(filepath);
280
+ // Ordering is not guaranteed, and system specific (Windows vs Unix)
281
+ // so we must sort them ourselves.
282
+ names.sort(compareStrings);
283
+ return names
284
+ } catch (err) {
285
+ if (err.code === 'ENOTDIR') return null
286
+ return []
287
+ }
288
+ }
289
+
290
+ /**
291
+ * Return a flat list of all the files nested inside a directory
292
+ *
293
+ * Based on an elegant concurrent recursive solution from SO
294
+ * https://stackoverflow.com/a/45130990/2168416
295
+ *
296
+ * @param {string} dir - The directory to read.
297
+ * @returns {Promise<string[]>} - A flat list of all files in the directory.
298
+ */
299
+ async readdirDeep(dir) {
300
+ const subdirs = await this._readdir(dir);
301
+ const files = await Promise.all(
302
+ subdirs.map(async subdir => {
303
+ const res = dir + '/' + subdir;
304
+ return (await this._stat(res)).isDirectory()
305
+ ? this.readdirDeep(res)
306
+ : res
307
+ })
308
+ );
309
+ return files.reduce((a, f) => a.concat(f), [])
310
+ }
311
+
312
+ /**
313
+ * Return the Stats of a file/symlink if it exists, otherwise returns null.
314
+ * Rethrows errors that aren't related to file existence.
315
+ *
316
+ * @param {string} filename - The path to the file or symlink.
317
+ * @returns {Promise<Object|null>} - The stats object, or `null` if the file doesn't exist.
318
+ */
319
+ async lstat(filename) {
320
+ try {
321
+ const stats = await this._lstat(filename);
322
+ return stats
323
+ } catch (err) {
324
+ if (err.code === 'ENOENT' || (err.code || '').includes('ENS')) {
325
+ return null
326
+ }
327
+ throw err
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Reads the contents of a symlink if it exists, otherwise returns null.
333
+ * Rethrows errors that aren't related to file existence.
334
+ *
335
+ * @param {string} filename - The path to the symlink.
336
+ * @param {Object} [opts={ encoding: 'buffer' }] - Options for reading the symlink.
337
+ * @returns {Promise<Buffer|null>} - The symlink target, or `null` if it doesn't exist.
338
+ */
339
+ async readlink(filename, opts = { encoding: 'buffer' }) {
340
+ // Note: FileSystem.readlink returns a buffer by default
341
+ // so we can dump it into GitObject.write just like any other file.
342
+ try {
343
+ const link = await this._readlink(filename, opts);
344
+ return Buffer.isBuffer(link) ? link : Buffer.from(link)
345
+ } catch (err) {
346
+ if (err.code === 'ENOENT' || (err.code || '').includes('ENS')) {
347
+ return null
348
+ }
349
+ throw err
350
+ }
351
+ }
352
+
353
+ /**
354
+ * Write the contents of buffer to a symlink.
355
+ *
356
+ * @param {string} filename - The path to the symlink.
357
+ * @param {Buffer} buffer - The symlink target.
358
+ * @returns {Promise<void>}
359
+ */
360
+ async writelink(filename, buffer) {
361
+ return this._symlink(buffer.toString('utf8'), filename)
362
+ }
363
+ }
364
+
365
+ exports.FileSystem = FileSystem;
@@ -0,0 +1,105 @@
1
+ export const __esModule: boolean;
2
+ /**
3
+ * A wrapper class for file system operations, providing a consistent API for both promise-based
4
+ * and callback-based file systems. It includes utility methods for common file system tasks.
5
+ */
6
+ export class FileSystem {
7
+ /**
8
+ * Creates an instance of FileSystem.
9
+ *
10
+ * @param {Object} fs - A file system implementation to wrap.
11
+ */
12
+ constructor(fs: any);
13
+ _original_unwrapped_fs: any;
14
+ /**
15
+ * Return true if a file exists, false if it doesn't exist.
16
+ * Rethrows errors that aren't related to file existence.
17
+ *
18
+ * @param {string} filepath - The path to the file.
19
+ * @param {Object} [options] - Additional options.
20
+ * @returns {Promise<boolean>} - `true` if the file exists, `false` otherwise.
21
+ */
22
+ exists(filepath: string, options?: any): Promise<boolean>;
23
+ /**
24
+ * Return the contents of a file if it exists, otherwise returns null.
25
+ *
26
+ * @param {string} filepath - The path to the file.
27
+ * @param {Object} [options] - Options for reading the file.
28
+ * @returns {Promise<Buffer|string|null>} - The file contents, or `null` if the file doesn't exist.
29
+ */
30
+ read(filepath: string, options?: any): Promise<Buffer | string | null>;
31
+ /**
32
+ * Write a file (creating missing directories if need be) without throwing errors.
33
+ *
34
+ * @param {string} filepath - The path to the file.
35
+ * @param {Buffer|Uint8Array|string} contents - The data to write.
36
+ * @param {Object|string} [options] - Options for writing the file.
37
+ * @returns {Promise<void>}
38
+ */
39
+ write(filepath: string, contents: Buffer | Uint8Array | string, options?: any | string): Promise<void>;
40
+ /**
41
+ * Make a directory (or series of nested directories) without throwing an error if it already exists.
42
+ *
43
+ * @param {string} filepath - The path to the directory.
44
+ * @param {boolean} [_selfCall=false] - Internal flag to prevent infinite recursion.
45
+ * @returns {Promise<void>}
46
+ */
47
+ mkdir(filepath: string, _selfCall?: boolean): Promise<void>;
48
+ /**
49
+ * Delete a file without throwing an error if it is already deleted.
50
+ *
51
+ * @param {string} filepath - The path to the file.
52
+ * @returns {Promise<void>}
53
+ */
54
+ rm(filepath: string): Promise<void>;
55
+ /**
56
+ * Delete a directory without throwing an error if it is already deleted.
57
+ *
58
+ * @param {string} filepath - The path to the directory.
59
+ * @param {Object} [opts] - Options for deleting the directory.
60
+ * @returns {Promise<void>}
61
+ */
62
+ rmdir(filepath: string, opts?: any): Promise<void>;
63
+ /**
64
+ * Read a directory without throwing an error is the directory doesn't exist
65
+ *
66
+ * @param {string} filepath - The path to the directory.
67
+ * @returns {Promise<string[]|null>} - An array of file names, or `null` if the path is not a directory.
68
+ */
69
+ readdir(filepath: string): Promise<string[] | null>;
70
+ /**
71
+ * Return a flat list of all the files nested inside a directory
72
+ *
73
+ * Based on an elegant concurrent recursive solution from SO
74
+ * https://stackoverflow.com/a/45130990/2168416
75
+ *
76
+ * @param {string} dir - The directory to read.
77
+ * @returns {Promise<string[]>} - A flat list of all files in the directory.
78
+ */
79
+ readdirDeep(dir: string): Promise<string[]>;
80
+ /**
81
+ * Return the Stats of a file/symlink if it exists, otherwise returns null.
82
+ * Rethrows errors that aren't related to file existence.
83
+ *
84
+ * @param {string} filename - The path to the file or symlink.
85
+ * @returns {Promise<Object|null>} - The stats object, or `null` if the file doesn't exist.
86
+ */
87
+ lstat(filename: string): Promise<any | null>;
88
+ /**
89
+ * Reads the contents of a symlink if it exists, otherwise returns null.
90
+ * Rethrows errors that aren't related to file existence.
91
+ *
92
+ * @param {string} filename - The path to the symlink.
93
+ * @param {Object} [opts={ encoding: 'buffer' }] - Options for reading the symlink.
94
+ * @returns {Promise<Buffer|null>} - The symlink target, or `null` if it doesn't exist.
95
+ */
96
+ readlink(filename: string, opts?: any): Promise<Buffer | null>;
97
+ /**
98
+ * Write the contents of buffer to a symlink.
99
+ *
100
+ * @param {string} filename - The path to the symlink.
101
+ * @param {Buffer} buffer - The symlink target.
102
+ * @returns {Promise<void>}
103
+ */
104
+ writelink(filename: string, buffer: Buffer): Promise<void>;
105
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * A wrapper class for file system operations, providing a consistent API for both promise-based
3
+ * and callback-based file systems. It includes utility methods for common file system tasks.
4
+ */
5
+ export class FileSystem {
6
+ /**
7
+ * Creates an instance of FileSystem.
8
+ *
9
+ * @param {Object} fs - A file system implementation to wrap.
10
+ */
11
+ constructor(fs: any);
12
+ _original_unwrapped_fs: any;
13
+ /**
14
+ * Return true if a file exists, false if it doesn't exist.
15
+ * Rethrows errors that aren't related to file existence.
16
+ *
17
+ * @param {string} filepath - The path to the file.
18
+ * @param {Object} [options] - Additional options.
19
+ * @returns {Promise<boolean>} - `true` if the file exists, `false` otherwise.
20
+ */
21
+ exists(filepath: string, options?: any): Promise<boolean>;
22
+ /**
23
+ * Return the contents of a file if it exists, otherwise returns null.
24
+ *
25
+ * @param {string} filepath - The path to the file.
26
+ * @param {Object} [options] - Options for reading the file.
27
+ * @returns {Promise<Buffer|string|null>} - The file contents, or `null` if the file doesn't exist.
28
+ */
29
+ read(filepath: string, options?: any): Promise<Buffer | string | null>;
30
+ /**
31
+ * Write a file (creating missing directories if need be) without throwing errors.
32
+ *
33
+ * @param {string} filepath - The path to the file.
34
+ * @param {Buffer|Uint8Array|string} contents - The data to write.
35
+ * @param {Object|string} [options] - Options for writing the file.
36
+ * @returns {Promise<void>}
37
+ */
38
+ write(filepath: string, contents: Buffer | Uint8Array | string, options?: any | string): Promise<void>;
39
+ /**
40
+ * Make a directory (or series of nested directories) without throwing an error if it already exists.
41
+ *
42
+ * @param {string} filepath - The path to the directory.
43
+ * @param {boolean} [_selfCall=false] - Internal flag to prevent infinite recursion.
44
+ * @returns {Promise<void>}
45
+ */
46
+ mkdir(filepath: string, _selfCall?: boolean): Promise<void>;
47
+ /**
48
+ * Delete a file without throwing an error if it is already deleted.
49
+ *
50
+ * @param {string} filepath - The path to the file.
51
+ * @returns {Promise<void>}
52
+ */
53
+ rm(filepath: string): Promise<void>;
54
+ /**
55
+ * Delete a directory without throwing an error if it is already deleted.
56
+ *
57
+ * @param {string} filepath - The path to the directory.
58
+ * @param {Object} [opts] - Options for deleting the directory.
59
+ * @returns {Promise<void>}
60
+ */
61
+ rmdir(filepath: string, opts?: any): Promise<void>;
62
+ /**
63
+ * Read a directory without throwing an error is the directory doesn't exist
64
+ *
65
+ * @param {string} filepath - The path to the directory.
66
+ * @returns {Promise<string[]|null>} - An array of file names, or `null` if the path is not a directory.
67
+ */
68
+ readdir(filepath: string): Promise<string[] | null>;
69
+ /**
70
+ * Return a flat list of all the files nested inside a directory
71
+ *
72
+ * Based on an elegant concurrent recursive solution from SO
73
+ * https://stackoverflow.com/a/45130990/2168416
74
+ *
75
+ * @param {string} dir - The directory to read.
76
+ * @returns {Promise<string[]>} - A flat list of all files in the directory.
77
+ */
78
+ readdirDeep(dir: string): Promise<string[]>;
79
+ /**
80
+ * Return the Stats of a file/symlink if it exists, otherwise returns null.
81
+ * Rethrows errors that aren't related to file existence.
82
+ *
83
+ * @param {string} filename - The path to the file or symlink.
84
+ * @returns {Promise<Object|null>} - The stats object, or `null` if the file doesn't exist.
85
+ */
86
+ lstat(filename: string): Promise<any | null>;
87
+ /**
88
+ * Reads the contents of a symlink if it exists, otherwise returns null.
89
+ * Rethrows errors that aren't related to file existence.
90
+ *
91
+ * @param {string} filename - The path to the symlink.
92
+ * @param {Object} [opts={ encoding: 'buffer' }] - Options for reading the symlink.
93
+ * @returns {Promise<Buffer|null>} - The symlink target, or `null` if it doesn't exist.
94
+ */
95
+ readlink(filename: string, opts?: any): Promise<Buffer | null>;
96
+ /**
97
+ * Write the contents of buffer to a symlink.
98
+ *
99
+ * @param {string} filename - The path to the symlink.
100
+ * @param {Buffer} buffer - The symlink target.
101
+ * @returns {Promise<void>}
102
+ */
103
+ writelink(filename: string, buffer: Buffer): Promise<void>;
104
+ }