@zenfs/core 0.3.4 → 0.4.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/dist/FileIndex.d.ts +6 -0
- package/dist/FileIndex.js +3 -3
- package/dist/backends/AsyncMirror.d.ts +3 -5
- package/dist/backends/AsyncMirror.js +7 -6
- package/dist/backends/AsyncStore.d.ts +9 -4
- package/dist/backends/AsyncStore.js +7 -2
- package/dist/backends/Locked.d.ts +8 -8
- package/dist/backends/Locked.js +2 -1
- package/dist/backends/Overlay.d.ts +13 -1
- package/dist/backends/Overlay.js +16 -16
- package/dist/backends/SyncStore.d.ts +8 -5
- package/dist/backends/SyncStore.js +9 -5
- package/dist/backends/backend.js +8 -8
- package/dist/browser.min.js +4 -5
- package/dist/browser.min.js.map +4 -4
- package/dist/cred.d.ts +1 -1
- package/dist/cred.js +1 -1
- package/dist/emulation/callbacks.d.ts +1 -1
- package/dist/emulation/callbacks.js +1 -1
- package/dist/emulation/constants.d.ts +48 -42
- package/dist/emulation/constants.js +68 -59
- package/dist/emulation/dir.d.ts +2 -2
- package/dist/emulation/promises.d.ts +1 -1
- package/dist/emulation/promises.js +6 -6
- package/dist/emulation/sync.d.ts +1 -1
- package/dist/emulation/sync.js +7 -7
- package/dist/file.d.ts +26 -12
- package/dist/file.js +68 -29
- package/dist/filesystem.d.ts +3 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +4 -5
- package/dist/inode.d.ts +21 -15
- package/dist/inode.js +52 -40
- package/dist/mutex.d.ts +1 -2
- package/dist/mutex.js +1 -1
- package/dist/stats.d.ts +70 -18
- package/dist/stats.js +12 -18
- package/dist/utils.d.ts +3 -8
- package/dist/utils.js +60 -39
- package/package.json +5 -1
- package/readme.md +14 -10
- package/scripts/make-index.js +100 -0
- package/dist/backends/index.d.ts +0 -10
- package/dist/backends/index.js +0 -12
package/dist/stats.js
CHANGED
|
@@ -10,7 +10,8 @@ export var FileType;
|
|
|
10
10
|
FileType[FileType["SYMLINK"] = S_IFLNK] = "SYMLINK";
|
|
11
11
|
})(FileType = FileType || (FileType = {}));
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Provides information about a particular entry in the file system.
|
|
14
|
+
* Common code used by both Stats and BigIntStats.
|
|
14
15
|
*/
|
|
15
16
|
export class StatsCommon {
|
|
16
17
|
get _typename() {
|
|
@@ -47,19 +48,9 @@ export class StatsCommon {
|
|
|
47
48
|
this.birthtimeMs = this._convert(value.getTime());
|
|
48
49
|
}
|
|
49
50
|
/**
|
|
50
|
-
*
|
|
51
|
-
* @param itemType Type of the item (FILE, DIRECTORY, SYMLINK, or SOCKET)
|
|
52
|
-
* @param size Size of the item in bytes. For directories/symlinks,
|
|
53
|
-
* this is normally the size of the struct that represents the item.
|
|
54
|
-
* @param mode Unix-style file mode (e.g. 0o644)
|
|
55
|
-
* @param atimeMs time of last access, in milliseconds since epoch
|
|
56
|
-
* @param mtimeMs time of last modification, in milliseconds since epoch
|
|
57
|
-
* @param ctimeMs time of last time file status was changed, in milliseconds since epoch
|
|
58
|
-
* @param uid the id of the user that owns the file
|
|
59
|
-
* @param gid the id of the group that owns the file
|
|
60
|
-
* @param birthtimeMs time of file creation, in milliseconds since epoch
|
|
51
|
+
* Creates a new stats instance from a stats-like object. Can be used to copy stats (note)
|
|
61
52
|
*/
|
|
62
|
-
constructor(
|
|
53
|
+
constructor({ atimeMs, mtimeMs, ctimeMs, birthtimeMs, uid, gid, size, mode } = {}) {
|
|
63
54
|
/**
|
|
64
55
|
* ID of device containing file
|
|
65
56
|
*/
|
|
@@ -93,7 +84,7 @@ export class StatsCommon {
|
|
|
93
84
|
*/
|
|
94
85
|
this.fileData = null;
|
|
95
86
|
const currentTime = Date.now();
|
|
96
|
-
const resolveT = (
|
|
87
|
+
const resolveT = (val, _default) => (typeof val == this._typename ? val : this._convert(typeof val == this._typename_inverse ? val : _default));
|
|
97
88
|
this.atimeMs = resolveT(atimeMs, currentTime);
|
|
98
89
|
this.mtimeMs = resolveT(mtimeMs, currentTime);
|
|
99
90
|
this.ctimeMs = resolveT(ctimeMs, currentTime);
|
|
@@ -101,6 +92,7 @@ export class StatsCommon {
|
|
|
101
92
|
this.uid = resolveT(uid, 0);
|
|
102
93
|
this.gid = resolveT(gid, 0);
|
|
103
94
|
this.size = this._convert(size);
|
|
95
|
+
const itemType = Number(mode) & S_IFMT || FileType.FILE;
|
|
104
96
|
if (mode) {
|
|
105
97
|
this.mode = this._convert(mode);
|
|
106
98
|
}
|
|
@@ -229,9 +221,10 @@ export class Stats extends StatsCommon {
|
|
|
229
221
|
}
|
|
230
222
|
/**
|
|
231
223
|
* Clones the stats object.
|
|
224
|
+
* @deprecated use `new Stats(stats)`
|
|
232
225
|
*/
|
|
233
|
-
static clone(
|
|
234
|
-
return new Stats(
|
|
226
|
+
static clone(stats) {
|
|
227
|
+
return new Stats(stats);
|
|
235
228
|
}
|
|
236
229
|
}
|
|
237
230
|
Stats;
|
|
@@ -246,9 +239,10 @@ export class BigIntStats extends StatsCommon {
|
|
|
246
239
|
}
|
|
247
240
|
/**
|
|
248
241
|
* Clone a stats object.
|
|
242
|
+
* @deprecated use `new BigIntStats(stats)`
|
|
249
243
|
*/
|
|
250
|
-
static clone(
|
|
251
|
-
return new BigIntStats(
|
|
244
|
+
static clone(stats) {
|
|
245
|
+
return new BigIntStats(stats);
|
|
252
246
|
}
|
|
253
247
|
}
|
|
254
248
|
BigIntStats;
|
package/dist/utils.d.ts
CHANGED
|
@@ -7,23 +7,18 @@ declare global {
|
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
9
|
* Synchronous recursive makedir.
|
|
10
|
-
* @
|
|
10
|
+
* @hidden
|
|
11
11
|
*/
|
|
12
12
|
export declare function mkdirpSync(p: string, mode: number, cred: Cred, fs: FileSystem): void;
|
|
13
13
|
/**
|
|
14
14
|
* Calculates levenshtein distance.
|
|
15
|
-
* @
|
|
15
|
+
* @hidden
|
|
16
16
|
*/
|
|
17
17
|
export declare function levenshtein(a: string, b: string): number;
|
|
18
18
|
/** Waits n ms. */
|
|
19
19
|
export declare function wait(ms: number): Promise<void>;
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
22
|
-
* @todo Look at changing resolve value from cbArgs[0] to include other callback arguments?
|
|
23
|
-
*/
|
|
24
|
-
export declare function toPromise(fn: (...fnArgs: unknown[]) => unknown): (...args: unknown[]) => Promise<unknown>;
|
|
25
|
-
/**
|
|
26
|
-
* @internal
|
|
21
|
+
* @hidden
|
|
27
22
|
*/
|
|
28
23
|
export declare const setImmediate: (callback: () => unknown) => void;
|
|
29
24
|
/**
|
package/dist/utils.js
CHANGED
|
@@ -1,25 +1,21 @@
|
|
|
1
1
|
import { ApiError, ErrorCode } from './ApiError.js';
|
|
2
|
-
import
|
|
2
|
+
import { dirname } from './emulation/path.js';
|
|
3
3
|
/**
|
|
4
4
|
* Synchronous recursive makedir.
|
|
5
|
-
* @
|
|
5
|
+
* @hidden
|
|
6
6
|
*/
|
|
7
7
|
export function mkdirpSync(p, mode, cred, fs) {
|
|
8
8
|
if (!fs.existsSync(p, cred)) {
|
|
9
|
-
mkdirpSync(
|
|
9
|
+
mkdirpSync(dirname(p), mode, cred, fs);
|
|
10
10
|
fs.mkdirSync(p, mode, cred);
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
-
/*
|
|
14
|
-
* Levenshtein distance, from the `js-levenshtein` NPM module.
|
|
15
|
-
* Copied here to avoid complexity of adding another CommonJS module dependency.
|
|
16
|
-
*/
|
|
17
13
|
function _min(d0, d1, d2, bx, ay) {
|
|
18
14
|
return Math.min(d0 + 1, d1 + 1, d2 + 1, bx === ay ? d1 : d1 + 1);
|
|
19
15
|
}
|
|
20
16
|
/**
|
|
21
17
|
* Calculates levenshtein distance.
|
|
22
|
-
* @
|
|
18
|
+
* @hidden
|
|
23
19
|
*/
|
|
24
20
|
export function levenshtein(a, b) {
|
|
25
21
|
if (a === b) {
|
|
@@ -94,26 +90,7 @@ export function wait(ms) {
|
|
|
94
90
|
});
|
|
95
91
|
}
|
|
96
92
|
/**
|
|
97
|
-
*
|
|
98
|
-
* @todo Look at changing resolve value from cbArgs[0] to include other callback arguments?
|
|
99
|
-
*/
|
|
100
|
-
export function toPromise(fn) {
|
|
101
|
-
return function (...args) {
|
|
102
|
-
return new Promise((resolve, reject) => {
|
|
103
|
-
args.push((e, ...cbArgs) => {
|
|
104
|
-
if (e) {
|
|
105
|
-
reject(e);
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
resolve(cbArgs[0]);
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
fn(...args);
|
|
112
|
-
});
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* @internal
|
|
93
|
+
* @hidden
|
|
117
94
|
*/
|
|
118
95
|
export const setImmediate = typeof globalThis.setImmediate == 'function' ? globalThis.setImmediate : cb => setTimeout(cb, 0);
|
|
119
96
|
/**
|
|
@@ -121,21 +98,45 @@ export const setImmediate = typeof globalThis.setImmediate == 'function' ? globa
|
|
|
121
98
|
* @internal
|
|
122
99
|
*/
|
|
123
100
|
export function encode(input, encoding = 'utf8') {
|
|
101
|
+
if (typeof input != 'string') {
|
|
102
|
+
throw new ApiError(ErrorCode.EINVAL, 'Can not encode a non-string');
|
|
103
|
+
}
|
|
124
104
|
switch (encoding) {
|
|
125
105
|
case 'ascii':
|
|
126
|
-
return new globalThis.TextEncoder().encode(input).map(v => v & 0x7f);
|
|
127
106
|
case 'latin1':
|
|
128
107
|
case 'binary':
|
|
108
|
+
return new Uint8Array(Array.from(input).map(char => char.charCodeAt(0)));
|
|
129
109
|
case 'utf8':
|
|
130
110
|
case 'utf-8':
|
|
111
|
+
return new Uint8Array(Array.from(input).flatMap(char => {
|
|
112
|
+
const code = char.charCodeAt(0);
|
|
113
|
+
if (code < 0x80) {
|
|
114
|
+
return code;
|
|
115
|
+
}
|
|
116
|
+
const a = (code & 0x3f) | 0x80;
|
|
117
|
+
if (code < 0x800) {
|
|
118
|
+
return [(code >> 6) | 0xc0, a];
|
|
119
|
+
}
|
|
120
|
+
const b = ((code >> 6) & 0x3f) | 0x80;
|
|
121
|
+
if (code < 0x10000) {
|
|
122
|
+
return [(code >> 12) | 0xe0, b, a];
|
|
123
|
+
}
|
|
124
|
+
return [(code >> 18) | 0xf0, ((code >> 12) & 0x3f) | 0x80, b, a];
|
|
125
|
+
}));
|
|
131
126
|
case 'base64':
|
|
127
|
+
return encode(atob(input), 'utf-8');
|
|
132
128
|
case 'base64url':
|
|
129
|
+
return encode(input.replace('_', '/').replace('-', '+'), 'base64');
|
|
133
130
|
case 'hex':
|
|
134
|
-
return new
|
|
131
|
+
return new Uint8Array(input.match(/.{1,2}/g).map(e => parseInt(e, 16)));
|
|
135
132
|
case 'utf16le':
|
|
136
133
|
case 'ucs2':
|
|
137
134
|
case 'ucs-2':
|
|
138
|
-
|
|
135
|
+
const u16 = new Uint16Array(new ArrayBuffer(input.length * 2));
|
|
136
|
+
for (let i = 0; i < input.length; i++) {
|
|
137
|
+
u16[i] = input.charCodeAt(i);
|
|
138
|
+
}
|
|
139
|
+
return new Uint8Array(u16.buffer);
|
|
139
140
|
default:
|
|
140
141
|
throw new ApiError(ErrorCode.EINVAL, 'Invalid encoding: ' + encoding);
|
|
141
142
|
}
|
|
@@ -145,14 +146,36 @@ export function encode(input, encoding = 'utf8') {
|
|
|
145
146
|
* @internal
|
|
146
147
|
*/
|
|
147
148
|
export function decode(input, encoding = 'utf8') {
|
|
149
|
+
if (!(input instanceof Uint8Array)) {
|
|
150
|
+
throw new ApiError(ErrorCode.EINVAL, 'Can not decode a non-Uint8Array');
|
|
151
|
+
}
|
|
148
152
|
switch (encoding) {
|
|
149
153
|
case 'ascii':
|
|
150
|
-
case 'utf8':
|
|
151
|
-
case 'utf-8':
|
|
152
|
-
return new globalThis.TextDecoder().decode(input);
|
|
153
154
|
case 'latin1':
|
|
154
155
|
case 'binary':
|
|
155
|
-
return
|
|
156
|
+
return Array.from(input)
|
|
157
|
+
.map(char => String.fromCharCode(char))
|
|
158
|
+
.join('');
|
|
159
|
+
case 'utf8':
|
|
160
|
+
case 'utf-8':
|
|
161
|
+
let utf8String = '';
|
|
162
|
+
for (let i = 0; i < input.length; i++) {
|
|
163
|
+
let code;
|
|
164
|
+
if (input[i] < 0x80) {
|
|
165
|
+
code = input[i];
|
|
166
|
+
}
|
|
167
|
+
else if (input[i] < 0xe0) {
|
|
168
|
+
code = ((input[i] & 0x1f) << 6) | (input[++i] & 0x3f);
|
|
169
|
+
}
|
|
170
|
+
else if (input[i] < 0xf0) {
|
|
171
|
+
code = ((input[i] & 0x0f) << 12) | ((input[++i] & 0x3f) << 6) | (input[++i] & 0x3f);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
code = ((input[i] & 0x07) << 18) | ((input[++i] & 0x3f) << 12) | ((input[++i] & 0x3f) << 6) | (input[++i] & 0x3f);
|
|
175
|
+
}
|
|
176
|
+
utf8String += String.fromCharCode(code);
|
|
177
|
+
}
|
|
178
|
+
return utf8String;
|
|
156
179
|
case 'utf16le':
|
|
157
180
|
case 'ucs2':
|
|
158
181
|
case 'ucs-2':
|
|
@@ -163,14 +186,12 @@ export function decode(input, encoding = 'utf8') {
|
|
|
163
186
|
}
|
|
164
187
|
return utf16leString;
|
|
165
188
|
case 'base64':
|
|
166
|
-
return btoa(
|
|
167
|
-
.map(v => String.fromCharCode(v))
|
|
168
|
-
.join(''));
|
|
189
|
+
return btoa(decode(input, 'utf-8'));
|
|
169
190
|
case 'base64url':
|
|
170
191
|
return decode(input, 'base64').replace('/', '_').replace('+', '-');
|
|
171
192
|
case 'hex':
|
|
172
193
|
return Array.from(input)
|
|
173
|
-
.map(e => e.toString(16))
|
|
194
|
+
.map(e => e.toString(16).padStart(2, '0'))
|
|
174
195
|
.join('');
|
|
175
196
|
default:
|
|
176
197
|
throw new ApiError(ErrorCode.EINVAL, 'Invalid encoding: ' + encoding);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenfs/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "A filesystem in your browser",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist",
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
"node",
|
|
10
10
|
"storage"
|
|
11
11
|
],
|
|
12
|
+
"bin": {
|
|
13
|
+
"make-index": "./scripts/make-index.js"
|
|
14
|
+
},
|
|
12
15
|
"type": "module",
|
|
13
16
|
"homepage": "https://github.com/zen-fs/core",
|
|
14
17
|
"author": "James P. <jp@drvortex.dev> (https://drvortex.dev)",
|
|
@@ -46,6 +49,7 @@
|
|
|
46
49
|
"dependencies": {
|
|
47
50
|
"@types/node": "^14.0.0",
|
|
48
51
|
"@types/readable-stream": "^4.0.10",
|
|
52
|
+
"minimatch": "^9.0.3",
|
|
49
53
|
"readable-stream": "^4.5.2"
|
|
50
54
|
},
|
|
51
55
|
"devDependencies": {
|
package/readme.md
CHANGED
|
@@ -15,7 +15,7 @@ ZenFS is highly extensible, and includes a few built-in backends:
|
|
|
15
15
|
|
|
16
16
|
More backends can be defined by separate libraries, as long as they implement `FileSystem`.
|
|
17
17
|
|
|
18
|
-
ZenFS supports a number of other backends
|
|
18
|
+
ZenFS supports a number of other backends. Many are provided as seperate packages under `@zenfs`.
|
|
19
19
|
|
|
20
20
|
For more information, see the [API documentation for ZenFS](https://zen-fs.github.io/core).
|
|
21
21
|
|
|
@@ -39,7 +39,7 @@ const contents = fs.readFileSync('/test.txt', 'utf-8');
|
|
|
39
39
|
console.log(contents);
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
#### Using different and/or
|
|
42
|
+
#### Using different and/or multiple backends
|
|
43
43
|
|
|
44
44
|
A single `InMemory` backend is created by default, mounted on `/`.
|
|
45
45
|
|
|
@@ -50,7 +50,7 @@ You can use multiple backends by passing an object to `configure` which maps pat
|
|
|
50
50
|
The following example mounts a zip file to `/zip`, in-memory storage to `/tmp`, and IndexedDB to `/home`. Note that `/` has the default in-memory backend.
|
|
51
51
|
|
|
52
52
|
```js
|
|
53
|
-
import { configure } from '@zenfs/core';
|
|
53
|
+
import { configure, InMemory } from '@zenfs/core';
|
|
54
54
|
import { IndexedDB } from '@zenfs/dom';
|
|
55
55
|
import { Zip } from '@zenfs/zip';
|
|
56
56
|
|
|
@@ -58,13 +58,17 @@ const zipData = await (await fetch('mydata.zip')).arrayBuffer();
|
|
|
58
58
|
|
|
59
59
|
await configure({
|
|
60
60
|
'/mnt/zip': { backend: Zip, zipData },
|
|
61
|
-
'/tmp':
|
|
61
|
+
'/tmp': InMemory,
|
|
62
62
|
'/home': IndexedDB,
|
|
63
63
|
};
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
> [!TIP]
|
|
67
|
-
> When configuring a mount point, you can pass in
|
|
67
|
+
> When configuring a mount point, you can pass in
|
|
68
|
+
>
|
|
69
|
+
> 1. A string that maps to a built-in backend
|
|
70
|
+
> 2. A `Backend` object, if the backend has no required options
|
|
71
|
+
> 3. An object that has the options accepted by the backend and a `backend` property which is (1) or (2)
|
|
68
72
|
|
|
69
73
|
Here is an example that mounts the `Storage` backend from `@zenfs/dom` on `/`:
|
|
70
74
|
|
|
@@ -109,13 +113,13 @@ if (!exists) {
|
|
|
109
113
|
You may have noticed that attempting to use a synchronous function on an asynchronous backend (e.g. `IndexedDB`) results in a "not supplied" error (`ENOTSUP`). If you would like to use an asynchronous backend synchronously you need to wrap it in an `AsyncMirror`:
|
|
110
114
|
|
|
111
115
|
```js
|
|
112
|
-
import { configure, fs } from '@zenfs/core';
|
|
116
|
+
import { configure, fs, AsyncMirror, InMemory } from '@zenfs/core';
|
|
113
117
|
import { IndexedDB } from '@zenfs/dom';
|
|
114
118
|
|
|
115
119
|
await configure({
|
|
116
120
|
'/': {
|
|
117
|
-
backend:
|
|
118
|
-
sync:
|
|
121
|
+
backend: AsyncMirror,
|
|
122
|
+
sync: InMemory,
|
|
119
123
|
async: IndexedDB,
|
|
120
124
|
},
|
|
121
125
|
});
|
|
@@ -130,12 +134,12 @@ If you would like to create backends without configure (e.g. to do something dyn
|
|
|
130
134
|
You can then mount and unmount the backend instance by using `mount` and `umount`.
|
|
131
135
|
|
|
132
136
|
```js
|
|
133
|
-
import { configure, createBackend } from '@zenfs/core';
|
|
137
|
+
import { configure, createBackend, InMemory } from '@zenfs/core';
|
|
134
138
|
import { IndexedDB } from '@zenfs/dom';
|
|
135
139
|
import { Zip } from '@zenfs/zip';
|
|
136
140
|
|
|
137
141
|
await configure({
|
|
138
|
-
'/tmp':
|
|
142
|
+
'/tmp': InMemory,
|
|
139
143
|
'/home': IndexedDB,
|
|
140
144
|
};
|
|
141
145
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from 'util';
|
|
3
|
+
import { statSync, readdirSync, writeFileSync } from 'fs';
|
|
4
|
+
import { join } from 'path/posix';
|
|
5
|
+
import { resolve } from 'path';
|
|
6
|
+
import { minimatch } from 'minimatch';
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
values: options,
|
|
10
|
+
positionals: [root],
|
|
11
|
+
} = parseArgs({
|
|
12
|
+
options: {
|
|
13
|
+
help: { short: 'h', type: 'boolean', default: false },
|
|
14
|
+
ignore: { short: 'i', type: 'string', multiple: true, default: [] },
|
|
15
|
+
output: { short: 'o', type: 'string', default: 'index.json' },
|
|
16
|
+
quiet: { short: 'q', type: 'boolean', default: false },
|
|
17
|
+
verbose: { type: 'boolean', default: false },
|
|
18
|
+
},
|
|
19
|
+
allowPositionals: true,
|
|
20
|
+
strict: true,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (options.help) {
|
|
24
|
+
console.log(`make-index <path> [...options]
|
|
25
|
+
path: The path to create a listing for
|
|
26
|
+
|
|
27
|
+
options:
|
|
28
|
+
--help, -h Outputs this help message
|
|
29
|
+
--quiet, -q Do not output messages about individual files
|
|
30
|
+
--verbose Output verbose messages
|
|
31
|
+
|
|
32
|
+
--output, -o <path> Path to the output file. Defaults to listing.
|
|
33
|
+
--ignore, -i <pattern> Ignores files which match the glob <pattern>. Can be passed multiple times.
|
|
34
|
+
`);
|
|
35
|
+
process.exit();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (options.quiet && options.verbose) {
|
|
39
|
+
console.log('Can not use both --verbose and --quiet.');
|
|
40
|
+
process.exit();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function pathToPosix(path) {
|
|
44
|
+
return path.replaceAll('\\', '/');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const colors = {
|
|
48
|
+
reset: 0,
|
|
49
|
+
black: 30,
|
|
50
|
+
red: 31,
|
|
51
|
+
green: 32,
|
|
52
|
+
yellow: 33,
|
|
53
|
+
blue: 34,
|
|
54
|
+
magenta: 35,
|
|
55
|
+
cyan: 36,
|
|
56
|
+
white: 37,
|
|
57
|
+
bright_black: 90,
|
|
58
|
+
bright_red: 91,
|
|
59
|
+
bright_green: 92,
|
|
60
|
+
bright_yellow: 93,
|
|
61
|
+
bright_blue: 94,
|
|
62
|
+
bright_magenta: 95,
|
|
63
|
+
bright_cyan: 96,
|
|
64
|
+
bright_white: 97,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
function color(color, text) {
|
|
68
|
+
return `\x1b[${colors[color]}m${text}\x1b[0m`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function makeListing(path, seen = new Set()) {
|
|
72
|
+
try {
|
|
73
|
+
const stats = statSync(path);
|
|
74
|
+
|
|
75
|
+
if (stats.isFile()) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let entries = {};
|
|
80
|
+
for (const file of readdirSync(path)) {
|
|
81
|
+
const full = join(path, file);
|
|
82
|
+
if (options.ignore.some(pattern => minimatch(full, pattern))) {
|
|
83
|
+
if (!options.quiet) console.log(`${color('yellow', 'skip')} ${full}`);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
entries[file] = makeListing(full, seen);
|
|
88
|
+
}
|
|
89
|
+
return entries;
|
|
90
|
+
} catch (e) {
|
|
91
|
+
if (!options.quiet) {
|
|
92
|
+
console.log(`${color('red', 'fail')} ${path}: ${e.message}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const listing = makeListing(pathToPosix(root));
|
|
98
|
+
if (!options.quiet) console.log('Generated listing for ' + pathToPosix(resolve(root)));
|
|
99
|
+
|
|
100
|
+
writeFileSync(options.output, JSON.stringify(listing));
|
package/dist/backends/index.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { AsyncMirror } from './AsyncMirror.js';
|
|
2
|
-
import { InMemory } from './InMemory.js';
|
|
3
|
-
import { Overlay } from './Overlay.js';
|
|
4
|
-
import { Backend } from './backend.js';
|
|
5
|
-
export declare const backends: {
|
|
6
|
-
[backend: string]: Backend;
|
|
7
|
-
};
|
|
8
|
-
export default backends;
|
|
9
|
-
export { AsyncMirror, InMemory, Overlay };
|
|
10
|
-
export declare function registerBackend(..._backends: Backend[]): void;
|
package/dist/backends/index.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { AsyncMirror } from './AsyncMirror.js';
|
|
2
|
-
import { InMemory } from './InMemory.js';
|
|
3
|
-
import { Overlay } from './Overlay.js';
|
|
4
|
-
export const backends = {};
|
|
5
|
-
export default backends;
|
|
6
|
-
export { AsyncMirror, InMemory, Overlay };
|
|
7
|
-
export function registerBackend(..._backends) {
|
|
8
|
-
for (const backend of _backends) {
|
|
9
|
-
backends[backend.name] = backend;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
registerBackend(AsyncMirror, InMemory, Overlay);
|