@impactor/nodejs 3.0.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.
package/src/fs-sync.js ADDED
@@ -0,0 +1,212 @@
1
+ import {
2
+ resolve as _resolve,
3
+ basename,
4
+ dirname,
5
+ extname,
6
+ join,
7
+ normalize,
8
+ sep
9
+ } from "node:path";
10
+ import { objectType } from "@impactor/javascript";
11
+ import {
12
+ existsSync,
13
+ lstatSync,
14
+ renameSync,
15
+ readdirSync,
16
+ unlinkSync,
17
+ rmdirSync,
18
+ writeFileSync,
19
+ mkdirSync as _mkdirSync,
20
+ readFileSync,
21
+ copyFileSync
22
+ } from "node:fs";
23
+ import { cleanJson } from "@impactor/javascript";
24
+ function resolve(...paths) {
25
+ let stringPaths = paths.filter(Boolean).map((path) => path instanceof URL ? path.pathname : path.toString());
26
+ return _resolve(normalize(join(...stringPaths)));
27
+ }
28
+ function parsePath(path) {
29
+ path = path.toString();
30
+ let extension = getExtensionSync(path);
31
+ return {
32
+ type: isDirSync(path) ? "dir" : "file",
33
+ // path of the containing dir
34
+ dir: dirname(path),
35
+ // basename (file or folder name) without extension
36
+ name: basename(path, `.${extension}`),
37
+ extension
38
+ };
39
+ }
40
+ function getExtensionSync(file) {
41
+ return extname(file.toString()).toLowerCase().replace(/^\./, "");
42
+ }
43
+ function getSizeSync(path, unit = "b", filter) {
44
+ let units = { b: 0, kb: 1, mb: 2, gb: 3 };
45
+ let sizes = recursiveSync(
46
+ path,
47
+ (_path, type) => type === "file" ? lstatSync(_path).size / 1024 ** units[unit] : void 0,
48
+ filter
49
+ );
50
+ let sum = (sizes2) => {
51
+ let total = 0;
52
+ for (let size of sizes2) {
53
+ total += Array.isArray(size) ? sum(size) : size;
54
+ }
55
+ return total;
56
+ };
57
+ return Array.isArray(sizes) ? sum(sizes) : sizes;
58
+ }
59
+ function isDirSync(path) {
60
+ path = resolve(path);
61
+ return existsSync(path) && lstatSync(path).isDirectory();
62
+ }
63
+ function getModifiedTimeSync(path) {
64
+ return lstatSync(resolve(path)).mtimeMs;
65
+ }
66
+ function mkdirSync(path, mode = 511) {
67
+ if (Array.isArray(path)) {
68
+ return path.forEach((p) => {
69
+ mkdirSync(p, mode);
70
+ });
71
+ }
72
+ let options = { mode, recursive: true };
73
+ if (!existsSync(path)) {
74
+ _mkdirSync(path, options);
75
+ }
76
+ }
77
+ var MoveOptionsExisting = /* @__PURE__ */ ((MoveOptionsExisting2) => {
78
+ MoveOptionsExisting2[MoveOptionsExisting2["replace"] = 0] = "replace";
79
+ MoveOptionsExisting2[MoveOptionsExisting2["rename"] = 1] = "rename";
80
+ MoveOptionsExisting2[MoveOptionsExisting2["skip"] = 2] = "skip";
81
+ MoveOptionsExisting2[MoveOptionsExisting2["stop"] = 3] = "stop";
82
+ MoveOptionsExisting2[MoveOptionsExisting2["throw"] = 4] = "throw";
83
+ return MoveOptionsExisting2;
84
+ })(MoveOptionsExisting || {});
85
+ function moveSync(path, newPath, _options) {
86
+ return renameSync(path, newPath);
87
+ }
88
+ function removeSync(path, filter, keepDir = false) {
89
+ return recursiveSync(
90
+ path,
91
+ (file, type) => type === "file" ? unlinkSync(file) : keepDir ? void 0 : rmdirSync(file),
92
+ filter
93
+ );
94
+ }
95
+ function copySync(source, destination, filter = () => true) {
96
+ source = resolve(source);
97
+ destination = resolve(destination);
98
+ return recursiveSync(source, (path, type) => {
99
+ if (type === "file" && filter(path)) {
100
+ let destination_ = path.replace(source.toString(), destination);
101
+ mkdirSync(dirname(destination_));
102
+ copyFileSync(path, destination_);
103
+ }
104
+ });
105
+ }
106
+ function writeSync(path, data, options) {
107
+ path = resolve(path);
108
+ mkdirSync(dirname(path));
109
+ let dataString = ["array", "object"].includes(objectType(data)) ? JSON.stringify(data, null, 2) : data;
110
+ return writeFileSync(path, dataString, options);
111
+ }
112
+ function readSync(path, options) {
113
+ path = resolve(path);
114
+ let opts = {
115
+ encoding: null,
116
+ flag: "r",
117
+ maxAge: 0,
118
+ ...typeof options === "string" ? { encoding: options } : options
119
+ };
120
+ if (opts.maxAge && opts.maxAge > 0 && getModifiedTimeSync(path) + opts.maxAge * 1e3 < Date.now()) {
121
+ throw new Error(`[fs-sync] expired file ${path}`);
122
+ }
123
+ let data = readFileSync(path, {
124
+ encoding: opts.encoding,
125
+ flag: opts.flag
126
+ });
127
+ if (opts.encoding === void 0) {
128
+ return data;
129
+ }
130
+ data = data.toString();
131
+ return path.toString().trim().slice(-5) === ".json" ? JSON.parse(cleanJson(data)) : data;
132
+ }
133
+ function stripComments(content) {
134
+ return content.replaceAll(/(\/\/|#).*|\/\*(.|\n)*\*\//g, "");
135
+ }
136
+ function getEntriesSync(dir = ".", filter, depth, skip) {
137
+ if (Array.isArray(dir)) {
138
+ return dir.flatMap((el) => getEntriesSync(el, filter, depth));
139
+ }
140
+ dir = resolve(dir);
141
+ let filterFunction = filter === "files" ? (entry) => lstatSync(entry).isFile() : filter === "dirs" ? (entry) => lstatSync(entry).isDirectory() : filter instanceof RegExp ? (entry) => filter.test(entry) : typeof filter === "function" ? filter : void 0;
142
+ let skipFunction = skip instanceof RegExp ? (entry) => skip.test(entry) : typeof skip === "function" ? skip : (entry) => ["node_modules", "dist"].includes(entry);
143
+ let entries = readdirSync(dir);
144
+ let result = [];
145
+ for (let entry of entries) {
146
+ let fullPath = join(dir, entry);
147
+ if (!filterFunction || filterFunction?.(fullPath)) {
148
+ result.push(fullPath);
149
+ }
150
+ if ((depth === void 0 || depth > 0) && lstatSync(fullPath).isDirectory() && !skipFunction?.(entry)) {
151
+ let subEntries = getEntriesSync(
152
+ fullPath,
153
+ filterFunction,
154
+ depth === void 0 ? void 0 : depth - 1
155
+ );
156
+ result = [...result, ...subEntries];
157
+ }
158
+ }
159
+ return result;
160
+ }
161
+ function recursiveSync(path, apply, filter = () => true) {
162
+ if (!path) {
163
+ throw new Error("path not provided");
164
+ }
165
+ if (Array.isArray(path)) {
166
+ return path.map((p) => recursiveSync(p, apply, filter));
167
+ }
168
+ path = resolve(path.toString());
169
+ if (!existsSync(path)) {
170
+ return;
171
+ }
172
+ let result = [];
173
+ if (isDirSync(path)) {
174
+ if (filter(path, "dir")) {
175
+ readdirSync(path).forEach((file) => {
176
+ result.push(recursiveSync(`${path}/${file}`, apply, filter));
177
+ });
178
+ apply(path, "dir");
179
+ }
180
+ } else if (filter(path, "file")) {
181
+ return apply(path, "file");
182
+ }
183
+ return result;
184
+ }
185
+ function toPosix(path, removeDriverLetter = true) {
186
+ let newPath = path.toString().replaceAll("\\", "/");
187
+ return removeDriverLetter ? newPath.replace(/^[A-Za-z]:/, "") : newPath;
188
+ }
189
+ function validFilePath(path) {
190
+ let pathResolved = resolve(path), driverLetter = pathResolved.match(/^[A-Za-z]:/)?.[0] || "", filePath = pathResolved.split(/^[A-Za-z]:/)?.[1] || pathResolved;
191
+ return driverLetter + filePath.split(sep).map((part) => encodeURIComponent(part.trim())).join(sep);
192
+ }
193
+ export {
194
+ MoveOptionsExisting,
195
+ copySync,
196
+ getEntriesSync,
197
+ getExtensionSync,
198
+ getModifiedTimeSync,
199
+ getSizeSync,
200
+ isDirSync,
201
+ mkdirSync,
202
+ moveSync,
203
+ parsePath,
204
+ readSync,
205
+ recursiveSync,
206
+ removeSync,
207
+ resolve,
208
+ stripComments,
209
+ toPosix,
210
+ validFilePath,
211
+ writeSync
212
+ };
@@ -0,0 +1,262 @@
1
+ import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
2
+ import {
3
+ copySync,
4
+ getEntriesSync,
5
+ getExtensionSync,
6
+ getModifiedTimeSync,
7
+ getSizeSync,
8
+ isDirSync,
9
+ mkdirSync,
10
+ moveSync,
11
+ parsePath,
12
+ readSync,
13
+ removeSync,
14
+ resolve,
15
+ writeSync
16
+ } from "./fs-sync";
17
+ import { objectType } from "@impactor/javascript";
18
+ import { existsSync, readFileSync, utimesSync } from "node:fs";
19
+ import { platform } from "node:process";
20
+ let dir = resolve(import.meta.dirname, "./test!!/fs-sync"), file = dir + "/file.txt";
21
+ beforeEach(() => {
22
+ removeSync(dir);
23
+ writeSync(file, "ok");
24
+ });
25
+ afterEach(() => removeSync(dir));
26
+ test("mkdir", () => {
27
+ expect(existsSync(`${dir}/mkdir`)).toBeFalsy();
28
+ mkdirSync(`${dir}/mkdir`);
29
+ expect(existsSync(`${dir}/mkdir`)).toBeTruthy();
30
+ });
31
+ test("write", () => {
32
+ mkdirSync(dir);
33
+ expect(existsSync(`${dir}/write.txt`)).toBeFalsy();
34
+ writeSync(`${dir}/write.txt`, "ok");
35
+ expect(existsSync(`${dir}/write.txt`)).toBeTruthy();
36
+ expect(readFileSync(`${dir}/write.txt`).toString()).toEqual("ok");
37
+ });
38
+ test("write in non-existing dir", () => {
39
+ let file2 = dir + "/non-existing/file.txt";
40
+ expect(existsSync(file2)).toBeFalsy();
41
+ writeSync(file2, "ok");
42
+ expect(existsSync(file2)).toBeTruthy();
43
+ expect(readFileSync(file2).toString()).toEqual("ok");
44
+ });
45
+ test("resolve", () => {
46
+ try {
47
+ expect(resolve("/path", "to/file.js")).toEqual("/path/to/file.js");
48
+ } catch {
49
+ expect(resolve("/path", "to/file.js")).toContain(
50
+ String.raw`path\to\file.js`
51
+ );
52
+ }
53
+ });
54
+ test("parsePath", () => {
55
+ expect(parsePath("/path/to/file.js")).toEqual({
56
+ type: "file",
57
+ dir: "/path/to",
58
+ name: "file",
59
+ extension: "js"
60
+ });
61
+ if (platform === "win32") {
62
+ expect(parsePath(String.raw`\path\to\file.js`)).toEqual({
63
+ type: "file",
64
+ dir: String.raw`\path\to`,
65
+ name: "file",
66
+ extension: "js"
67
+ });
68
+ }
69
+ });
70
+ test("getExtension", () => {
71
+ expect(getExtensionSync("/path/to/file.js")).toEqual("js");
72
+ expect(getExtensionSync(".gitignore")).toEqual("");
73
+ expect(getExtensionSync("/path/to/.gitignore")).toEqual("");
74
+ expect(getExtensionSync("/path/to")).toEqual("");
75
+ });
76
+ test("size units", () => {
77
+ let size = 1234567890, units = { b: 0, kb: 1, mb: 2, gb: 3 };
78
+ expect(size / 1024 ** units.mb).toBeCloseTo(1177.3, 0);
79
+ });
80
+ test("getSize", () => {
81
+ writeSync(`${dir}/get-size/file1.txt`, "ok");
82
+ writeSync(`${dir}/get-size/file2.txt`, "ok");
83
+ expect(getSizeSync(`${dir}/get-size/file1.txt`)).toEqual(2);
84
+ expect(getSizeSync(`${dir}/get-size`)).toEqual(4);
85
+ expect(
86
+ getSizeSync([`${dir}/get-size/file1.txt`, `${dir}/get-size/file2.txt`])
87
+ ).toEqual(4);
88
+ });
89
+ test("isDir", () => {
90
+ expect(isDirSync(file)).toEqual(false);
91
+ expect(isDirSync(dir)).toEqual(true);
92
+ });
93
+ test("getModifiedTime", () => {
94
+ expect(Math.floor(getModifiedTimeSync(file))).toBeGreaterThanOrEqual(
95
+ 1624906832178
96
+ );
97
+ expect(Math.floor(getModifiedTimeSync(dir))).toBeGreaterThanOrEqual(
98
+ 1624906832178
99
+ );
100
+ });
101
+ test("move", () => {
102
+ let file2 = dir + "/file2.txt";
103
+ expect(existsSync(file)).toBeTruthy();
104
+ expect(existsSync(file2)).toBeFalsy();
105
+ moveSync(file, file2);
106
+ expect(existsSync(file)).toBeFalsy();
107
+ expect(existsSync(file2)).toBeTruthy();
108
+ });
109
+ test("read", () => {
110
+ let fileJson = dir + "/file.json", fileArray = dir + "/array.json", fileJsonComments = dir + "/comments.json";
111
+ writeSync(fileJson, { x: 1, y: 2 });
112
+ writeSync(fileArray, [1, 2, 3]);
113
+ writeSync(
114
+ fileJsonComments,
115
+ `// this file is created to test reading .json files that contains comments
116
+ // to test stripComments()
117
+
118
+ {
119
+ /* it should remove all comments */
120
+ /* even this
121
+ multi-line comment
122
+ */
123
+ // also this comment
124
+
125
+ "x": 1,
126
+ "hello": "ok"
127
+ }
128
+ `
129
+ );
130
+ let txt = readSync(file), json = readSync(fileJson), jsonWithComments = readSync(fileJsonComments), array = readSync(fileArray);
131
+ expect(txt.length).toEqual(2);
132
+ expect(txt).toContain("ok");
133
+ expect(objectType(txt)).toEqual("string");
134
+ expect(objectType(json)).toEqual("object");
135
+ expect(objectType(jsonWithComments)).toEqual("object");
136
+ expect(objectType(array)).toEqual("array");
137
+ expect(json).toEqual({ x: 1, y: 2 });
138
+ expect(jsonWithComments).toEqual({ x: 1, hello: "ok" });
139
+ expect(array).toEqual([1, 2, 3]);
140
+ });
141
+ test("read from a non-existing file", () => {
142
+ expect(
143
+ () => readSync(`${dir}/non-existing.txt`, { maxAge: 24 * 60 * 60 })
144
+ ).toThrow("no such file or directory");
145
+ });
146
+ test("read: maxAge", () => {
147
+ let file2 = dir + "/file.txt";
148
+ writeSync(file2, "ok");
149
+ expect(readSync(file2, { maxAge: 24 * 60 * 60 })).toEqual("ok");
150
+ });
151
+ test("read from an expired cache", () => {
152
+ let file2 = dir + "/file.txt";
153
+ writeSync(file2, "ok");
154
+ let date = /* @__PURE__ */ new Date(), today = date.getDate();
155
+ date.setDate(today - 1);
156
+ let yesterday = date.getTime() / 1e3;
157
+ utimesSync(file2, yesterday, yesterday);
158
+ expect(() => readSync(file2, { maxAge: 1 })).toThrow("expired file");
159
+ });
160
+ test("remove dir", () => {
161
+ expect(existsSync(file)).toBeTruthy();
162
+ expect(existsSync(dir)).toBeTruthy();
163
+ removeSync(dir);
164
+ expect(existsSync(file)).toBeFalsy();
165
+ expect(existsSync(dir)).toBeFalsy();
166
+ });
167
+ test("remove non-exists path", () => {
168
+ let file2 = `${dir}/non-existing/file.txt`;
169
+ removeSync(file2);
170
+ expect(existsSync(file2)).toBeFalsy();
171
+ });
172
+ test("copy a directory and its sub-directories", () => {
173
+ writeSync(`${dir}/copy-dir/file.txt`, "");
174
+ writeSync(`${dir}/copy-dir/sub-dir/file2.txt`, "");
175
+ copySync(`${dir}/copy-dir`, `${dir}/copy-dir2`);
176
+ expect(existsSync(`${dir}/copy-dir2/file.txt`)).toBeTruthy();
177
+ expect(existsSync(`${dir}/copy-dir2/sub-dir/file2.txt`)).toBeTruthy();
178
+ });
179
+ describe("getEntries", () => {
180
+ let entries = ["file.txt", "file.js"];
181
+ beforeEach(() => {
182
+ for (let element of entries) {
183
+ writeSync(`${dir}/${element}`, "");
184
+ writeSync(`${dir}/subdir/${element}`, "");
185
+ }
186
+ });
187
+ test("list all entries recursively", () => {
188
+ expect(getEntriesSync(dir).sort()).toEqual(
189
+ // all files in dir with full path
190
+ [
191
+ ...entries.map((element) => resolve(`${dir}/${element}`)).concat(
192
+ entries.map((element) => resolve(`${dir}/subdir/${element}`))
193
+ ),
194
+ resolve(`${dir}/subdir`)
195
+ ].sort()
196
+ );
197
+ });
198
+ test("filter by function", () => {
199
+ expect(getEntriesSync(dir, (element) => element.includes(".js"))).toEqual([
200
+ resolve(`${dir}/file.js`),
201
+ resolve(`${dir}/subdir/file.js`)
202
+ ]);
203
+ });
204
+ test("filter by regex", () => {
205
+ expect(getEntriesSync(dir, /subdir/).sort()).toEqual(
206
+ [
207
+ ...entries.map((element) => resolve(`${dir}/subdir/${element}`)),
208
+ resolve(`${dir}/subdir`)
209
+ ].sort()
210
+ );
211
+ });
212
+ test("filter by type: files", () => {
213
+ expect(getEntriesSync(dir, "files").sort()).toEqual(
214
+ entries.map((element) => resolve(`${dir}/${element}`)).concat(entries.map((element) => resolve(`${dir}/subdir/${element}`))).sort()
215
+ );
216
+ });
217
+ test("filter by type: dirs", () => {
218
+ expect(getEntriesSync(dir, "dirs")).toEqual([resolve(`${dir}/subdir`)]);
219
+ });
220
+ test("depth=0", () => {
221
+ for (let element of entries) {
222
+ writeSync(`${dir}/subdir/extra/${element}`, "");
223
+ }
224
+ expect(getEntriesSync(dir, void 0, 0).sort()).toEqual(
225
+ [
226
+ ...entries.map((element) => resolve(`${dir}/${element}`)),
227
+ resolve(`${dir}/subdir`)
228
+ ].sort()
229
+ );
230
+ });
231
+ test("depth=1", () => {
232
+ for (let element of entries) {
233
+ writeSync(`${dir}/subdir/extra/${element}`, "");
234
+ }
235
+ expect(getEntriesSync(dir, void 0, 1).sort()).toEqual(
236
+ [
237
+ ...entries.map((element) => resolve(`${dir}/${element}`)),
238
+ resolve(`${dir}/subdir`),
239
+ resolve(`${dir}/subdir/extra`)
240
+ ].concat(entries.map((element) => resolve(`${dir}/subdir/${element}`))).sort()
241
+ );
242
+ });
243
+ test("depth=2", () => {
244
+ for (let element of entries) {
245
+ writeSync(`${dir}/subdir/extra/${element}`, "");
246
+ }
247
+ expect(getEntriesSync(dir, void 0, 2).sort()).toEqual(
248
+ [
249
+ ...entries.map((element) => resolve(`${dir}/${element}`)),
250
+ resolve(`${dir}/subdir`),
251
+ resolve(`${dir}/subdir/extra`)
252
+ ].concat(entries.map((element) => resolve(`${dir}/subdir/${element}`))).concat(
253
+ entries.map((element) => resolve(`${dir}/subdir/extra/${element}`))
254
+ ).sort()
255
+ );
256
+ });
257
+ test("non existing dir", () => {
258
+ expect(() => getEntriesSync(dir + "/non-existing")).toThrow(
259
+ "no such file or directory"
260
+ );
261
+ });
262
+ });
package/src/fs.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { type PathLike, type WriteFileOptions } from 'node:fs';
2
+ import { type Abortable } from 'node:events';
3
+ import { type Filter, type MoveOptions, type ReadOptions } from './fs-sync';
4
+ import { type Obj } from '@impactor/javascript';
5
+ export declare function getSize(path: PathLike | PathLike[], unit?: 'b' | 'kb' | 'mb' | 'gb', filter?: Filter): Promise<number>;
6
+ export declare function isDir(path: PathLike): Promise<boolean>;
7
+ export declare function getModifiedTime(file: PathLike): Promise<number>;
8
+ export declare function mkdir(path: PathLike | PathLike[], mode?: number | string): Promise<void>;
9
+ export declare function move(path: PathLike, newPath: PathLike, _options?: MoveOptions): Promise<void>;
10
+ export declare function remove(path: PathLike | PathLike[], filter?: Filter, keepDir?: boolean): Promise<void>;
11
+ export declare function copy(source: PathLike, destination: string, filter?: Filter): Promise<any>;
12
+ export declare function write(path: PathLike, data: any, options?: WriteFileOptions & Abortable): Promise<void>;
13
+ export declare function read<T extends Buffer | string | Array<any> | Obj>(path: PathLike | URL, options?: ReadOptions | BufferEncoding): Promise<T>;
14
+ export declare function getEntries(dir?: string | string[], filter?: ((entry: string) => boolean) | RegExp | 'files' | 'dirs', depth?: number, skip?: ((entry: string) => boolean) | RegExp): Promise<Array<string>>;
15
+ export declare function recursive(path: PathLike | PathLike[], apply: (path: string, type: 'dir' | 'file') => any, filter?: Filter): Promise<any | any[]>;
16
+ export declare function exists(path: PathLike): Promise<boolean>;
package/src/fs.js ADDED
@@ -0,0 +1,188 @@
1
+ import {
2
+ constants,
3
+ lstatSync,
4
+ readdirSync
5
+ } from "node:fs";
6
+ import {
7
+ mkdir as _mkdir,
8
+ access,
9
+ copyFile,
10
+ lstat,
11
+ readFile,
12
+ readdir,
13
+ rename,
14
+ rmdir,
15
+ unlink,
16
+ writeFile
17
+ } from "node:fs/promises";
18
+ import {
19
+ resolve
20
+ } from "./fs-sync";
21
+ import { dirname, join } from "node:path";
22
+ import { objectType } from "@impactor/javascript";
23
+ import { cleanJson } from "@impactor/javascript";
24
+ function getSize(path, unit = "b", filter) {
25
+ let units = { b: 0, kb: 1, mb: 2, gb: 3 };
26
+ return recursive(
27
+ path,
28
+ (_path, type) => type === "file" ? lstat(_path).then((stats) => stats.size / 1024 ** units[unit]) : (
29
+ // todo: for dirs, size = total sizes of its contents
30
+ void 0
31
+ ),
32
+ filter
33
+ ).then((sizes) => {
34
+ let sum = (sizes2) => {
35
+ let total = 0;
36
+ for (let size of sizes2.filter(Boolean)) {
37
+ total += Array.isArray(size) ? sum(size) : size;
38
+ }
39
+ return total;
40
+ };
41
+ return Array.isArray(sizes) ? sum(sizes) : sizes;
42
+ });
43
+ }
44
+ function isDir(path) {
45
+ return lstat(path).then((stats) => stats.isDirectory());
46
+ }
47
+ function getModifiedTime(file) {
48
+ return lstat(file).then((stats) => stats.mtimeMs);
49
+ }
50
+ function mkdir(path, mode = 511) {
51
+ if (Array.isArray(path)) {
52
+ return Promise.all(
53
+ path.map((p) => ({ [p.toString()]: mkdir(p, mode) }))
54
+ ).then(() => {
55
+ });
56
+ }
57
+ let options = { mode, recursive: true };
58
+ return access(path, constants.R_OK).catch(() => _mkdir(path, options)).then(() => {
59
+ });
60
+ }
61
+ async function move(path, newPath, _options) {
62
+ await mkdir(dirname(newPath.toString()));
63
+ return rename(path, newPath);
64
+ }
65
+ function remove(path, filter, keepDir = false) {
66
+ return recursive(
67
+ path,
68
+ (file, type) => type === "file" ? unlink(file) : keepDir ? void 0 : rmdir(file),
69
+ filter
70
+ );
71
+ }
72
+ function copy(source, destination, filter = () => true) {
73
+ source = resolve(source);
74
+ destination = resolve(destination);
75
+ return recursive(
76
+ source,
77
+ (path, type) => {
78
+ path = path.toString();
79
+ if (type === "file" && filter(path)) {
80
+ let destination_ = path.replace(source.toString(), destination);
81
+ return mkdir(dirname(destination_)).then(
82
+ () => copyFile(path, destination_)
83
+ );
84
+ }
85
+ return;
86
+ },
87
+ filter
88
+ );
89
+ }
90
+ function write(path, data, options) {
91
+ path = resolve(path);
92
+ return mkdir(dirname(path)).then(
93
+ () => ["array", "object"].includes(objectType(data)) ? JSON.stringify(data, null, 2) : data
94
+ ).then((dataString) => writeFile(path, dataString, options));
95
+ }
96
+ function read(path, options) {
97
+ path = resolve(path);
98
+ let opts = {
99
+ encoding: null,
100
+ flag: "r",
101
+ maxAge: 0,
102
+ ...typeof options === "string" ? { encoding: options } : options
103
+ };
104
+ return getModifiedTime(path).then((modified) => {
105
+ if (opts.maxAge && opts.maxAge > 0 && modified + opts.maxAge < Date.now()) {
106
+ throw new Error(`[fs-sync] expired file ${path}`);
107
+ }
108
+ return readFile(path, {
109
+ encoding: opts.encoding,
110
+ flag: opts.flag
111
+ }).then((data) => {
112
+ if (opts.encoding === void 0) {
113
+ return data;
114
+ }
115
+ data = data.toString();
116
+ return path.toString().trim().slice(-5) === ".json" ? JSON.parse(cleanJson(data)) : data;
117
+ });
118
+ });
119
+ }
120
+ async function getEntries(dir = ".", filter, depth, skip) {
121
+ if (Array.isArray(dir)) {
122
+ return Promise.all(dir.map((el) => getEntries(el, filter, depth))).then(
123
+ // combine an array of arrays into a single array
124
+ (result2) => result2.flat()
125
+ );
126
+ }
127
+ dir = resolve(dir);
128
+ let filterFunction = filter === "files" ? (entry) => lstatSync(entry).isFile() : filter === "dirs" ? (entry) => lstatSync(entry).isDirectory() : filter instanceof RegExp ? (entry) => filter.test(entry) : typeof filter === "function" ? filter : void 0;
129
+ let skipFunction = skip instanceof RegExp ? (entry) => skip.test(entry) : typeof skip === "function" ? skip : (entry) => ["node_modules", "dist"].includes(entry);
130
+ let entries = readdirSync(dir);
131
+ let result = [];
132
+ for (let entry of entries) {
133
+ let path = join(dir, entry), _fullPath = resolve(dir, entry);
134
+ if (!filterFunction || filterFunction(path)) {
135
+ result.push(path);
136
+ }
137
+ if ((depth === void 0 || depth > 0) && lstatSync(path).isDirectory() && !skipFunction?.(entry)) {
138
+ let subEntries = await getEntries(
139
+ path,
140
+ filterFunction,
141
+ depth === void 0 ? void 0 : depth - 1
142
+ );
143
+ result = result.concat(subEntries);
144
+ }
145
+ }
146
+ return result;
147
+ }
148
+ async function recursive(path, apply, filter) {
149
+ if (!path) {
150
+ throw "path not provided";
151
+ }
152
+ if (Array.isArray(path)) {
153
+ return Promise.all(
154
+ // todo: path.map((p) => ({ [p]: recursive(p as string, apply) }))
155
+ path.map((p) => recursive(p, apply, filter))
156
+ );
157
+ }
158
+ let _path = resolve(path);
159
+ await access(_path, constants.R_OK);
160
+ let _isDir = await isDir(_path);
161
+ if (filter?.(_path, _isDir ? "dir" : "file") === false) return;
162
+ if (_isDir) {
163
+ apply(_path, "dir");
164
+ let dir = await readdir(_path);
165
+ for (let file of dir) {
166
+ await recursive(`${_path}/${file}`, apply, filter);
167
+ }
168
+ } else {
169
+ apply(_path, "file");
170
+ }
171
+ }
172
+ function exists(path) {
173
+ return access(resolve(path), constants.R_OK).then(() => true).catch(() => false);
174
+ }
175
+ export {
176
+ copy,
177
+ exists,
178
+ getEntries,
179
+ getModifiedTime,
180
+ getSize,
181
+ isDir,
182
+ mkdir,
183
+ move,
184
+ read,
185
+ recursive,
186
+ remove,
187
+ write
188
+ };