@ix-xs/node-comfort 1.0.57 → 1.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/src/fs.js DELETED
@@ -1,656 +0,0 @@
1
- const { readdirSync, existsSync, mkdirSync, rmSync, writeFileSync, unlinkSync, copyFileSync, readFileSync, watch } = require("node:fs");
2
- const { resolve, dirname, sep, isAbsolute, join, relative, basename } = require("node:path");
3
-
4
- try {
5
- process.loadEnvFile();
6
- }
7
- catch {}
8
-
9
- /**
10
- * @param {string} path
11
- */
12
- const _format = (path) => {
13
- return path.replace(/\//g, sep).replace(/\\/g, sep);
14
- };
15
- /**
16
- * @returns {string|undefined}
17
- */
18
- const _caller = () => {
19
- const opst = Error.prepareStackTrace;
20
- Error.prepareStackTrace = (_, stack) => stack;
21
- const e = new Error();
22
- const s = e.stack;
23
- Error.prepareStackTrace = opst;
24
-
25
- if (s) {
26
- for (const cs of s) {
27
- const name = cs.getFileName();
28
- if (
29
- name &&
30
- !name.startsWith("node:internal") &&
31
- !name.includes("node_modules") &&
32
- name !== s[0].getFileName()
33
- ) {
34
- return _format(name);
35
- }
36
- }
37
- }
38
- return undefined;
39
- };
40
- /**
41
- * @param {string} path
42
- * @param {boolean} [recursive=true]
43
- * @param {"folder"|"file"} [type="folder"]
44
- * @returns {string[]}
45
- */
46
- const _walk = (path = process.cwd(), recursive = true, type = "folder") => {
47
- let result = [];
48
- try {
49
- for (const entry of readdirSync(path, { withFileTypes: true })) {
50
- if (entry.name.includes("node_modules")) continue;
51
- const _ = resolve(path, entry.name);
52
-
53
- if (type === "folder" && entry.isDirectory()) {
54
- result.push(_);
55
- if (recursive) result = result.concat(_walk(_, recursive, type));
56
- } else if (type === "file" && entry.isFile()) {
57
- result.push(_);
58
- } else if (type === "file" && entry.isDirectory() && recursive) {
59
- result = result.concat(_walk(_, recursive, type));
60
- }
61
- }
62
- return result;
63
- } catch (error) {
64
- return result;
65
- }
66
- };
67
- /**
68
- * @param {string} path
69
- * @param {string} name
70
- * @returns {string|undefined}
71
- */
72
- const _firstFolder = (path, name) => {
73
- try {
74
- const entries = readdirSync(path, { withFileTypes: true });
75
- for (const entry of entries) {
76
- if (entry.name === name && entry.isDirectory()) {
77
- return resolve(path, name);
78
- }
79
- }
80
- for (const entry of entries) {
81
- if (entry.isDirectory() && !entry.name.includes("node_modules")) {
82
- const result = _firstFolder(resolve(path, entry.name), name);
83
- if (result) return result;
84
- }
85
- }
86
- } catch {}
87
- return undefined;
88
- };
89
- /**
90
- * @param {string} path
91
- * @param {string} name
92
- * @returns {string|undefined}
93
- */
94
- const _firstFile = (path, name) => {
95
- try {
96
- const entries = readdirSync(path, { withFileTypes: true });
97
- for (const entry of entries) {
98
- if (entry.name === name && entry.isFile()) {
99
- return resolve(path, name);
100
- }
101
- }
102
- for (const entry of entries) {
103
- if (entry.isDirectory() && !entry.name.includes("node_modules")) {
104
- const result = _firstFile(resolve(path, entry.name), name);
105
- if (result) return result;
106
- }
107
- }
108
- } catch {}
109
- return undefined;
110
- };
111
- /**
112
- * @param {string} [path=process.cwd()]
113
- * @param {"folder"|"file"} [type="folder"]
114
- * @returns {string|undefined}
115
- */
116
- const _target = (path = process.cwd(), type = "folder") => {
117
- if (path === process.cwd()) return path;
118
-
119
- let absolute;
120
- const caller = dirname(_caller() || process.cwd());
121
-
122
- if (
123
- _format(path).startsWith(_format("./")) ||
124
- _format(path).startsWith(_format("../"))
125
- ) {
126
- absolute = resolve(caller, path);
127
- } else if (isAbsolute(path)) {
128
- absolute = _format(path);
129
- } else {
130
- absolute = resolve(process.cwd(), _format(path));
131
- if (!existsSync(absolute)) {
132
- absolute =
133
- type === "folder"
134
- ? (_firstFolder(process.cwd(), _format(path)) ?? undefined)
135
- : (_firstFile(process.cwd(), _format(path)) ?? undefined);
136
- }
137
- }
138
-
139
- if (absolute && existsSync(absolute)) return _format(absolute);
140
- return undefined;
141
- };
142
-
143
- module.exports = {
144
- /**
145
- * @param {string} value
146
- */
147
- getEnv(value, envFilePath) {
148
- return process.env[value];
149
- },
150
- /**
151
- * @param {string} [path=process.cwd()]
152
- */
153
- createPath(path = process.cwd()) {
154
- const target = _target(path);
155
- return target
156
- ? target
157
- : isAbsolute(path)
158
- ? path
159
- : path.startsWith("./") || path.startsWith("../")
160
- ? resolve(dirname(_caller()), path)
161
- : resolve(process.cwd(), path);
162
- },
163
- /**
164
- * @param {string} [path]
165
- * @param {boolean} [recursive]
166
- */
167
- getFoldersIn(path = process.cwd(), recursive = true) {
168
- const target = _target(path ?? process.cwd());
169
- return target ? _walk(target, recursive) : undefined;
170
- },
171
- /**
172
- * @param {string} [path]
173
- */
174
- getFolder(path = process.cwd()) {
175
- return _target(path ?? process.cwd());
176
- },
177
- /**
178
- * @param {string} [path]
179
- * @param {boolean} [recursive]
180
- */
181
- getFilesIn(path = process.cwd(), recursive = true) {
182
- const target = _target(path ?? process.cwd());
183
- return target ? _walk(target, recursive, "file") : undefined;
184
- },
185
- /**
186
- * @param {string} path
187
- */
188
- getFile(path) {
189
- return path ? _target(path, "file") : path;
190
- },
191
- /**
192
- * @param {string} path
193
- * @param {boolean} [force]
194
- */
195
- createFolder(path, force = false) {
196
- if (!path) return undefined;
197
- const target = this.createPath(path);
198
-
199
- try {
200
- if (this.getFolder(target)) {
201
- if (force) {
202
- this.deleteFolder(target);
203
- mkdirSync(target, { recursive: true });
204
- return true;
205
- }
206
- return false;
207
- }
208
- mkdirSync(target, { recursive: true });
209
- return true;
210
- } catch {
211
- return false;
212
- }
213
- },
214
- /**
215
- * @param {string} path
216
- * @param {boolean} [force]
217
- * @param {string|object|null|undefined} [data]
218
- */
219
- createFile(path, force = false, data) {
220
- if (!path) return undefined;
221
- const target = this.createPath(path);
222
- const content =
223
- data === null || typeof data === "undefined"
224
- ? ""
225
- : typeof data === "string"
226
- ? data
227
- : JSON.stringify(data, null, 2);
228
-
229
- try {
230
- if (this.getFile(target)) {
231
- if (force) {
232
- this.deleteFile(target);
233
- writeFileSync(target, content, "utf8");
234
- return true;
235
- }
236
- return false;
237
- }
238
-
239
- if (!this.getFolder(dirname(target))) {
240
- this.createFolder(dirname(target));
241
- }
242
-
243
- writeFileSync(target, content, "utf8");
244
- return true;
245
- } catch {
246
- return false;
247
- }
248
- },
249
- /**
250
- * @param {string} [path]
251
- * @param {(folder: string) => boolean} [filter]
252
- */
253
- deleteFoldersIn(path = process.cwd(), filter = () => true) {
254
- const target = _target(path);
255
- if (!target) return undefined;
256
-
257
- const folders = this.getFoldersIn(target);
258
- let deleted = 0;
259
-
260
- for (const folder of folders.map(_format)) {
261
- if (!filter(folder)) continue;
262
- this.deleteFolder(folder);
263
- deleted++;
264
- }
265
- return deleted;
266
- },
267
- /**
268
- * @param {string} path
269
- */
270
- deleteFolder(path) {
271
- const target = path ? _target(path) : path;
272
- if (!target || !this.getFolder(target)) return undefined;
273
-
274
- try {
275
- rmSync(target, { recursive: true, force: true });
276
- return true;
277
- } catch {
278
- return false;
279
- }
280
- },
281
- /**
282
- * @param {string} [path=process.cwd()]
283
- * @param {boolean} [recursive=false]
284
- * @param {(file: string) => boolean} [filter]
285
- */
286
- deleteFilesIn(path = process.cwd(), recursive = false, filter = () => true) {
287
- const target = _target(path);
288
- if (!target) return undefined;
289
-
290
- const files = this.getFilesIn(target, recursive);
291
- let deleted = 0;
292
-
293
- for (const file of files.map(_format)) {
294
- if (!filter(file)) continue;
295
- this.deleteFile(file);
296
- deleted++;
297
- }
298
- return deleted;
299
- },
300
- /**
301
- * @param {string} path
302
- */
303
- deleteFile(path) {
304
- const target = path ? _target(path, "file") : path;
305
- if (!target || !this.getFile(target)) return undefined;
306
-
307
- try {
308
- unlinkSync(target);
309
- return true;
310
- } catch {
311
- return false;
312
- }
313
- },
314
- /**
315
- * @param {Object} options
316
- * @param {string} options.dest
317
- * @param {string} [options.path]
318
- * @param {boolean} [options.recursive=true]
319
- * @param {boolean} [options.withFiles=false]
320
- * @param {boolean} [options.force=false]
321
- * @param {(folder: string) => boolean} [options.filter]
322
- */
323
- copyFoldersIn(options) {
324
- const target = _target(options.path ?? process.cwd());
325
- if (!target || !options.dest) return undefined;
326
-
327
- const folders = this.getFoldersIn(target, options.recursive ?? true) ?? [];
328
- options.filter =
329
- typeof options.filter === "function" ? options.filter : () => true;
330
- let copied = 0;
331
-
332
- for (const folder of folders.map(_format)) {
333
- if (!options.filter(folder)) continue;
334
-
335
- const destFolder = join(
336
- this.createPath(options.dest),
337
- relative(target, folder),
338
- );
339
-
340
- if (options.force && this.getFolder(destFolder)) {
341
- this.deleteFolder(destFolder);
342
- }
343
-
344
- this.createFolder(destFolder);
345
- copied++;
346
-
347
- if (options.withFiles) {
348
- if (options.recursive) {
349
- for (const file of this.getFilesIn(folder, true) ?? []) {
350
- const destFile = join(destFolder, relative(folder, file));
351
- this.createFolder(dirname(destFile));
352
- copyFileSync(file, destFile);
353
- }
354
- } else {
355
- for (const file of this.getFilesIn(folder, false) ?? []) {
356
- const destFile = join(destFolder, basename(file));
357
- copyFileSync(file, destFile);
358
- }
359
- }
360
- }
361
- }
362
- return copied;
363
- },
364
- /**
365
- * @param {Object} options
366
- * @param {string} options.dest
367
- * @param {string} [options.path]
368
- * @param {boolean} [options.recursive=false]
369
- * @param {boolean} [options.withFiles=false]
370
- * @param {boolean} [options.force=false]
371
- */
372
- copyFolder(options) {
373
- const target = _target(options.path ?? process.cwd());
374
- const dest = this.createPath(options.dest);
375
-
376
- if (!target || !dest) return undefined;
377
-
378
- if (options.force && this.getFolder(dest)) {
379
- this.deleteFolder(dest);
380
- }
381
-
382
- this.createFolder(dest);
383
-
384
- if (options.recursive) {
385
- for (const folder of this.getFoldersIn(target, true) ?? []) {
386
- const destFolder = join(dest, relative(target, folder));
387
- this.createFolder(destFolder);
388
-
389
- if (options.withFiles) {
390
- for (const file of this.getFilesIn(folder, false) ?? []) {
391
- const destFile = join(destFolder, basename(file));
392
- copyFileSync(file, destFile);
393
- }
394
- }
395
- }
396
-
397
- if (options.withFiles) {
398
- for (const file of this.getFilesIn(target, false) ?? []) {
399
- const destFile = join(dest, basename(file));
400
- copyFileSync(file, destFile);
401
- }
402
- }
403
- } else {
404
- if (options.withFiles) {
405
- for (const file of this.getFilesIn(target, false) ?? []) {
406
- const destFile = join(dest, basename(file));
407
- copyFileSync(file, destFile);
408
- }
409
- }
410
- }
411
- return true;
412
- },
413
- /**
414
- * @param {Object} options
415
- * @param {string} options.dest
416
- * @param {string} [options.path]
417
- * @param {boolean} [options.recursive=true]
418
- * @param {boolean} [options.force=false]
419
- * @param {(file: string) => boolean} [options.filter]
420
- */
421
- copyFilesIn(options) {
422
- const target = _target(options.path ?? process.cwd());
423
- const destBase = this.createPath(options.dest);
424
-
425
- if (!target || !options.dest) return undefined;
426
-
427
- const recursive = options.recursive ?? true;
428
- const files = this.getFilesIn(target, recursive) ?? [];
429
- const filter =
430
- typeof options.filter === "function" ? options.filter : () => true;
431
- let copied = 0;
432
-
433
- for (const file of files.map(_format)) {
434
- if (!filter(file)) continue;
435
-
436
- const destFile = join(
437
- destBase,
438
- recursive ? relative(target, file) : basename(file),
439
- );
440
-
441
- if (options.force && this.getFile(destFile)) {
442
- this.deleteFile(destFile);
443
- }
444
-
445
- this.createFolder(dirname(destFile));
446
- copyFileSync(file, destFile);
447
- copied++;
448
- }
449
- return copied;
450
- },
451
- /**
452
- * @param {Object} options
453
- * @param {string} options.path
454
- * @param {string} options.dest
455
- * @param {boolean} [options.force=false]
456
- */
457
- copyFile(options) {
458
- const target = _target(options.path, "file");
459
- if (!target || !options.dest) return undefined;
460
-
461
- let destFile;
462
- if (
463
- !basename(options.dest) ||
464
- options.dest.endsWith("/") ||
465
- options.dest.endsWith("\\")
466
- ) {
467
- destFile = join(this.createPath(options.dest), basename(target));
468
- } else {
469
- destFile = this.createPath(options.dest);
470
- }
471
-
472
- if (options.force && this.getFile(destFile)) {
473
- this.deleteFile(destFile);
474
- }
475
-
476
- this.createFolder(dirname(destFile));
477
- copyFileSync(target, destFile);
478
- return true;
479
- },
480
- /**
481
- * @param {Object} options
482
- * @param {string} options.dest
483
- * @param {string} [options.path]
484
- * @param {boolean} [options.recursive=true]
485
- * @param {boolean} [options.withFiles=false]
486
- * @param {boolean} [options.force=false]
487
- * @param {(folder: string) => boolean} [options.filter]
488
- */
489
- moveFoldersIn(options) {
490
- const copied = this.copyFoldersIn(options);
491
- if (copied === undefined || !options.path) return copied;
492
-
493
- const target = _target(options.path);
494
- if (!target) return copied;
495
-
496
- const folders = this.getFoldersIn(target, options.recursive ?? true) ?? [];
497
- options.filter =
498
- typeof options.filter === "function" ? options.filter : () => true;
499
-
500
- for (const folder of folders.map(_format)) {
501
- if (!options.filter(folder)) continue;
502
- this.deleteFolder(folder);
503
- }
504
- return copied;
505
- },
506
- /**
507
- * @param {Object} options
508
- * @param {string} options.path
509
- * @param {string} options.dest
510
- * @param {boolean} [options.recursive=false]
511
- * @param {boolean} [options.withFiles=false]
512
- * @param {boolean} [options.force=false]
513
- */
514
- moveFolder(options) {
515
- const copied = this.copyFolder(options);
516
- const target = _target(options.path);
517
- if (!target) return copied;
518
-
519
- this.deleteFolder(target);
520
- return copied;
521
- },
522
- /**
523
- * @param {Object} options
524
- * @param {string} options.dest
525
- * @param {string} [options.path]
526
- * @param {boolean} [options.recursive=true]
527
- * @param {boolean} [options.force=false]
528
- * @param {(file: string) => boolean} [options.filter]
529
- */
530
- moveFilesIn(options) {
531
- const copied = this.copyFilesIn(options);
532
- if (copied === undefined || !options.path) return copied;
533
-
534
- const target = _target(options.path ?? process.cwd());
535
- if (!target) return copied;
536
-
537
- const files = this.getFilesIn(target, options.recursive ?? true) ?? [];
538
- const filter =
539
- typeof options.filter === "function" ? options.filter : () => true;
540
-
541
- for (const file of files.map(_format)) {
542
- if (!filter(file)) continue;
543
- this.deleteFile(file);
544
- }
545
- return copied;
546
- },
547
- /**
548
- * @param {Object} options
549
- * @param {string} options.path
550
- * @param {string} options.dest
551
- * @param {boolean} [options.force=false]
552
- */
553
- moveFile(options) {
554
- const moved = this.copyFile(options);
555
- if (moved) {
556
- const target = _target(options.path, "file");
557
- if (target) this.deleteFile(target);
558
- }
559
- return moved;
560
- },
561
- /**
562
- * @param {string} path
563
- */
564
- readFile(path) {
565
- const target = _target(path, "file");
566
- if (!target) return undefined;
567
-
568
- try {
569
- return readFileSync(target, "utf8");
570
- } catch {
571
- return undefined;
572
- }
573
- },
574
- /**
575
- * @param {Object} [options]
576
- * @param {string} [options.path=process.cwd()]
577
- * @param {boolean} [options.recursive=false]
578
- * @param {(event: string, file: string) => boolean} [options.filter]
579
- */
580
- watch(options = {}) {
581
- const target = _target(options.path ?? process.cwd());
582
- if (!target) return undefined;
583
-
584
- let paused = false;
585
- const listeners = {};
586
-
587
- /**
588
- * @param {"rename"|"change"|"all"} event
589
- * @param {string} file
590
- */
591
- const handler = (event, file) => {
592
- if (paused) return;
593
- if (
594
- typeof options.filter === "function" &&
595
- !options.filter(event, file)
596
- ) {
597
- return;
598
- }
599
-
600
- if (listeners[event]) {
601
- for (const cb of listeners[event]) cb(file);
602
- }
603
- if (listeners["all"]) {
604
- for (const cb of listeners["all"]) cb(event, file);
605
- }
606
- };
607
-
608
- const addListener = (type, callback) => {
609
- listeners[type] = listeners[type] ?? [];
610
- listeners[type].push(callback);
611
- };
612
-
613
- const watcher = watch(
614
- target,
615
- { recursive: options.recursive ?? false },
616
- (eventType, fileName) => {
617
- handler(eventType, fileName ? join(target, fileName) : target);
618
- },
619
- );
620
-
621
- return {
622
- /**
623
- * @typedef { "change" | "rename" | "all" } EventNames
624
- * @typedef {{
625
- * change: (file: string) => void|Promise<void>,
626
- * rename: (file: string) => void|Promise<void>,
627
- * all: (event: EventNames, file: string) => void|Promise<void>,
628
- * }} EventHandlers
629
- */
630
- /**
631
- * @template {EventNames} E
632
- * @param {E} event
633
- * @param {EventHandlers[E]} callback
634
- */
635
- on(event, callback) {
636
- addListener(event, callback);
637
- return this;
638
- },
639
- stop() {
640
- if (watcher) {
641
- try {
642
- watcher.close();
643
- } catch {}
644
- }
645
- },
646
- pause() {
647
- paused = true;
648
- return this;
649
- },
650
- resume() {
651
- paused = false;
652
- return this;
653
- },
654
- };
655
- },
656
- };