@warlock.js/fs 4.1.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/README.md +76 -0
- package/cjs/index.cjs +424 -0
- package/cjs/index.cjs.map +1 -0
- package/esm/atomic.d.mts +22 -0
- package/esm/atomic.mjs +40 -0
- package/esm/atomic.mjs.map +1 -0
- package/esm/copy.d.mts +14 -0
- package/esm/copy.mjs +29 -0
- package/esm/copy.mjs.map +1 -0
- package/esm/dirs.d.mts +10 -0
- package/esm/dirs.mjs +18 -0
- package/esm/dirs.mjs.map +1 -0
- package/esm/exists.d.mts +44 -0
- package/esm/exists.mjs +86 -0
- package/esm/exists.mjs.map +1 -0
- package/esm/hash.d.mts +32 -0
- package/esm/hash.mjs +52 -0
- package/esm/hash.mjs.map +1 -0
- package/esm/index.d.mts +12 -0
- package/esm/index.mjs +13 -0
- package/esm/list.d.mts +20 -0
- package/esm/list.mjs +39 -0
- package/esm/list.mjs.map +1 -0
- package/esm/read.d.mts +16 -0
- package/esm/read.mjs +28 -0
- package/esm/read.mjs.map +1 -0
- package/esm/remove.d.mts +14 -0
- package/esm/remove.mjs +40 -0
- package/esm/remove.mjs.map +1 -0
- package/esm/rename.d.mts +9 -0
- package/esm/rename.mjs +17 -0
- package/esm/rename.mjs.map +1 -0
- package/esm/stats.d.mts +16 -0
- package/esm/stats.mjs +28 -0
- package/esm/stats.mjs.map +1 -0
- package/esm/write.d.mts +14 -0
- package/esm/write.mjs +29 -0
- package/esm/write.mjs.map +1 -0
- package/llms-full.txt +570 -0
- package/llms.txt +13 -0
- package/package.json +24 -0
- package/skills/hash-files/SKILL.md +122 -0
- package/skills/manage-directories/SKILL.md +140 -0
- package/skills/overview/SKILL.md +77 -0
- package/skills/read-and-write-files/SKILL.md +107 -0
- package/skills/write-atomically/SKILL.md +98 -0
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# @warlock.js/fs
|
|
2
|
+
|
|
3
|
+
A pocket-sized filesystem toolkit for Node — the shape you wish `node:fs/promises` had, without pulling in `fs-extra`, `rimraf`, `mkdirp`, `write-file-atomic`, and `hasha`. Standalone: usable in any Node project, no `@warlock.js/core` required.
|
|
4
|
+
|
|
5
|
+
Every helper picks the right defaults — writes create parent directories for you, deletes swallow `ENOENT`, `atomicWriteAsync` writes-then-renames, and `hashFileAsync` streams so a 1 GB file doesn't blow the heap.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
yarn add @warlock.js/fs
|
|
11
|
+
# or
|
|
12
|
+
npm install @warlock.js/fs
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## One naming convention
|
|
16
|
+
|
|
17
|
+
That's the whole vocabulary:
|
|
18
|
+
|
|
19
|
+
- **`*Async`** returns a `Promise` — use it in server / runtime code.
|
|
20
|
+
- **bare name** is synchronous — use it in CLI tools, codegen, and one-shot scripts.
|
|
21
|
+
|
|
22
|
+
One canonical name per operation; no aliases to remember. If the obvious name isn't there, the operation isn't there.
|
|
23
|
+
|
|
24
|
+
## 30-second tour
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import {
|
|
28
|
+
putJsonFileAsync,
|
|
29
|
+
getJsonFileAsync,
|
|
30
|
+
atomicWriteAsync,
|
|
31
|
+
ensureDirectoryAsync,
|
|
32
|
+
listFilesAsync,
|
|
33
|
+
hashFileAsync,
|
|
34
|
+
} from "@warlock.js/fs";
|
|
35
|
+
|
|
36
|
+
// Write JSON (parent dirs auto-created, pretty-printed at 2 spaces)
|
|
37
|
+
await putJsonFileAsync("./build/manifest.json", { version: "1.0.0" });
|
|
38
|
+
|
|
39
|
+
// Read it back, typed
|
|
40
|
+
const manifest = await getJsonFileAsync<{ version: string }>("./build/manifest.json");
|
|
41
|
+
|
|
42
|
+
// Atomic write — concurrent readers never see a half-written file
|
|
43
|
+
await atomicWriteAsync("./build/state.lock", manifest.version);
|
|
44
|
+
|
|
45
|
+
// Directory ops
|
|
46
|
+
await ensureDirectoryAsync("./build/cache");
|
|
47
|
+
const files = await listFilesAsync("./build"); // full paths, not bare names
|
|
48
|
+
|
|
49
|
+
// Content fingerprint (streaming — constant memory)
|
|
50
|
+
const digest = await hashFileAsync("./build/manifest.json");
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## What you get
|
|
54
|
+
|
|
55
|
+
- **Read + write text and JSON** — `getFileAsync`, `getJsonFileAsync`, `putFileAsync`, `putJsonFileAsync`. Writes auto-create parent directories; JSON variants pretty-print at 2-space indent.
|
|
56
|
+
- **Atomic writes** — `atomicWriteAsync` (accepts `string | Buffer`) and `atomicWriteJsonAsync`, for files other processes read concurrently.
|
|
57
|
+
- **Directory management** — `ensureDirectoryAsync`, `list(Async)` / `listFiles(Async)` / `listDirectories(Async)`, `copyFile(Async)` / `copyDirectory(Async)`, `renameFile(Async)`.
|
|
58
|
+
- **Delete** — `unlink(Async)` and `removeDirectory(Async)`, both `ENOENT`-safe (no-op on missing targets).
|
|
59
|
+
- **Content hashing** — `hashFileAsync` (streaming), `hashFileSmallAsync`, `hashString`, `hashBuffer`. SHA-256 default; `sha1` / `md5` / `sha512` supported.
|
|
60
|
+
- **Existence + stats** — `pathExists`, `fileExists`, `directoryExists`, `lastModified`, `stats` (each with an `*Async` twin).
|
|
61
|
+
|
|
62
|
+
## Full documentation
|
|
63
|
+
|
|
64
|
+
The complete guide — getting started, essentials, task guides, recipes, and API reference — lives at **[warlock.js.org](https://warlock.js.org/v/latest/fs/)**.
|
|
65
|
+
|
|
66
|
+
## Tests
|
|
67
|
+
|
|
68
|
+
This package uses Vitest:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
yarn test
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT
|
package/cjs/index.cjs
ADDED
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
12
|
+
key = keys[i];
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
14
|
+
__defProp(to, key, {
|
|
15
|
+
get: ((k) => from[k]).bind(null, key),
|
|
16
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
24
|
+
value: mod,
|
|
25
|
+
enumerable: true
|
|
26
|
+
}) : target, mod));
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
let node_crypto = require("node:crypto");
|
|
30
|
+
let node_fs_promises = require("node:fs/promises");
|
|
31
|
+
let node_path = require("node:path");
|
|
32
|
+
node_path = __toESM(node_path, 1);
|
|
33
|
+
let node_fs = require("node:fs");
|
|
34
|
+
|
|
35
|
+
//#region ../../@warlock.js/fs/src/atomic.ts
|
|
36
|
+
/**
|
|
37
|
+
* Write a file atomically.
|
|
38
|
+
*
|
|
39
|
+
* Writes to a uniquely-named sibling temp file first, then renames it onto
|
|
40
|
+
* the target. Readers either see the old content or the complete new
|
|
41
|
+
* content — never a half-written file. If anything fails mid-write the
|
|
42
|
+
* temp file is cleaned up.
|
|
43
|
+
*
|
|
44
|
+
* Parent directories are created if missing.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* await atomicWriteAsync("manifest.json", JSON.stringify(data));
|
|
48
|
+
*/
|
|
49
|
+
async function atomicWriteAsync(filePath, content) {
|
|
50
|
+
const dir = node_path.default.dirname(filePath);
|
|
51
|
+
await (0, node_fs_promises.mkdir)(dir, { recursive: true });
|
|
52
|
+
const tempPath = node_path.default.join(dir, `.${node_path.default.basename(filePath)}.${(0, node_crypto.randomBytes)(6).toString("hex")}.tmp`);
|
|
53
|
+
try {
|
|
54
|
+
await (0, node_fs_promises.writeFile)(tempPath, content);
|
|
55
|
+
await (0, node_fs_promises.rename)(tempPath, filePath);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
await (0, node_fs_promises.unlink)(tempPath).catch(() => void 0);
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Atomic write convenience for JSON values (pretty-printed, 2-space indent).
|
|
63
|
+
*/
|
|
64
|
+
async function atomicWriteJsonAsync(filePath, value) {
|
|
65
|
+
await atomicWriteAsync(filePath, JSON.stringify(value, null, 2));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region ../../@warlock.js/fs/src/copy.ts
|
|
70
|
+
/**
|
|
71
|
+
* Copy a single file. Creates the destination's parent directory if needed.
|
|
72
|
+
*/
|
|
73
|
+
async function copyFileAsync(source, destination) {
|
|
74
|
+
await (0, node_fs_promises.mkdir)(node_path.default.dirname(destination), { recursive: true });
|
|
75
|
+
await (0, node_fs_promises.copyFile)(source, destination);
|
|
76
|
+
}
|
|
77
|
+
function copyFile(source, destination) {
|
|
78
|
+
(0, node_fs.mkdirSync)(node_path.default.dirname(destination), { recursive: true });
|
|
79
|
+
(0, node_fs.copyFileSync)(source, destination);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Recursively copy a directory.
|
|
83
|
+
*/
|
|
84
|
+
async function copyDirectoryAsync(source, destination) {
|
|
85
|
+
await (0, node_fs_promises.cp)(source, destination, { recursive: true });
|
|
86
|
+
}
|
|
87
|
+
function copyDirectory(source, destination) {
|
|
88
|
+
(0, node_fs.cpSync)(source, destination, { recursive: true });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region ../../@warlock.js/fs/src/dirs.ts
|
|
93
|
+
/**
|
|
94
|
+
* Ensure a directory exists (recursively creating parents).
|
|
95
|
+
* Idempotent — no error if the directory already exists.
|
|
96
|
+
*/
|
|
97
|
+
async function ensureDirectoryAsync(path) {
|
|
98
|
+
await (0, node_fs_promises.mkdir)(path, { recursive: true });
|
|
99
|
+
}
|
|
100
|
+
function ensureDirectory(path) {
|
|
101
|
+
(0, node_fs.mkdirSync)(path, { recursive: true });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region ../../@warlock.js/fs/src/exists.ts
|
|
106
|
+
/**
|
|
107
|
+
* Check whether a path exists, REGARDLESS of type — resolves `true` for both
|
|
108
|
+
* files and directories, `false` only when nothing is there (ENOENT).
|
|
109
|
+
*
|
|
110
|
+
* Pick the right check for the job:
|
|
111
|
+
* - `pathExistsAsync` — anything at this path (file OR directory).
|
|
112
|
+
* - `fileExistsAsync` — exists AND is a regular file.
|
|
113
|
+
* - `directoryExistsAsync` — exists AND is a directory.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* if (await pathExistsAsync("/var/data")) {
|
|
117
|
+
* // something is there — could be a file or a folder
|
|
118
|
+
* }
|
|
119
|
+
*/
|
|
120
|
+
async function pathExistsAsync(path) {
|
|
121
|
+
try {
|
|
122
|
+
await (0, node_fs_promises.access)(path);
|
|
123
|
+
return true;
|
|
124
|
+
} catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function pathExists(path) {
|
|
129
|
+
try {
|
|
130
|
+
(0, node_fs.accessSync)(path);
|
|
131
|
+
return true;
|
|
132
|
+
} catch {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Check whether a path exists AND is a regular file. Resolves `false` for a
|
|
138
|
+
* directory — use `directoryExistsAsync` for folders, or `pathExistsAsync`
|
|
139
|
+
* when the type does not matter.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* if (await fileExistsAsync("/etc/config.json")) {
|
|
143
|
+
* const raw = await readFile("/etc/config.json", "utf8");
|
|
144
|
+
* }
|
|
145
|
+
*/
|
|
146
|
+
async function fileExistsAsync(path) {
|
|
147
|
+
try {
|
|
148
|
+
return (await (0, node_fs_promises.stat)(path)).isFile();
|
|
149
|
+
} catch {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function fileExists(path) {
|
|
154
|
+
try {
|
|
155
|
+
return (0, node_fs.statSync)(path).isFile();
|
|
156
|
+
} catch {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Check whether a path exists AND is a directory. Resolves `false` for a
|
|
162
|
+
* regular file — use `fileExistsAsync` for files, or `pathExistsAsync` when
|
|
163
|
+
* the type does not matter.
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* if (await directoryExistsAsync("/var/uploads")) {
|
|
167
|
+
* const entries = await readdir("/var/uploads");
|
|
168
|
+
* }
|
|
169
|
+
*/
|
|
170
|
+
async function directoryExistsAsync(path) {
|
|
171
|
+
try {
|
|
172
|
+
return (await (0, node_fs_promises.stat)(path)).isDirectory();
|
|
173
|
+
} catch {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function directoryExists(path) {
|
|
178
|
+
try {
|
|
179
|
+
return (0, node_fs.statSync)(path).isDirectory();
|
|
180
|
+
} catch {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region ../../@warlock.js/fs/src/hash.ts
|
|
187
|
+
/**
|
|
188
|
+
* Compute a hex digest of a file's contents. Uses streaming for large
|
|
189
|
+
* files so memory doesn't spike when hashing big assets.
|
|
190
|
+
*
|
|
191
|
+
* @param path - File to hash.
|
|
192
|
+
* @param algorithm - Hash algorithm (default `sha256`).
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* const fingerprint = await hashFile("./bundle.js");
|
|
196
|
+
* const quick = await hashFile("./small.txt", "md5");
|
|
197
|
+
*/
|
|
198
|
+
function hashFileAsync(path, algorithm = "sha256") {
|
|
199
|
+
return new Promise((resolve, reject) => {
|
|
200
|
+
const hash = (0, node_crypto.createHash)(algorithm);
|
|
201
|
+
const stream = (0, node_fs.createReadStream)(path);
|
|
202
|
+
stream.on("data", (chunk) => hash.update(chunk));
|
|
203
|
+
stream.on("end", () => resolve(hash.digest("hex")));
|
|
204
|
+
stream.on("error", reject);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
function hashFile(path, algorithm = "sha256") {
|
|
208
|
+
return (0, node_crypto.createHash)(algorithm).update((0, node_fs.readFileSync)(path)).digest("hex");
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Hash an in-memory string without touching disk. Convenient when the
|
|
212
|
+
* caller already has the content loaded (e.g. file watcher diffing).
|
|
213
|
+
*/
|
|
214
|
+
function hashString(content, algorithm = "sha256") {
|
|
215
|
+
return (0, node_crypto.createHash)(algorithm).update(content).digest("hex");
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Hash an arbitrary buffer.
|
|
219
|
+
*/
|
|
220
|
+
function hashBuffer(content, algorithm = "sha256") {
|
|
221
|
+
return (0, node_crypto.createHash)(algorithm).update(content).digest("hex");
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Like `hashFileAsync` but reads the file in one go. Slightly faster for
|
|
225
|
+
* small files; use the streaming variant for anything > ~1 MB.
|
|
226
|
+
*/
|
|
227
|
+
async function hashFileSmallAsync(path, algorithm = "sha256") {
|
|
228
|
+
return (0, node_crypto.createHash)(algorithm).update(await (0, node_fs_promises.readFile)(path)).digest("hex");
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region ../../@warlock.js/fs/src/list.ts
|
|
233
|
+
/**
|
|
234
|
+
* List immediate children of a directory (files + subdirs), returning
|
|
235
|
+
* full paths.
|
|
236
|
+
*/
|
|
237
|
+
async function listAsync(directoryPath) {
|
|
238
|
+
return (await (0, node_fs_promises.readdir)(directoryPath)).map((entry) => node_path.default.join(directoryPath, entry));
|
|
239
|
+
}
|
|
240
|
+
function list(directoryPath) {
|
|
241
|
+
return (0, node_fs.readdirSync)(directoryPath).map((entry) => node_path.default.join(directoryPath, entry));
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* List only files (not subdirectories) directly inside a directory.
|
|
245
|
+
*/
|
|
246
|
+
async function listFilesAsync(directoryPath) {
|
|
247
|
+
const entries = await listAsync(directoryPath);
|
|
248
|
+
return (await Promise.all(entries.map(async (entry) => (await (0, node_fs_promises.stat)(entry)).isFile() ? entry : null))).filter((entry) => entry !== null);
|
|
249
|
+
}
|
|
250
|
+
function listFiles(directoryPath) {
|
|
251
|
+
return list(directoryPath).filter((entry) => (0, node_fs.statSync)(entry).isFile());
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* List only subdirectories directly inside a directory.
|
|
255
|
+
*/
|
|
256
|
+
async function listDirectoriesAsync(directoryPath) {
|
|
257
|
+
const entries = await listAsync(directoryPath);
|
|
258
|
+
return (await Promise.all(entries.map(async (entry) => (await (0, node_fs_promises.stat)(entry)).isDirectory() ? entry : null))).filter((entry) => entry !== null);
|
|
259
|
+
}
|
|
260
|
+
function listDirectories(directoryPath) {
|
|
261
|
+
return list(directoryPath).filter((entry) => (0, node_fs.statSync)(entry).isDirectory());
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
//#endregion
|
|
265
|
+
//#region ../../@warlock.js/fs/src/read.ts
|
|
266
|
+
/**
|
|
267
|
+
* Read a file as UTF-8 text.
|
|
268
|
+
*/
|
|
269
|
+
async function getFileAsync(path) {
|
|
270
|
+
return (0, node_fs_promises.readFile)(path, "utf-8");
|
|
271
|
+
}
|
|
272
|
+
function getFile(path) {
|
|
273
|
+
return (0, node_fs.readFileSync)(path, "utf-8");
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Read a JSON file and parse it.
|
|
277
|
+
*
|
|
278
|
+
* @throws if the file does not exist or contains invalid JSON.
|
|
279
|
+
*/
|
|
280
|
+
async function getJsonFileAsync(path) {
|
|
281
|
+
return JSON.parse(await getFileAsync(path));
|
|
282
|
+
}
|
|
283
|
+
function getJsonFile(path) {
|
|
284
|
+
return JSON.parse(getFile(path));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region ../../@warlock.js/fs/src/remove.ts
|
|
289
|
+
/**
|
|
290
|
+
* Delete a single file. No error if the file doesn't exist.
|
|
291
|
+
*/
|
|
292
|
+
async function unlinkAsync(path) {
|
|
293
|
+
try {
|
|
294
|
+
await (0, node_fs_promises.unlink)(path);
|
|
295
|
+
} catch (error) {
|
|
296
|
+
if (error?.code !== "ENOENT") throw error;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
function unlink(path) {
|
|
300
|
+
try {
|
|
301
|
+
(0, node_fs.unlinkSync)(path);
|
|
302
|
+
} catch (error) {
|
|
303
|
+
if (error?.code !== "ENOENT") throw error;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Recursively delete a directory and its contents. No error if missing.
|
|
308
|
+
*/
|
|
309
|
+
async function removeDirectoryAsync(path) {
|
|
310
|
+
await (0, node_fs_promises.rm)(path, {
|
|
311
|
+
recursive: true,
|
|
312
|
+
force: true
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
function removeDirectory(path) {
|
|
316
|
+
(0, node_fs.rmSync)(path, {
|
|
317
|
+
recursive: true,
|
|
318
|
+
force: true
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
//#endregion
|
|
323
|
+
//#region ../../@warlock.js/fs/src/rename.ts
|
|
324
|
+
/**
|
|
325
|
+
* Rename / move a file or directory.
|
|
326
|
+
*/
|
|
327
|
+
async function renameFileAsync(from, to) {
|
|
328
|
+
await (0, node_fs_promises.rename)(from, to);
|
|
329
|
+
}
|
|
330
|
+
function renameFile(from, to) {
|
|
331
|
+
(0, node_fs.renameSync)(from, to);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
//#endregion
|
|
335
|
+
//#region ../../@warlock.js/fs/src/stats.ts
|
|
336
|
+
/**
|
|
337
|
+
* Get last-modified time of a path. Returns a Date.
|
|
338
|
+
*
|
|
339
|
+
* @throws if the path does not exist.
|
|
340
|
+
*/
|
|
341
|
+
async function lastModifiedAsync(path) {
|
|
342
|
+
return (await (0, node_fs_promises.stat)(path)).mtime;
|
|
343
|
+
}
|
|
344
|
+
function lastModified(path) {
|
|
345
|
+
return (0, node_fs.statSync)(path).mtime;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Return raw fs.Stats for a path.
|
|
349
|
+
*/
|
|
350
|
+
async function statsAsync(path) {
|
|
351
|
+
return (0, node_fs_promises.stat)(path);
|
|
352
|
+
}
|
|
353
|
+
function stats(path) {
|
|
354
|
+
return (0, node_fs.statSync)(path);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
//#endregion
|
|
358
|
+
//#region ../../@warlock.js/fs/src/write.ts
|
|
359
|
+
/**
|
|
360
|
+
* Write a UTF-8 string to disk, creating any missing parent directories.
|
|
361
|
+
*/
|
|
362
|
+
async function putFileAsync(filePath, content) {
|
|
363
|
+
await (0, node_fs_promises.mkdir)(node_path.default.dirname(filePath), { recursive: true });
|
|
364
|
+
await (0, node_fs_promises.writeFile)(filePath, content, "utf-8");
|
|
365
|
+
}
|
|
366
|
+
function putFile(filePath, content) {
|
|
367
|
+
(0, node_fs.mkdirSync)(node_path.default.dirname(filePath), { recursive: true });
|
|
368
|
+
(0, node_fs.writeFileSync)(filePath, content, "utf-8");
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Write a JSON-serialisable value to disk (pretty-printed, 2-space indent).
|
|
372
|
+
*/
|
|
373
|
+
async function putJsonFileAsync(filePath, value) {
|
|
374
|
+
await putFileAsync(filePath, JSON.stringify(value, null, 2));
|
|
375
|
+
}
|
|
376
|
+
function putJsonFile(filePath, value) {
|
|
377
|
+
putFile(filePath, JSON.stringify(value, null, 2));
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
//#endregion
|
|
381
|
+
exports.atomicWriteAsync = atomicWriteAsync;
|
|
382
|
+
exports.atomicWriteJsonAsync = atomicWriteJsonAsync;
|
|
383
|
+
exports.copyDirectory = copyDirectory;
|
|
384
|
+
exports.copyDirectoryAsync = copyDirectoryAsync;
|
|
385
|
+
exports.copyFile = copyFile;
|
|
386
|
+
exports.copyFileAsync = copyFileAsync;
|
|
387
|
+
exports.directoryExists = directoryExists;
|
|
388
|
+
exports.directoryExistsAsync = directoryExistsAsync;
|
|
389
|
+
exports.ensureDirectory = ensureDirectory;
|
|
390
|
+
exports.ensureDirectoryAsync = ensureDirectoryAsync;
|
|
391
|
+
exports.fileExists = fileExists;
|
|
392
|
+
exports.fileExistsAsync = fileExistsAsync;
|
|
393
|
+
exports.getFile = getFile;
|
|
394
|
+
exports.getFileAsync = getFileAsync;
|
|
395
|
+
exports.getJsonFile = getJsonFile;
|
|
396
|
+
exports.getJsonFileAsync = getJsonFileAsync;
|
|
397
|
+
exports.hashBuffer = hashBuffer;
|
|
398
|
+
exports.hashFile = hashFile;
|
|
399
|
+
exports.hashFileAsync = hashFileAsync;
|
|
400
|
+
exports.hashFileSmallAsync = hashFileSmallAsync;
|
|
401
|
+
exports.hashString = hashString;
|
|
402
|
+
exports.lastModified = lastModified;
|
|
403
|
+
exports.lastModifiedAsync = lastModifiedAsync;
|
|
404
|
+
exports.list = list;
|
|
405
|
+
exports.listAsync = listAsync;
|
|
406
|
+
exports.listDirectories = listDirectories;
|
|
407
|
+
exports.listDirectoriesAsync = listDirectoriesAsync;
|
|
408
|
+
exports.listFiles = listFiles;
|
|
409
|
+
exports.listFilesAsync = listFilesAsync;
|
|
410
|
+
exports.pathExists = pathExists;
|
|
411
|
+
exports.pathExistsAsync = pathExistsAsync;
|
|
412
|
+
exports.putFile = putFile;
|
|
413
|
+
exports.putFileAsync = putFileAsync;
|
|
414
|
+
exports.putJsonFile = putJsonFile;
|
|
415
|
+
exports.putJsonFileAsync = putJsonFileAsync;
|
|
416
|
+
exports.removeDirectory = removeDirectory;
|
|
417
|
+
exports.removeDirectoryAsync = removeDirectoryAsync;
|
|
418
|
+
exports.renameFile = renameFile;
|
|
419
|
+
exports.renameFileAsync = renameFileAsync;
|
|
420
|
+
exports.stats = stats;
|
|
421
|
+
exports.statsAsync = statsAsync;
|
|
422
|
+
exports.unlink = unlink;
|
|
423
|
+
exports.unlinkAsync = unlinkAsync;
|
|
424
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["path","path","path","path"],"sources":["../../../../../@warlock.js/fs/src/atomic.ts","../../../../../@warlock.js/fs/src/copy.ts","../../../../../@warlock.js/fs/src/dirs.ts","../../../../../@warlock.js/fs/src/exists.ts","../../../../../@warlock.js/fs/src/hash.ts","../../../../../@warlock.js/fs/src/list.ts","../../../../../@warlock.js/fs/src/read.ts","../../../../../@warlock.js/fs/src/remove.ts","../../../../../@warlock.js/fs/src/rename.ts","../../../../../@warlock.js/fs/src/stats.ts","../../../../../@warlock.js/fs/src/write.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { mkdir, rename, unlink, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\n/**\n * Write a file atomically.\n *\n * Writes to a uniquely-named sibling temp file first, then renames it onto\n * the target. Readers either see the old content or the complete new\n * content — never a half-written file. If anything fails mid-write the\n * temp file is cleaned up.\n *\n * Parent directories are created if missing.\n *\n * @example\n * await atomicWriteAsync(\"manifest.json\", JSON.stringify(data));\n */\nexport async function atomicWriteAsync(filePath: string, content: string | Buffer): Promise<void> {\n const dir = path.dirname(filePath);\n await mkdir(dir, { recursive: true });\n\n // Random suffix so concurrent writers don't fight over the same temp file.\n const tempPath = path.join(dir, `.${path.basename(filePath)}.${randomBytes(6).toString(\"hex\")}.tmp`);\n\n try {\n await writeFile(tempPath, content);\n await rename(tempPath, filePath);\n } catch (error) {\n await unlink(tempPath).catch(() => undefined);\n throw error;\n }\n}\n\n/**\n * Atomic write convenience for JSON values (pretty-printed, 2-space indent).\n */\nexport async function atomicWriteJsonAsync(filePath: string, value: unknown): Promise<void> {\n await atomicWriteAsync(filePath, JSON.stringify(value, null, 2));\n}\n","import { cp, copyFile as copyFilePromise, mkdir } from \"node:fs/promises\";\nimport { copyFileSync, cpSync, mkdirSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Copy a single file. Creates the destination's parent directory if needed.\n */\nexport async function copyFileAsync(source: string, destination: string): Promise<void> {\n await mkdir(path.dirname(destination), { recursive: true });\n await copyFilePromise(source, destination);\n}\n\nexport function copyFile(source: string, destination: string): void {\n mkdirSync(path.dirname(destination), { recursive: true });\n copyFileSync(source, destination);\n}\n\n/**\n * Recursively copy a directory.\n */\nexport async function copyDirectoryAsync(source: string, destination: string): Promise<void> {\n await cp(source, destination, { recursive: true });\n}\n\nexport function copyDirectory(source: string, destination: string): void {\n cpSync(source, destination, { recursive: true });\n}\n","import { mkdir } from \"node:fs/promises\";\nimport { mkdirSync } from \"node:fs\";\n\n/**\n * Ensure a directory exists (recursively creating parents).\n * Idempotent — no error if the directory already exists.\n */\nexport async function ensureDirectoryAsync(path: string): Promise<void> {\n await mkdir(path, { recursive: true });\n}\n\nexport function ensureDirectory(path: string): void {\n mkdirSync(path, { recursive: true });\n}\n","import { access, stat } from \"node:fs/promises\";\nimport { accessSync, statSync } from \"node:fs\";\n\n/**\n * Check whether a path exists, REGARDLESS of type — resolves `true` for both\n * files and directories, `false` only when nothing is there (ENOENT).\n *\n * Pick the right check for the job:\n * - `pathExistsAsync` — anything at this path (file OR directory).\n * - `fileExistsAsync` — exists AND is a regular file.\n * - `directoryExistsAsync` — exists AND is a directory.\n *\n * @example\n * if (await pathExistsAsync(\"/var/data\")) {\n * // something is there — could be a file or a folder\n * }\n */\nexport async function pathExistsAsync(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function pathExists(path: string): boolean {\n try {\n accessSync(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check whether a path exists AND is a regular file. Resolves `false` for a\n * directory — use `directoryExistsAsync` for folders, or `pathExistsAsync`\n * when the type does not matter.\n *\n * @example\n * if (await fileExistsAsync(\"/etc/config.json\")) {\n * const raw = await readFile(\"/etc/config.json\", \"utf8\");\n * }\n */\nexport async function fileExistsAsync(path: string): Promise<boolean> {\n try {\n return (await stat(path)).isFile();\n } catch {\n return false;\n }\n}\n\nexport function fileExists(path: string): boolean {\n try {\n return statSync(path).isFile();\n } catch {\n return false;\n }\n}\n\n/**\n * Check whether a path exists AND is a directory. Resolves `false` for a\n * regular file — use `fileExistsAsync` for files, or `pathExistsAsync` when\n * the type does not matter.\n *\n * @example\n * if (await directoryExistsAsync(\"/var/uploads\")) {\n * const entries = await readdir(\"/var/uploads\");\n * }\n */\nexport async function directoryExistsAsync(path: string): Promise<boolean> {\n try {\n return (await stat(path)).isDirectory();\n } catch {\n return false;\n }\n}\n\nexport function directoryExists(path: string): boolean {\n try {\n return statSync(path).isDirectory();\n } catch {\n return false;\n }\n}\n","import { createHash } from \"node:crypto\";\nimport { createReadStream } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { readFileSync } from \"node:fs\";\n\nexport type HashAlgorithm = \"sha256\" | \"sha1\" | \"md5\" | \"sha512\";\n\n/**\n * Compute a hex digest of a file's contents. Uses streaming for large\n * files so memory doesn't spike when hashing big assets.\n *\n * @param path - File to hash.\n * @param algorithm - Hash algorithm (default `sha256`).\n *\n * @example\n * const fingerprint = await hashFile(\"./bundle.js\");\n * const quick = await hashFile(\"./small.txt\", \"md5\");\n */\nexport function hashFileAsync(\n path: string,\n algorithm: HashAlgorithm = \"sha256\",\n): Promise<string> {\n return new Promise((resolve, reject) => {\n const hash = createHash(algorithm);\n const stream = createReadStream(path);\n stream.on(\"data\", chunk => hash.update(chunk));\n stream.on(\"end\", () => resolve(hash.digest(\"hex\")));\n stream.on(\"error\", reject);\n });\n}\n\nexport function hashFile(path: string, algorithm: HashAlgorithm = \"sha256\"): string {\n return createHash(algorithm).update(readFileSync(path)).digest(\"hex\");\n}\n\n/**\n * Hash an in-memory string without touching disk. Convenient when the\n * caller already has the content loaded (e.g. file watcher diffing).\n */\nexport function hashString(content: string, algorithm: HashAlgorithm = \"sha256\"): string {\n return createHash(algorithm).update(content).digest(\"hex\");\n}\n\n/**\n * Hash an arbitrary buffer.\n */\nexport function hashBuffer(\n content: Buffer | Uint8Array,\n algorithm: HashAlgorithm = \"sha256\",\n): string {\n return createHash(algorithm).update(content).digest(\"hex\");\n}\n\n/**\n * Like `hashFileAsync` but reads the file in one go. Slightly faster for\n * small files; use the streaming variant for anything > ~1 MB.\n */\nexport async function hashFileSmallAsync(\n path: string,\n algorithm: HashAlgorithm = \"sha256\",\n): Promise<string> {\n return createHash(algorithm).update(await readFile(path)).digest(\"hex\");\n}\n","import { readdir, stat } from \"node:fs/promises\";\nimport { readdirSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * List immediate children of a directory (files + subdirs), returning\n * full paths.\n */\nexport async function listAsync(directoryPath: string): Promise<string[]> {\n const entries = await readdir(directoryPath);\n return entries.map(entry => path.join(directoryPath, entry));\n}\n\nexport function list(directoryPath: string): string[] {\n return readdirSync(directoryPath).map(entry => path.join(directoryPath, entry));\n}\n\n/**\n * List only files (not subdirectories) directly inside a directory.\n */\nexport async function listFilesAsync(directoryPath: string): Promise<string[]> {\n const entries = await listAsync(directoryPath);\n const checks = await Promise.all(\n entries.map(async entry => ((await stat(entry)).isFile() ? entry : null)),\n );\n return checks.filter((entry): entry is string => entry !== null);\n}\n\nexport function listFiles(directoryPath: string): string[] {\n return list(directoryPath).filter(entry => statSync(entry).isFile());\n}\n\n/**\n * List only subdirectories directly inside a directory.\n */\nexport async function listDirectoriesAsync(directoryPath: string): Promise<string[]> {\n const entries = await listAsync(directoryPath);\n const checks = await Promise.all(\n entries.map(async entry => ((await stat(entry)).isDirectory() ? entry : null)),\n );\n return checks.filter((entry): entry is string => entry !== null);\n}\n\nexport function listDirectories(directoryPath: string): string[] {\n return list(directoryPath).filter(entry => statSync(entry).isDirectory());\n}\n","import { readFile } from \"node:fs/promises\";\nimport { readFileSync } from \"node:fs\";\n\n/**\n * Read a file as UTF-8 text.\n */\nexport async function getFileAsync(path: string): Promise<string> {\n return readFile(path, \"utf-8\");\n}\n\nexport function getFile(path: string): string {\n return readFileSync(path, \"utf-8\");\n}\n\n/**\n * Read a JSON file and parse it.\n *\n * @throws if the file does not exist or contains invalid JSON.\n */\nexport async function getJsonFileAsync<T = unknown>(path: string): Promise<T> {\n return JSON.parse(await getFileAsync(path)) as T;\n}\n\nexport function getJsonFile<T = unknown>(path: string): T {\n return JSON.parse(getFile(path)) as T;\n}\n","import { rm, unlink as unlinkPromise } from \"node:fs/promises\";\nimport { rmSync, unlinkSync } from \"node:fs\";\n\n/**\n * Delete a single file. No error if the file doesn't exist.\n */\nexport async function unlinkAsync(path: string): Promise<void> {\n try {\n await unlinkPromise(path);\n } catch (error: any) {\n if (error?.code !== \"ENOENT\") throw error;\n }\n}\n\nexport function unlink(path: string): void {\n try {\n unlinkSync(path);\n } catch (error: any) {\n if (error?.code !== \"ENOENT\") throw error;\n }\n}\n\n/**\n * Recursively delete a directory and its contents. No error if missing.\n */\nexport async function removeDirectoryAsync(path: string): Promise<void> {\n await rm(path, { recursive: true, force: true });\n}\n\nexport function removeDirectory(path: string): void {\n rmSync(path, { recursive: true, force: true });\n}\n","import { rename as renamePromise } from \"node:fs/promises\";\nimport { renameSync } from \"node:fs\";\n\n/**\n * Rename / move a file or directory.\n */\nexport async function renameFileAsync(from: string, to: string): Promise<void> {\n await renamePromise(from, to);\n}\n\nexport function renameFile(from: string, to: string): void {\n renameSync(from, to);\n}\n","import { stat as statPromise } from \"node:fs/promises\";\nimport { statSync } from \"node:fs\";\n\n/**\n * Get last-modified time of a path. Returns a Date.\n *\n * @throws if the path does not exist.\n */\nexport async function lastModifiedAsync(path: string): Promise<Date> {\n return (await statPromise(path)).mtime;\n}\n\nexport function lastModified(path: string): Date {\n return statSync(path).mtime;\n}\n\n/**\n * Return raw fs.Stats for a path.\n */\nexport async function statsAsync(path: string) {\n return statPromise(path);\n}\n\nexport function stats(path: string) {\n return statSync(path);\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Write a UTF-8 string to disk, creating any missing parent directories.\n */\nexport async function putFileAsync(filePath: string, content: string): Promise<void> {\n await mkdir(path.dirname(filePath), { recursive: true });\n await writeFile(filePath, content, \"utf-8\");\n}\n\nexport function putFile(filePath: string, content: string): void {\n mkdirSync(path.dirname(filePath), { recursive: true });\n writeFileSync(filePath, content, \"utf-8\");\n}\n\n/**\n * Write a JSON-serialisable value to disk (pretty-printed, 2-space indent).\n */\nexport async function putJsonFileAsync(filePath: string, value: unknown): Promise<void> {\n await putFileAsync(filePath, JSON.stringify(value, null, 2));\n}\n\nexport function putJsonFile(filePath: string, value: unknown): void {\n putFile(filePath, JSON.stringify(value, null, 2));\n}\n"],"mappings":"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"}
|
package/esm/atomic.d.mts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region ../../@warlock.js/fs/src/atomic.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Write a file atomically.
|
|
4
|
+
*
|
|
5
|
+
* Writes to a uniquely-named sibling temp file first, then renames it onto
|
|
6
|
+
* the target. Readers either see the old content or the complete new
|
|
7
|
+
* content — never a half-written file. If anything fails mid-write the
|
|
8
|
+
* temp file is cleaned up.
|
|
9
|
+
*
|
|
10
|
+
* Parent directories are created if missing.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* await atomicWriteAsync("manifest.json", JSON.stringify(data));
|
|
14
|
+
*/
|
|
15
|
+
declare function atomicWriteAsync(filePath: string, content: string | Buffer): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Atomic write convenience for JSON values (pretty-printed, 2-space indent).
|
|
18
|
+
*/
|
|
19
|
+
declare function atomicWriteJsonAsync(filePath: string, value: unknown): Promise<void>;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { atomicWriteAsync, atomicWriteJsonAsync };
|
|
22
|
+
//# sourceMappingURL=atomic.d.mts.map
|
package/esm/atomic.mjs
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { mkdir, rename, unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
//#region ../../@warlock.js/fs/src/atomic.ts
|
|
6
|
+
/**
|
|
7
|
+
* Write a file atomically.
|
|
8
|
+
*
|
|
9
|
+
* Writes to a uniquely-named sibling temp file first, then renames it onto
|
|
10
|
+
* the target. Readers either see the old content or the complete new
|
|
11
|
+
* content — never a half-written file. If anything fails mid-write the
|
|
12
|
+
* temp file is cleaned up.
|
|
13
|
+
*
|
|
14
|
+
* Parent directories are created if missing.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* await atomicWriteAsync("manifest.json", JSON.stringify(data));
|
|
18
|
+
*/
|
|
19
|
+
async function atomicWriteAsync(filePath, content) {
|
|
20
|
+
const dir = path.dirname(filePath);
|
|
21
|
+
await mkdir(dir, { recursive: true });
|
|
22
|
+
const tempPath = path.join(dir, `.${path.basename(filePath)}.${randomBytes(6).toString("hex")}.tmp`);
|
|
23
|
+
try {
|
|
24
|
+
await writeFile(tempPath, content);
|
|
25
|
+
await rename(tempPath, filePath);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
await unlink(tempPath).catch(() => void 0);
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Atomic write convenience for JSON values (pretty-printed, 2-space indent).
|
|
33
|
+
*/
|
|
34
|
+
async function atomicWriteJsonAsync(filePath, value) {
|
|
35
|
+
await atomicWriteAsync(filePath, JSON.stringify(value, null, 2));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
39
|
+
export { atomicWriteAsync, atomicWriteJsonAsync };
|
|
40
|
+
//# sourceMappingURL=atomic.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atomic.mjs","names":[],"sources":["../../../../../@warlock.js/fs/src/atomic.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { mkdir, rename, unlink, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\n/**\n * Write a file atomically.\n *\n * Writes to a uniquely-named sibling temp file first, then renames it onto\n * the target. Readers either see the old content or the complete new\n * content — never a half-written file. If anything fails mid-write the\n * temp file is cleaned up.\n *\n * Parent directories are created if missing.\n *\n * @example\n * await atomicWriteAsync(\"manifest.json\", JSON.stringify(data));\n */\nexport async function atomicWriteAsync(filePath: string, content: string | Buffer): Promise<void> {\n const dir = path.dirname(filePath);\n await mkdir(dir, { recursive: true });\n\n // Random suffix so concurrent writers don't fight over the same temp file.\n const tempPath = path.join(dir, `.${path.basename(filePath)}.${randomBytes(6).toString(\"hex\")}.tmp`);\n\n try {\n await writeFile(tempPath, content);\n await rename(tempPath, filePath);\n } catch (error) {\n await unlink(tempPath).catch(() => undefined);\n throw error;\n }\n}\n\n/**\n * Atomic write convenience for JSON values (pretty-printed, 2-space indent).\n */\nexport async function atomicWriteJsonAsync(filePath: string, value: unknown): Promise<void> {\n await atomicWriteAsync(filePath, JSON.stringify(value, null, 2));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiBA,eAAsB,iBAAiB,UAAkB,SAAyC;CAChG,MAAM,MAAM,KAAK,QAAQ,QAAQ;CACjC,MAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;CAGpC,MAAM,WAAW,KAAK,KAAK,KAAK,IAAI,KAAK,SAAS,QAAQ,EAAE,GAAG,YAAY,CAAC,EAAE,SAAS,KAAK,EAAE,KAAK;CAEnG,IAAI;EACF,MAAM,UAAU,UAAU,OAAO;EACjC,MAAM,OAAO,UAAU,QAAQ;CACjC,SAAS,OAAO;EACd,MAAM,OAAO,QAAQ,EAAE,YAAY,MAAS;EAC5C,MAAM;CACR;AACF;;;;AAKA,eAAsB,qBAAqB,UAAkB,OAA+B;CAC1F,MAAM,iBAAiB,UAAU,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AACjE"}
|
package/esm/copy.d.mts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region ../../@warlock.js/fs/src/copy.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Copy a single file. Creates the destination's parent directory if needed.
|
|
4
|
+
*/
|
|
5
|
+
declare function copyFileAsync(source: string, destination: string): Promise<void>;
|
|
6
|
+
declare function copyFile(source: string, destination: string): void;
|
|
7
|
+
/**
|
|
8
|
+
* Recursively copy a directory.
|
|
9
|
+
*/
|
|
10
|
+
declare function copyDirectoryAsync(source: string, destination: string): Promise<void>;
|
|
11
|
+
declare function copyDirectory(source: string, destination: string): void;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { copyDirectory, copyDirectoryAsync, copyFile, copyFileAsync };
|
|
14
|
+
//# sourceMappingURL=copy.d.mts.map
|
package/esm/copy.mjs
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { copyFile, cp, mkdir } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { copyFileSync, cpSync, mkdirSync } from "node:fs";
|
|
4
|
+
|
|
5
|
+
//#region ../../@warlock.js/fs/src/copy.ts
|
|
6
|
+
/**
|
|
7
|
+
* Copy a single file. Creates the destination's parent directory if needed.
|
|
8
|
+
*/
|
|
9
|
+
async function copyFileAsync(source, destination) {
|
|
10
|
+
await mkdir(path.dirname(destination), { recursive: true });
|
|
11
|
+
await copyFile(source, destination);
|
|
12
|
+
}
|
|
13
|
+
function copyFile$1(source, destination) {
|
|
14
|
+
mkdirSync(path.dirname(destination), { recursive: true });
|
|
15
|
+
copyFileSync(source, destination);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Recursively copy a directory.
|
|
19
|
+
*/
|
|
20
|
+
async function copyDirectoryAsync(source, destination) {
|
|
21
|
+
await cp(source, destination, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
function copyDirectory(source, destination) {
|
|
24
|
+
cpSync(source, destination, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
export { copyDirectory, copyDirectoryAsync, copyFile$1 as copyFile, copyFileAsync };
|
|
29
|
+
//# sourceMappingURL=copy.mjs.map
|
package/esm/copy.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy.mjs","names":["copyFilePromise","copyFile"],"sources":["../../../../../@warlock.js/fs/src/copy.ts"],"sourcesContent":["import { cp, copyFile as copyFilePromise, mkdir } from \"node:fs/promises\";\nimport { copyFileSync, cpSync, mkdirSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Copy a single file. Creates the destination's parent directory if needed.\n */\nexport async function copyFileAsync(source: string, destination: string): Promise<void> {\n await mkdir(path.dirname(destination), { recursive: true });\n await copyFilePromise(source, destination);\n}\n\nexport function copyFile(source: string, destination: string): void {\n mkdirSync(path.dirname(destination), { recursive: true });\n copyFileSync(source, destination);\n}\n\n/**\n * Recursively copy a directory.\n */\nexport async function copyDirectoryAsync(source: string, destination: string): Promise<void> {\n await cp(source, destination, { recursive: true });\n}\n\nexport function copyDirectory(source: string, destination: string): void {\n cpSync(source, destination, { recursive: true });\n}\n"],"mappings":";;;;;;;;AAOA,eAAsB,cAAc,QAAgB,aAAoC;CACtF,MAAM,MAAM,KAAK,QAAQ,WAAW,GAAG,EAAE,WAAW,KAAK,CAAC;CAC1D,MAAMA,SAAgB,QAAQ,WAAW;AAC3C;AAEA,SAAgBC,WAAS,QAAgB,aAA2B;CAClE,UAAU,KAAK,QAAQ,WAAW,GAAG,EAAE,WAAW,KAAK,CAAC;CACxD,aAAa,QAAQ,WAAW;AAClC;;;;AAKA,eAAsB,mBAAmB,QAAgB,aAAoC;CAC3F,MAAM,GAAG,QAAQ,aAAa,EAAE,WAAW,KAAK,CAAC;AACnD;AAEA,SAAgB,cAAc,QAAgB,aAA2B;CACvE,OAAO,QAAQ,aAAa,EAAE,WAAW,KAAK,CAAC;AACjD"}
|
package/esm/dirs.d.mts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region ../../@warlock.js/fs/src/dirs.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Ensure a directory exists (recursively creating parents).
|
|
4
|
+
* Idempotent — no error if the directory already exists.
|
|
5
|
+
*/
|
|
6
|
+
declare function ensureDirectoryAsync(path: string): Promise<void>;
|
|
7
|
+
declare function ensureDirectory(path: string): void;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { ensureDirectory, ensureDirectoryAsync };
|
|
10
|
+
//# sourceMappingURL=dirs.d.mts.map
|