@gjsify/fs 0.0.1 → 0.0.2
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 +6 -8
- package/lib/cjs/callback.js +131 -0
- package/lib/cjs/dirent.js +127 -0
- package/lib/cjs/encoding.js +53 -0
- package/lib/cjs/file-handle.js +473 -0
- package/lib/cjs/fs-watcher.js +79 -0
- package/lib/cjs/index.js +95 -0
- package/lib/cjs/promises.js +189 -0
- package/lib/cjs/read-stream.js +107 -0
- package/lib/cjs/stats.js +74 -0
- package/lib/cjs/sync.js +155 -0
- package/lib/cjs/types/encoding-option.js +15 -0
- package/lib/cjs/types/file-read-options.js +15 -0
- package/lib/cjs/types/file-read-result.js +15 -0
- package/lib/cjs/types/flag-and-open-mode.js +15 -0
- package/lib/cjs/types/index.js +22 -0
- package/lib/cjs/types/open-flags.js +15 -0
- package/lib/cjs/types/read-options.js +15 -0
- package/lib/cjs/utils.js +37 -0
- package/lib/cjs/write-stream.js +135 -0
- package/lib/esm/callback.js +112 -0
- package/lib/esm/dirent.js +98 -0
- package/lib/esm/encoding.js +34 -0
- package/lib/esm/file-handle.js +444 -0
- package/lib/esm/fs-watcher.js +50 -0
- package/lib/esm/index.js +95 -0
- package/lib/esm/promises.js +160 -0
- package/lib/esm/read-stream.js +78 -0
- package/lib/esm/stats.js +45 -0
- package/lib/esm/sync.js +126 -0
- package/lib/esm/types/encoding-option.js +0 -0
- package/lib/esm/types/file-read-options.js +0 -0
- package/lib/esm/types/file-read-result.js +0 -0
- package/lib/esm/types/flag-and-open-mode.js +0 -0
- package/lib/esm/types/index.js +6 -0
- package/lib/esm/types/open-flags.js +0 -0
- package/lib/esm/types/read-options.js +0 -0
- package/lib/esm/utils.js +18 -0
- package/lib/esm/write-stream.js +116 -0
- package/package.json +52 -17
- package/src/callback.spec.ts +42 -0
- package/src/callback.ts +362 -0
- package/src/dirent.ts +117 -0
- package/src/encoding.ts +40 -0
- package/src/file-handle.spec.ts +34 -0
- package/src/file-handle.ts +606 -0
- package/{fs-watcher.js → src/fs-watcher.ts} +10 -9
- package/src/index.ts +95 -0
- package/src/promises.spec.ts +172 -0
- package/src/promises.ts +349 -0
- package/src/read-stream.ts +98 -0
- package/src/stat.spec.ts +79 -0
- package/src/stats.ts +106 -0
- package/src/symlink.spec.ts +38 -0
- package/src/sync.spec.ts +205 -0
- package/src/sync.ts +239 -0
- package/src/test.mts +11 -0
- package/src/types/encoding-option.ts +3 -0
- package/src/types/file-read-options.ts +15 -0
- package/src/types/file-read-result.ts +4 -0
- package/src/types/flag-and-open-mode.ts +6 -0
- package/src/types/index.ts +6 -0
- package/src/types/open-flags.ts +14 -0
- package/src/types/read-options.ts +9 -0
- package/src/utils.ts +19 -0
- package/src/write-stream.ts +143 -0
- package/test/file.txt +1 -0
- package/test/watch.js +1 -0
- package/test.gjs.js +35359 -0
- package/test.gjs.js.map +7 -0
- package/test.gjs.mjs +40570 -0
- package/test.gjs.mjs.meta.json +1 -0
- package/test.node.js +1479 -0
- package/test.node.js.map +7 -0
- package/test.node.mjs +710 -0
- package/tsconfig.json +18 -0
- package/tsconfig.types.json +8 -0
- package/index.js +0 -114
- package/test/index.js +0 -90
- package/test/resources/file.txt +0 -1
package/src/index.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
existsSync,
|
|
3
|
+
readdirSync,
|
|
4
|
+
readFileSync,
|
|
5
|
+
writeFileSync,
|
|
6
|
+
mkdirSync,
|
|
7
|
+
rmdirSync,
|
|
8
|
+
unlinkSync,
|
|
9
|
+
watch,
|
|
10
|
+
mkdtempSync,
|
|
11
|
+
rmSync,
|
|
12
|
+
statSync,
|
|
13
|
+
openSync,
|
|
14
|
+
realpathSync,
|
|
15
|
+
symlinkSync,
|
|
16
|
+
lstatSync,
|
|
17
|
+
} from './sync.js';
|
|
18
|
+
import { open,
|
|
19
|
+
close,
|
|
20
|
+
read,
|
|
21
|
+
write,
|
|
22
|
+
rm,
|
|
23
|
+
realpath,
|
|
24
|
+
readdir,
|
|
25
|
+
symlink,
|
|
26
|
+
lstat,
|
|
27
|
+
} from './callback.js';
|
|
28
|
+
import FSWatcher from './fs-watcher.js';
|
|
29
|
+
import {
|
|
30
|
+
createReadStream,
|
|
31
|
+
ReadStream
|
|
32
|
+
} from './read-stream.js';
|
|
33
|
+
import * as promises from './promises.js';
|
|
34
|
+
|
|
35
|
+
export {
|
|
36
|
+
FSWatcher,
|
|
37
|
+
existsSync,
|
|
38
|
+
readdirSync,
|
|
39
|
+
readFileSync,
|
|
40
|
+
writeFileSync,
|
|
41
|
+
mkdirSync,
|
|
42
|
+
rmdirSync,
|
|
43
|
+
unlinkSync,
|
|
44
|
+
mkdtempSync,
|
|
45
|
+
rmSync,
|
|
46
|
+
statSync,
|
|
47
|
+
openSync,
|
|
48
|
+
realpathSync,
|
|
49
|
+
symlinkSync,
|
|
50
|
+
lstatSync,
|
|
51
|
+
watch,
|
|
52
|
+
createReadStream,
|
|
53
|
+
ReadStream,
|
|
54
|
+
promises,
|
|
55
|
+
open,
|
|
56
|
+
close,
|
|
57
|
+
read,
|
|
58
|
+
write,
|
|
59
|
+
rm,
|
|
60
|
+
realpath,
|
|
61
|
+
readdir,
|
|
62
|
+
symlink,
|
|
63
|
+
lstat,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default {
|
|
67
|
+
FSWatcher,
|
|
68
|
+
existsSync,
|
|
69
|
+
readdirSync,
|
|
70
|
+
readFileSync,
|
|
71
|
+
writeFileSync,
|
|
72
|
+
mkdirSync,
|
|
73
|
+
rmdirSync,
|
|
74
|
+
unlinkSync,
|
|
75
|
+
mkdtempSync,
|
|
76
|
+
rmSync,
|
|
77
|
+
statSync,
|
|
78
|
+
openSync,
|
|
79
|
+
realpathSync,
|
|
80
|
+
symlinkSync,
|
|
81
|
+
lstatSync,
|
|
82
|
+
watch,
|
|
83
|
+
createReadStream,
|
|
84
|
+
ReadStream,
|
|
85
|
+
promises,
|
|
86
|
+
open,
|
|
87
|
+
close,
|
|
88
|
+
read,
|
|
89
|
+
write,
|
|
90
|
+
rm,
|
|
91
|
+
realpath,
|
|
92
|
+
readdir,
|
|
93
|
+
symlink,
|
|
94
|
+
lstat,
|
|
95
|
+
};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { describe, it, expect } from '@gjsify/unit';
|
|
2
|
+
import { promises, existsSync } from 'fs';
|
|
3
|
+
import { mkdir, readdir, mkdtemp, writeFile, rm, rmdir } from 'fs/promises';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { Buffer } from 'buffer';
|
|
6
|
+
|
|
7
|
+
export default async () => {
|
|
8
|
+
|
|
9
|
+
await describe('fs/promises', async () => {
|
|
10
|
+
await it('import over "fs/should" should be work', async () => {
|
|
11
|
+
expect(typeof mkdir).toBe("function");
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
await describe('fs.promises.readdir', async () => {
|
|
16
|
+
await it('should return no files for an empty directory', async () => {
|
|
17
|
+
const dir = await mkdtemp('fs-test-');
|
|
18
|
+
const files = await readdir(dir);
|
|
19
|
+
expect(files.length).toBe(0);
|
|
20
|
+
|
|
21
|
+
// Clear
|
|
22
|
+
await rmdir(dir);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
await it('should return the files for non-empty directory', async () => {
|
|
26
|
+
const dir = await mkdtemp('fs-test-');
|
|
27
|
+
const txt1 = join(dir, 'test1.txt');
|
|
28
|
+
const txt2 = join(dir, 'test2.txt');
|
|
29
|
+
const dir1 = join(dir, 'empty-dir');
|
|
30
|
+
await writeFile(txt1, '');
|
|
31
|
+
await writeFile(txt2, '');
|
|
32
|
+
await mkdir(dir1);
|
|
33
|
+
const files = await readdir(dir);
|
|
34
|
+
expect(files.length).toEqual(3);
|
|
35
|
+
|
|
36
|
+
// Clear
|
|
37
|
+
await rm(txt1);
|
|
38
|
+
await rm(txt2);
|
|
39
|
+
await rmdir(dir1);
|
|
40
|
+
await rmdir(dir);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
await it('should return the file with the name "file.txt"', async () => {
|
|
44
|
+
const dir = await mkdtemp('fs-test-');
|
|
45
|
+
const expectedFileName = 'file.txt';
|
|
46
|
+
const file = join(dir, expectedFileName);
|
|
47
|
+
|
|
48
|
+
await writeFile(file, '');
|
|
49
|
+
|
|
50
|
+
const files = await readdir(dir);
|
|
51
|
+
expect(files[0]).toEqual(expectedFileName);
|
|
52
|
+
|
|
53
|
+
// Clear
|
|
54
|
+
await rm(file);
|
|
55
|
+
await rmdir(dir);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
await it('should return with file types if option "withFileTypes" is `true`', async () => {
|
|
59
|
+
const dir = await mkdtemp('fs-test-');
|
|
60
|
+
const expectedFile = 'file.txt';
|
|
61
|
+
const expectedDir = 'subdir';
|
|
62
|
+
const file = join(dir, expectedFile);
|
|
63
|
+
const subdir = join(dir, expectedDir);
|
|
64
|
+
|
|
65
|
+
await writeFile(file, '');
|
|
66
|
+
await mkdir(subdir);
|
|
67
|
+
|
|
68
|
+
const files = await readdir(dir, { withFileTypes: true });
|
|
69
|
+
|
|
70
|
+
expect(files.length).toBe(2);
|
|
71
|
+
|
|
72
|
+
const fileWithTypes = files.find((f) => f.name === expectedFile);
|
|
73
|
+
const dirWithTypes = files.find((f) => f.name === expectedDir);
|
|
74
|
+
|
|
75
|
+
expect(fileWithTypes.isFile()).toBeTruthy();
|
|
76
|
+
expect(fileWithTypes.isDirectory()).toBeFalsy();
|
|
77
|
+
|
|
78
|
+
expect(dirWithTypes.isFile()).toBeFalsy();
|
|
79
|
+
expect(dirWithTypes.isDirectory()).toBeTruthy();
|
|
80
|
+
|
|
81
|
+
// Clear
|
|
82
|
+
await rm(file);
|
|
83
|
+
await rmdir(subdir);
|
|
84
|
+
await rmdir(dir);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
await describe('fs.promises.readFile', async () => {
|
|
89
|
+
|
|
90
|
+
await it('should be a function', async () => {
|
|
91
|
+
expect(typeof promises.readFile).toBe("function");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
await it('should be a promise', async () => {
|
|
95
|
+
expect(promises.readFile('./test/file.txt', 'utf-8') instanceof Promise).toBeTruthy();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
await it('should return a Buffer if no encoding was specified', async () => {
|
|
99
|
+
const bufferData = await promises.readFile('package.json');
|
|
100
|
+
expect(bufferData instanceof Buffer).toBeTruthy();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
await it('should return a string when encoding is utf-8', async () => {
|
|
104
|
+
const utf8Data = await promises.readFile('./test/file.txt', 'utf-8');
|
|
105
|
+
expect(typeof utf8Data === 'string').toBeTruthy();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
await it('should return a string with "Hello World"', async () => {
|
|
109
|
+
const utf8Data = await promises.readFile('./test/file.txt', 'utf-8');
|
|
110
|
+
expect(utf8Data).toBe('Hello World');
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
await describe('fs.promises.mkdtemp', async () => {
|
|
115
|
+
await it('should be a function', async () => {
|
|
116
|
+
expect(typeof promises.mkdtemp).toBe("function");
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
await it('should create a new directory', async () => {
|
|
120
|
+
const directory = await promises.mkdtemp('fs-test-');
|
|
121
|
+
expect(existsSync(directory)).toBeTruthy();
|
|
122
|
+
await promises.rmdir(directory);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
await describe('fs.promises.rm', async () => {
|
|
127
|
+
await it('should be a function', async () => {
|
|
128
|
+
expect(typeof promises.rm).toBe("function");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
await it('should remove an text file', async () => {
|
|
132
|
+
|
|
133
|
+
const dir = await promises.mkdtemp('fs-test-');
|
|
134
|
+
const txt1 = join(dir, 'file1.txt');
|
|
135
|
+
await promises.writeFile(txt1, '');
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
expect(existsSync(txt1)).toBeTruthy();
|
|
139
|
+
await promises.rm(txt1);
|
|
140
|
+
expect(existsSync(txt1)).toBeFalsy();
|
|
141
|
+
|
|
142
|
+
// Clear
|
|
143
|
+
await promises.rmdir(dir);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
await it('should not remove an non-empty folder if recursive option is false and should remove an non-empty folder if recursive option is true', async () => {
|
|
147
|
+
|
|
148
|
+
const dir = await promises.mkdtemp('fs-test-');
|
|
149
|
+
|
|
150
|
+
await promises.writeFile(join(dir, "file1.txt"), "");
|
|
151
|
+
await promises.writeFile(join(dir, "file2.txt"), "");
|
|
152
|
+
await promises.mkdir(join(dir, "some_dir"));
|
|
153
|
+
await promises.mkdir(join(dir, "some_dir", "file.txt"));
|
|
154
|
+
|
|
155
|
+
expect(existsSync(dir)).toBeTruthy();
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
await promises.rm(dir, { recursive: false });
|
|
159
|
+
} catch (error) {
|
|
160
|
+
expect(error).toBeDefined();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Dir should still exists because recursive was `false`
|
|
164
|
+
expect(existsSync(dir)).toBeTruthy();
|
|
165
|
+
|
|
166
|
+
await promises.rm(dir, { recursive: true });
|
|
167
|
+
|
|
168
|
+
// Dir should not exists anymore because recursive was `true`
|
|
169
|
+
expect(existsSync(dir)).toBeFalsy();
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
}
|
package/src/promises.ts
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import Gio from '@girs/gio-2.0';
|
|
2
|
+
import GLib from '@girs/glib-2.0';
|
|
3
|
+
import { warnNotImplemented } from '@gjsify/utils';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { getEncodingFromOptions, encodeUint8Array, decode } from './encoding.js';
|
|
6
|
+
import { writeFileSync, mkdirSync, rmdirSync, unlinkSync } from './sync.js';
|
|
7
|
+
import { FileHandle } from './file-handle.js';
|
|
8
|
+
import { tempDirPath } from './utils.js';
|
|
9
|
+
import { Dirent } from './dirent.js';
|
|
10
|
+
|
|
11
|
+
import { realpathPromise as realpath } from '@gjsify/deno_std/node/_fs/_fs_realpath';
|
|
12
|
+
import { readdirPromise as readdir } from '@gjsify/deno_std/node/_fs/_fs_readdir';
|
|
13
|
+
import { symlinkPromise as symlink } from '@gjsify/deno_std/node/_fs/_fs_symlink';
|
|
14
|
+
import { lstatPromise as lstat } from '@gjsify/deno_std/node/_fs/_fs_lstat';
|
|
15
|
+
import { statPromise as stat } from '@gjsify/deno_std/node/_fs/_fs_stat';
|
|
16
|
+
|
|
17
|
+
import type {
|
|
18
|
+
OpenFlags,
|
|
19
|
+
ReadOptions,
|
|
20
|
+
} from './types/index.js';
|
|
21
|
+
import type {
|
|
22
|
+
PathLike,
|
|
23
|
+
Mode,
|
|
24
|
+
RmOptions,
|
|
25
|
+
ObjectEncodingOptions,
|
|
26
|
+
BufferEncodingOption,
|
|
27
|
+
MakeDirectoryOptions,
|
|
28
|
+
RmDirOptions
|
|
29
|
+
} from 'fs';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Asynchronously creates a directory.
|
|
33
|
+
*
|
|
34
|
+
* The optional `options` argument can be an integer specifying `mode` (permission
|
|
35
|
+
* and sticky bits), or an object with a `mode` property and a `recursive`property indicating whether parent directories should be created. Calling`fsPromises.mkdir()` when `path` is a directory
|
|
36
|
+
* that exists results in a
|
|
37
|
+
* rejection only when `recursive` is false.
|
|
38
|
+
* @since v10.0.0
|
|
39
|
+
* @return Upon success, fulfills with `undefined` if `recursive` is `false`, or the first directory path created if `recursive` is `true`.
|
|
40
|
+
*/
|
|
41
|
+
async function mkdir(
|
|
42
|
+
path: PathLike,
|
|
43
|
+
options: MakeDirectoryOptions & {
|
|
44
|
+
recursive: true;
|
|
45
|
+
}
|
|
46
|
+
): Promise<string | undefined>;
|
|
47
|
+
/**
|
|
48
|
+
* Asynchronous mkdir(2) - create a directory.
|
|
49
|
+
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
|
50
|
+
* @param options Either the file mode, or an object optionally specifying the file mode and whether parent folders
|
|
51
|
+
* should be created. If a string is passed, it is parsed as an octal integer. If not specified, defaults to `0o777`.
|
|
52
|
+
*/
|
|
53
|
+
async function mkdir(
|
|
54
|
+
path: PathLike,
|
|
55
|
+
options?:
|
|
56
|
+
| Mode
|
|
57
|
+
| (MakeDirectoryOptions & {
|
|
58
|
+
recursive?: false | undefined;
|
|
59
|
+
})
|
|
60
|
+
| null
|
|
61
|
+
): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Asynchronous mkdir(2) - create a directory.
|
|
64
|
+
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
|
65
|
+
* @param options Either the file mode, or an object optionally specifying the file mode and whether parent folders
|
|
66
|
+
* should be created. If a string is passed, it is parsed as an octal integer. If not specified, defaults to `0o777`.
|
|
67
|
+
*/
|
|
68
|
+
async function mkdir(path: PathLike, options?: Mode | MakeDirectoryOptions | null): Promise<string | undefined>
|
|
69
|
+
|
|
70
|
+
async function mkdir(path: PathLike, options?: Mode | MakeDirectoryOptions | null): Promise<string | undefined | void> {
|
|
71
|
+
|
|
72
|
+
let recursive: boolean | undefined;
|
|
73
|
+
let mode: Mode | undefined = 0o777;
|
|
74
|
+
|
|
75
|
+
if (typeof options === 'object') {
|
|
76
|
+
if(options.recursive) recursive = options.recursive;
|
|
77
|
+
if(options.mode) mode = options.mode
|
|
78
|
+
} else {
|
|
79
|
+
mode = options;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// TODO async
|
|
83
|
+
const firstPath = mkdirSync(path, {
|
|
84
|
+
recursive,
|
|
85
|
+
mode
|
|
86
|
+
});
|
|
87
|
+
return firstPath;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function readFile(path: PathLike | FileHandle, options: ReadOptions = { encoding: null, flag: 'r' }) {
|
|
91
|
+
const file = Gio.File.new_for_path(path.toString());
|
|
92
|
+
|
|
93
|
+
const [ok, data] = await new Promise<[boolean, Uint8Array, string]>((resolve, reject) => {
|
|
94
|
+
file.load_contents_async(null, (self, res) => {
|
|
95
|
+
try {
|
|
96
|
+
resolve(file.load_contents_finish(res));
|
|
97
|
+
} catch (error) {
|
|
98
|
+
reject(error);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
if (!ok) {
|
|
104
|
+
// TODO: throw a better error
|
|
105
|
+
throw new Error('failed to read file');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return encodeUint8Array(getEncodingFromOptions(options, 'buffer'), data);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Creates a unique temporary directory. A unique directory name is generated by
|
|
113
|
+
* appending six random characters to the end of the provided `prefix`. Due to
|
|
114
|
+
* platform inconsistencies, avoid trailing `X` characters in `prefix`. Some
|
|
115
|
+
* platforms, notably the BSDs, can return more than six random characters, and
|
|
116
|
+
* replace trailing `X` characters in `prefix` with random characters.
|
|
117
|
+
*
|
|
118
|
+
* The optional `options` argument can be a string specifying an encoding, or an
|
|
119
|
+
* object with an `encoding` property specifying the character encoding to use.
|
|
120
|
+
*
|
|
121
|
+
* ```js
|
|
122
|
+
* import { mkdtemp } from 'fs/promises';
|
|
123
|
+
*
|
|
124
|
+
* try {
|
|
125
|
+
* await mkdtemp(path.join(os.tmpdir(), 'foo-'));
|
|
126
|
+
* } catch (err) {
|
|
127
|
+
* console.error(err);
|
|
128
|
+
* }
|
|
129
|
+
* ```
|
|
130
|
+
*
|
|
131
|
+
* The `fsPromises.mkdtemp()` method will append the six randomly selected
|
|
132
|
+
* characters directly to the `prefix` string. For instance, given a directory`/tmp`, if the intention is to create a temporary directory _within_`/tmp`, the`prefix` must end with a trailing
|
|
133
|
+
* platform-specific path separator
|
|
134
|
+
* (`require('path').sep`).
|
|
135
|
+
* @since v10.0.0
|
|
136
|
+
* @return Fulfills with a string containing the filesystem path of the newly created temporary directory.
|
|
137
|
+
*/
|
|
138
|
+
async function mkdtemp(prefix: string, options?: ObjectEncodingOptions | BufferEncoding | null): Promise<string>;
|
|
139
|
+
/**
|
|
140
|
+
* Asynchronously creates a unique temporary directory.
|
|
141
|
+
* Generates six random characters to be appended behind a required `prefix` to create a unique temporary directory.
|
|
142
|
+
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
|
|
143
|
+
*/
|
|
144
|
+
async function mkdtemp(prefix: string, options: BufferEncodingOption): Promise<Buffer>;
|
|
145
|
+
/**
|
|
146
|
+
* Asynchronously creates a unique temporary directory.
|
|
147
|
+
* Generates six random characters to be appended behind a required `prefix` to create a unique temporary directory.
|
|
148
|
+
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
|
|
149
|
+
*/
|
|
150
|
+
async function mkdtemp(prefix: string, options?: ObjectEncodingOptions | BufferEncoding | null): Promise<string | Buffer>;
|
|
151
|
+
|
|
152
|
+
async function mkdtemp(prefix: string, options?: BufferEncodingOption | ObjectEncodingOptions | BufferEncoding | null): Promise<string | Buffer> {
|
|
153
|
+
const encoding: string | undefined = getEncodingFromOptions(options);
|
|
154
|
+
const path = tempDirPath(prefix);
|
|
155
|
+
|
|
156
|
+
await mkdir(
|
|
157
|
+
path,
|
|
158
|
+
{ recursive: false, mode: 0o700 }
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
return decode(path, encoding);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function writeFile(path: string, data: any) {
|
|
165
|
+
// TODO async
|
|
166
|
+
return writeFileSync(path, data);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Removes the directory identified by `path`.
|
|
171
|
+
*
|
|
172
|
+
* Using `fsPromises.rmdir()` on a file (not a directory) results in the
|
|
173
|
+
* promise being rejected with an `ENOENT` error on Windows and an `ENOTDIR`error on POSIX.
|
|
174
|
+
*
|
|
175
|
+
* To get a behavior similar to the `rm -rf` Unix command, use `fsPromises.rm()` with options `{ recursive: true, force: true }`.
|
|
176
|
+
* @since v10.0.0
|
|
177
|
+
* @return Fulfills with `undefined` upon success.
|
|
178
|
+
*/
|
|
179
|
+
async function rmdir(path: PathLike, options?: RmDirOptions): Promise<void> {
|
|
180
|
+
// TODO async
|
|
181
|
+
return rmdirSync(path, options);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async function unlink(path: string) {
|
|
185
|
+
// TODO async
|
|
186
|
+
return unlinkSync(path);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function open(path: PathLike, flags?: OpenFlags, mode?: Mode): Promise<FileHandle> {
|
|
190
|
+
return new FileHandle({
|
|
191
|
+
path,
|
|
192
|
+
flags,
|
|
193
|
+
mode,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function write<TBuffer extends Uint8Array>(
|
|
198
|
+
fd: number,
|
|
199
|
+
buffer: TBuffer,
|
|
200
|
+
offset?: number | null,
|
|
201
|
+
length?: number | null,
|
|
202
|
+
position?: number | null
|
|
203
|
+
): Promise<{
|
|
204
|
+
bytesWritten: number;
|
|
205
|
+
buffer: TBuffer;
|
|
206
|
+
}>
|
|
207
|
+
|
|
208
|
+
async function write(
|
|
209
|
+
fd: number,
|
|
210
|
+
data: string,
|
|
211
|
+
position?: number | null,
|
|
212
|
+
encoding?: BufferEncoding | null
|
|
213
|
+
): Promise<{
|
|
214
|
+
bytesWritten: number;
|
|
215
|
+
buffer: string;
|
|
216
|
+
}>
|
|
217
|
+
|
|
218
|
+
async function write<TBuffer extends Uint8Array>(
|
|
219
|
+
fd: number,
|
|
220
|
+
data: string | TBuffer,
|
|
221
|
+
positionOrOffset?: number | null,
|
|
222
|
+
encodingOrLength?: BufferEncoding | null | number,
|
|
223
|
+
position?: number | null
|
|
224
|
+
): Promise<{
|
|
225
|
+
bytesWritten: number;
|
|
226
|
+
buffer: string;
|
|
227
|
+
}> {
|
|
228
|
+
if(typeof data === 'string') {
|
|
229
|
+
return _writeStr(fd, data, positionOrOffset, encodingOrLength as BufferEncoding | null);
|
|
230
|
+
}
|
|
231
|
+
return _writeBuf<any>(fd, data, positionOrOffset as number | null, encodingOrLength as null | number, position);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function _writeBuf<TBuffer extends Uint8Array>(
|
|
235
|
+
fd: number,
|
|
236
|
+
buffer: TBuffer,
|
|
237
|
+
offset?: number | null,
|
|
238
|
+
length?: number | null,
|
|
239
|
+
position?: number | null
|
|
240
|
+
): Promise<{
|
|
241
|
+
bytesWritten: number;
|
|
242
|
+
buffer: TBuffer;
|
|
243
|
+
}> {
|
|
244
|
+
warnNotImplemented("fs.promises.write");
|
|
245
|
+
return {
|
|
246
|
+
bytesWritten: 0,
|
|
247
|
+
buffer
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async function _writeStr(
|
|
252
|
+
fd: number,
|
|
253
|
+
data: string,
|
|
254
|
+
position?: number | null,
|
|
255
|
+
encoding?: BufferEncoding | null
|
|
256
|
+
): Promise<{
|
|
257
|
+
bytesWritten: number;
|
|
258
|
+
buffer: string;
|
|
259
|
+
}> {
|
|
260
|
+
warnNotImplemented("fs.promises.write");
|
|
261
|
+
return {
|
|
262
|
+
bytesWritten: 0,
|
|
263
|
+
buffer: data,
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Removes files and directories (modeled on the standard POSIX `rm` utility).
|
|
269
|
+
* @since v14.14.0
|
|
270
|
+
* @return Fulfills with `undefined` upon success.
|
|
271
|
+
*/
|
|
272
|
+
async function rm(path: PathLike, options?: RmOptions): Promise<void> {
|
|
273
|
+
const file = Gio.File.new_for_path(path.toString());
|
|
274
|
+
|
|
275
|
+
const recursive = options?.recursive || false;
|
|
276
|
+
|
|
277
|
+
const dirent = new Dirent(path.toString());
|
|
278
|
+
|
|
279
|
+
if (dirent.isDirectory()) {
|
|
280
|
+
const childFiles = await readdir(path, { withFileTypes: true });
|
|
281
|
+
|
|
282
|
+
if (!recursive && childFiles.length) {
|
|
283
|
+
throw new Error('Dir is not empty!');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
for (const childFile of childFiles) {
|
|
287
|
+
if (childFile.isDirectory()) {
|
|
288
|
+
await rmdir(join(path.toString(), childFile.name), options);
|
|
289
|
+
} else if (childFile.isFile()) {
|
|
290
|
+
await rm(join(path.toString(), childFile.name), options);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const ok = await new Promise<boolean>((resolve, reject) => {
|
|
296
|
+
try {
|
|
297
|
+
file.delete_async(GLib.PRIORITY_DEFAULT, null, (self, res) => {
|
|
298
|
+
try {
|
|
299
|
+
resolve(file.delete_finish(res));
|
|
300
|
+
} catch (error) {
|
|
301
|
+
reject(error);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
} catch (error) {
|
|
305
|
+
reject(error);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
if (!ok) {
|
|
311
|
+
// TODO: throw a better error
|
|
312
|
+
const err = new Error('failed to remove file ' + path);
|
|
313
|
+
throw err;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export {
|
|
318
|
+
readFile,
|
|
319
|
+
mkdir,
|
|
320
|
+
mkdtemp,
|
|
321
|
+
realpath,
|
|
322
|
+
readdir,
|
|
323
|
+
writeFile,
|
|
324
|
+
rmdir,
|
|
325
|
+
unlink,
|
|
326
|
+
open,
|
|
327
|
+
write,
|
|
328
|
+
rm,
|
|
329
|
+
lstat,
|
|
330
|
+
symlink,
|
|
331
|
+
stat,
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
export default {
|
|
335
|
+
readFile,
|
|
336
|
+
mkdir,
|
|
337
|
+
mkdtemp,
|
|
338
|
+
realpath,
|
|
339
|
+
readdir,
|
|
340
|
+
writeFile,
|
|
341
|
+
rmdir,
|
|
342
|
+
unlink,
|
|
343
|
+
open,
|
|
344
|
+
write,
|
|
345
|
+
rm,
|
|
346
|
+
lstat,
|
|
347
|
+
symlink,
|
|
348
|
+
stat,
|
|
349
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Credits https://github.com/denoland/deno_std/blob/main/node/_fs/_fs_streams.ts
|
|
2
|
+
import GLib from '@girs/glib-2.0';
|
|
3
|
+
import { notImplemented } from "@gjsify/utils";
|
|
4
|
+
import { Buffer } from "buffer";
|
|
5
|
+
import { Readable } from "stream";
|
|
6
|
+
import { URL } from "url";
|
|
7
|
+
|
|
8
|
+
import type { CreateReadStreamOptions } from 'fs/promises'; // Types from @types/node
|
|
9
|
+
import type { PathLike, ReadStream as IReadStream } from 'fs'; // Types from @types/node
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Converts a file URL to a path string.
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { fromFileUrl } from "./posix.ts";
|
|
16
|
+
* fromFileUrl("file:///home/foo"); // "/home/foo"
|
|
17
|
+
* ```
|
|
18
|
+
* @param url of a file URL
|
|
19
|
+
* @credits https://github.com/denoland/deno_std/blob/44d05e7a8d445888d989d49eb3e59eee3055f2c5/node/path/posix.ts#L486
|
|
20
|
+
*/
|
|
21
|
+
export function fromFileUrl(url: string | URL): string {
|
|
22
|
+
url = url instanceof URL ? url : new URL(url);
|
|
23
|
+
if (url.protocol != "file:") {
|
|
24
|
+
throw new TypeError("Must be a file URL.");
|
|
25
|
+
}
|
|
26
|
+
return decodeURIComponent(
|
|
27
|
+
url.pathname.replace(/%(?![0-9A-Fa-f]{2})/g, "%25"),
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class ReadStream extends Readable implements IReadStream {
|
|
32
|
+
close(callback?: (err?: NodeJS.ErrnoException | null) => void): void {
|
|
33
|
+
// TODO
|
|
34
|
+
callback(notImplemented('ReadStream.close'));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The number of bytes that have been read so far.
|
|
38
|
+
* @since v6.4.0
|
|
39
|
+
*/
|
|
40
|
+
bytesRead: number;
|
|
41
|
+
/**
|
|
42
|
+
* The path to the file the stream is reading from as specified in the first
|
|
43
|
+
* argument to `fs.createReadStream()`. If `path` is passed as a string, then`readStream.path` will be a string. If `path` is passed as a `Buffer`, then`readStream.path` will be a
|
|
44
|
+
* `Buffer`. If `fd` is specified, then`readStream.path` will be `undefined`.
|
|
45
|
+
* @since v0.1.93
|
|
46
|
+
*/
|
|
47
|
+
path: string | Buffer;
|
|
48
|
+
/**
|
|
49
|
+
* This property is `true` if the underlying file has not been opened yet,
|
|
50
|
+
* i.e. before the `'ready'` event is emitted.
|
|
51
|
+
* @since v11.2.0, v10.16.0
|
|
52
|
+
*/
|
|
53
|
+
pending: boolean;
|
|
54
|
+
|
|
55
|
+
constructor(path: PathLike, opts?: CreateReadStreamOptions) {
|
|
56
|
+
path = path instanceof URL ? fromFileUrl(path) : path;
|
|
57
|
+
const hasBadOptions = opts && (
|
|
58
|
+
opts.start || opts.end
|
|
59
|
+
);
|
|
60
|
+
if (hasBadOptions) {
|
|
61
|
+
notImplemented(
|
|
62
|
+
`fs.ReadStream.prototype.constructor with unsupported options (${
|
|
63
|
+
JSON.stringify(opts)
|
|
64
|
+
})`,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
const file = GLib.IOChannel.new_file(path.toString(), "r")
|
|
68
|
+
const buffer = "";
|
|
69
|
+
super({
|
|
70
|
+
autoDestroy: true,
|
|
71
|
+
emitClose: true,
|
|
72
|
+
objectMode: false,
|
|
73
|
+
read: async function (_size) {
|
|
74
|
+
try {
|
|
75
|
+
let n = 0
|
|
76
|
+
file.read(buffer, 16 * 1024, n);
|
|
77
|
+
this.push(n ? Buffer.from(buffer.slice(0, n)) : null);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
this.destroy(err as Error);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
destroy: (err, cb) => {
|
|
83
|
+
try {
|
|
84
|
+
file.close();
|
|
85
|
+
} catch {}
|
|
86
|
+
cb(err);
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
this.path = path.toString();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function createReadStream(
|
|
94
|
+
path: string | URL,
|
|
95
|
+
options?: CreateReadStreamOptions,
|
|
96
|
+
): ReadStream {
|
|
97
|
+
return new ReadStream(path, options);
|
|
98
|
+
}
|