tiny-essentials 1.11.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -3
- package/dist/node_modules/firebase-functions/lib/common/trace.cjs +82 -0
- package/dist/node_modules/firebase-functions/lib/logger/common.cjs +57 -0
- package/dist/node_modules/firebase-functions/lib/logger/index.cjs +158 -0
- package/dist/v1/TinyBasicsEs.js +1653 -1
- package/dist/v1/TinyBasicsEs.min.js +1 -1
- package/dist/v1/TinyDragDropDetector.js +307 -0
- package/dist/v1/TinyDragDropDetector.min.js +1 -0
- package/dist/v1/TinyDragger.js +3563 -0
- package/dist/v1/TinyDragger.min.js +2 -0
- package/dist/v1/TinyDragger.min.js.LICENSE.txt +8 -0
- package/dist/v1/TinyEssentials.js +2783 -2
- package/dist/v1/TinyEssentials.min.js +1 -1
- package/dist/v1/TinyNotifyCenter.js +32 -0
- package/dist/v1/TinyNotifyCenter.min.js +1 -1
- package/dist/v1/TinyToastNotify.js +24 -0
- package/dist/v1/TinyToastNotify.min.js +1 -1
- package/dist/v1/TinyUploadClicker.js +5235 -0
- package/dist/v1/TinyUploadClicker.min.js +2 -0
- package/dist/v1/TinyUploadClicker.min.js.LICENSE.txt +8 -0
- package/dist/v1/basics/fileManager.cjs +524 -0
- package/dist/v1/basics/fileManager.d.mts +209 -0
- package/dist/v1/basics/fileManager.mjs +443 -0
- package/dist/v1/basics/fullScreen.cjs +134 -0
- package/dist/v1/basics/fullScreen.d.mts +8 -0
- package/dist/v1/basics/fullScreen.mjs +121 -0
- package/dist/v1/basics/html.cjs +262 -0
- package/dist/v1/basics/html.d.mts +63 -0
- package/dist/v1/basics/html.mjs +208 -0
- package/dist/v1/basics/index.cjs +40 -0
- package/dist/v1/basics/index.d.mts +38 -1
- package/dist/v1/basics/index.mjs +4 -1
- package/dist/v1/build/TinyDragDropDetector.cjs +7 -0
- package/dist/v1/build/TinyDragDropDetector.d.mts +3 -0
- package/dist/v1/build/TinyDragDropDetector.mjs +2 -0
- package/dist/v1/build/TinyDragger.cjs +7 -0
- package/dist/v1/build/TinyDragger.d.mts +3 -0
- package/dist/v1/build/TinyDragger.mjs +2 -0
- package/dist/v1/build/TinyUploadClicker.cjs +7 -0
- package/dist/v1/build/TinyUploadClicker.d.mts +3 -0
- package/dist/v1/build/TinyUploadClicker.mjs +2 -0
- package/dist/v1/css/TinyDraggerExample.css +21 -0
- package/dist/v1/css/TinyDraggerExample.min.css +1 -0
- package/dist/v1/index.cjs +44 -0
- package/dist/v1/index.d.mts +40 -1
- package/dist/v1/index.mjs +6 -1
- package/dist/v1/libs/TinyDragDropDetector.cjs +268 -0
- package/dist/v1/libs/TinyDragDropDetector.d.mts +123 -0
- package/dist/v1/libs/TinyDragDropDetector.mjs +228 -0
- package/dist/v1/libs/TinyDragger.cjs +801 -0
- package/dist/v1/libs/TinyDragger.d.mts +300 -0
- package/dist/v1/libs/TinyDragger.mjs +689 -0
- package/dist/v1/libs/TinyNotifyCenter.cjs +32 -0
- package/dist/v1/libs/TinyNotifyCenter.d.mts +9 -0
- package/dist/v1/libs/TinyNotifyCenter.mjs +28 -0
- package/dist/v1/libs/TinyToastNotify.cjs +24 -0
- package/dist/v1/libs/TinyToastNotify.d.mts +8 -0
- package/dist/v1/libs/TinyToastNotify.mjs +20 -0
- package/dist/v1/libs/TinyUploadClicker.cjs +223 -0
- package/dist/v1/libs/TinyUploadClicker.d.mts +80 -0
- package/dist/v1/libs/TinyUploadClicker.mjs +182 -0
- package/docs/v1/README.md +8 -2
- package/docs/v1/basics/fileManager.md +222 -0
- package/docs/v1/basics/fullScreen.md +183 -0
- package/docs/v1/basics/html.md +243 -0
- package/docs/v1/libs/TinyDragDropDetector.md +143 -0
- package/docs/v1/libs/TinyDragger.md +415 -0
- package/docs/v1/libs/TinyLevelUp.md +1 -1
- package/docs/v1/libs/TinyNotifyCenter.md +20 -0
- package/docs/v1/libs/TinyToastNotify.md +19 -0
- package/docs/v1/libs/TinyUploadClicker.md +108 -0
- package/package.json +12 -2
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads and parses a JSON file.
|
|
3
|
+
* Throws an error if the file content is not valid JSON.
|
|
4
|
+
* @param {string} filePath
|
|
5
|
+
* @returns {any}
|
|
6
|
+
*/
|
|
7
|
+
export function readJsonFile(filePath: string): any;
|
|
8
|
+
/**
|
|
9
|
+
* Saves an object as JSON to a file.
|
|
10
|
+
* Automatically creates the directory if it does not exist.
|
|
11
|
+
* @param {string} filePath
|
|
12
|
+
* @param {any} data
|
|
13
|
+
* @param {number} [spaces=2]
|
|
14
|
+
*/
|
|
15
|
+
export function writeJsonFile(filePath: string, data: any, spaces?: number): void;
|
|
16
|
+
/**
|
|
17
|
+
* Reads and parses a JSON file.
|
|
18
|
+
* Throws an error if the file content is not valid JSON.
|
|
19
|
+
* @param {string} filePath
|
|
20
|
+
* @returns {Promise<any>}
|
|
21
|
+
*/
|
|
22
|
+
export function readJsonFileAsync(filePath: string): Promise<any>;
|
|
23
|
+
/**
|
|
24
|
+
* Saves an object as JSON to a file.
|
|
25
|
+
* Automatically creates the directory if it does not exist.
|
|
26
|
+
* @param {string} filePath
|
|
27
|
+
* @param {any} data
|
|
28
|
+
* @param {number} [spaces=2]
|
|
29
|
+
* @returns {Promise<void>}
|
|
30
|
+
*/
|
|
31
|
+
export function writeJsonFileAsync(filePath: string, data: any, spaces?: number): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Ensures that the directory exists, creating it recursively if needed.
|
|
34
|
+
* @param {string} dirPath
|
|
35
|
+
*/
|
|
36
|
+
export function ensureDirectory(dirPath: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* Clears all contents inside a directory but keeps the directory.
|
|
39
|
+
* @param {string} dirPath
|
|
40
|
+
*/
|
|
41
|
+
export function clearDirectory(dirPath: string): void;
|
|
42
|
+
/**
|
|
43
|
+
* Checks whether a file exists.
|
|
44
|
+
* @param {string} filePath
|
|
45
|
+
* @returns {boolean}
|
|
46
|
+
*/
|
|
47
|
+
export function fileExists(filePath: string): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Checks whether a directory exists.
|
|
50
|
+
* @param {string} dirPath
|
|
51
|
+
* @returns {boolean}
|
|
52
|
+
*/
|
|
53
|
+
export function dirExists(dirPath: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Checks whether a directory is empty.
|
|
56
|
+
* @param {string} dirPath
|
|
57
|
+
* @returns {boolean}
|
|
58
|
+
*/
|
|
59
|
+
export function isDirEmpty(dirPath: string): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Copies a file to a destination.
|
|
62
|
+
* @param {string} src
|
|
63
|
+
* @param {string} dest
|
|
64
|
+
* @param {number} [mode]
|
|
65
|
+
*/
|
|
66
|
+
export function ensureCopyFile(src: string, dest: string, mode?: number): void;
|
|
67
|
+
/**
|
|
68
|
+
* Deletes a file (If the file exists).
|
|
69
|
+
* @param {string} filePath
|
|
70
|
+
* @returns {boolean}
|
|
71
|
+
*/
|
|
72
|
+
export function tryDeleteFile(filePath: string): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Copies a file to a destination.
|
|
75
|
+
* @param {string} src
|
|
76
|
+
* @param {string} dest
|
|
77
|
+
* @param {number} [mode]
|
|
78
|
+
* @returns {Promise<void>}
|
|
79
|
+
*/
|
|
80
|
+
export function ensureCopyFileAsync(src: string, dest: string, mode?: number): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* Deletes a file (If the file exists).
|
|
83
|
+
* @param {string} filePath
|
|
84
|
+
* @returns {Promise<boolean>}
|
|
85
|
+
*/
|
|
86
|
+
export function tryDeleteFileAsync(filePath: string): Promise<boolean>;
|
|
87
|
+
/**
|
|
88
|
+
* Writes text to a file (Ensures that the directory exists, creating it recursively if needed).
|
|
89
|
+
* @param {string} filePath
|
|
90
|
+
* @param {string} content
|
|
91
|
+
* @param {fs.WriteFileOptions} [ops='utf-8']
|
|
92
|
+
*/
|
|
93
|
+
export function writeTextFile(filePath: string, content: string, ops?: fs.WriteFileOptions): void;
|
|
94
|
+
/**
|
|
95
|
+
* Writes text to a file (Ensures that the directory exists, creating it recursively if needed).
|
|
96
|
+
* @param {string} filePath
|
|
97
|
+
* @param {string} content
|
|
98
|
+
* @param {fs.WriteFileOptions} [ops='utf-8']
|
|
99
|
+
* @returns {Promise<void>}
|
|
100
|
+
*/
|
|
101
|
+
export function writeTextFileAsync(filePath: string, content: string, ops?: fs.WriteFileOptions): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Lists all files and dirs in a directory (optionally recursive).
|
|
104
|
+
* @param {string} dirPath
|
|
105
|
+
* @param {boolean} [recursive=false]
|
|
106
|
+
* @returns {{ files: string[]; dirs: string[] }}
|
|
107
|
+
*/
|
|
108
|
+
export function listFiles(dirPath: string, recursive?: boolean): {
|
|
109
|
+
files: string[];
|
|
110
|
+
dirs: string[];
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Lists all directories in a directory (optionally recursive).
|
|
114
|
+
* @param {string} dirPath
|
|
115
|
+
* @param {boolean} [recursive=false]
|
|
116
|
+
* @returns {string[]}
|
|
117
|
+
*/
|
|
118
|
+
export function listDirs(dirPath: string, recursive?: boolean): string[];
|
|
119
|
+
/**
|
|
120
|
+
* Returns the size of a file in bytes.
|
|
121
|
+
* @param {string} filePath
|
|
122
|
+
* @returns {number}
|
|
123
|
+
*/
|
|
124
|
+
export function fileSize(filePath: string): number;
|
|
125
|
+
/**
|
|
126
|
+
* Returns the total size of a directory in bytes.
|
|
127
|
+
* @param {string} dirPath
|
|
128
|
+
* @returns {number}
|
|
129
|
+
*/
|
|
130
|
+
export function dirSize(dirPath: string): number;
|
|
131
|
+
/**
|
|
132
|
+
* Creates a backup copy of a file with .bak timestamp suffix.
|
|
133
|
+
* @param {string} filePath
|
|
134
|
+
* @param {string} [ext='bak']
|
|
135
|
+
*/
|
|
136
|
+
export function backupFile(filePath: string, ext?: string): void;
|
|
137
|
+
/**
|
|
138
|
+
* Returns the most recent backup file path for a given file.
|
|
139
|
+
* @param {string} filePath
|
|
140
|
+
* @param {string} [ext='bak']
|
|
141
|
+
* @returns {string} Full path to the most recent backup
|
|
142
|
+
*/
|
|
143
|
+
export function getLatestBackupPath(filePath: string, ext?: string): string;
|
|
144
|
+
/**
|
|
145
|
+
* Restores the most recent backup of a file.
|
|
146
|
+
* @param {string} filePath
|
|
147
|
+
* @param {string} [ext='bak']
|
|
148
|
+
*/
|
|
149
|
+
export function restoreLatestBackup(filePath: string, ext?: string): void;
|
|
150
|
+
/**
|
|
151
|
+
* Restores the most recent backup of a file.
|
|
152
|
+
* @param {string} filePath
|
|
153
|
+
* @param {string} [ext='bak']
|
|
154
|
+
* @returns {Promise<void>}
|
|
155
|
+
*/
|
|
156
|
+
export function restoreLatestBackupAsync(filePath: string, ext?: string): Promise<void>;
|
|
157
|
+
/**
|
|
158
|
+
* Creates a backup copy of a file with .bak timestamp suffix.
|
|
159
|
+
* @param {string} filePath
|
|
160
|
+
* @param {string} [ext='bak']
|
|
161
|
+
* @returns {Promise<void>}
|
|
162
|
+
*/
|
|
163
|
+
export function backupFileAsync(filePath: string, ext?: string): Promise<void>;
|
|
164
|
+
/**
|
|
165
|
+
* Renames multiple files in a directory using a rename function.
|
|
166
|
+
* @param {string} dirPath - The target directory.
|
|
167
|
+
* @param {(original: string, index: number) => string} renameFn - Function that returns new filename.
|
|
168
|
+
* @param {string[]} [extensions] - Optional: Only rename files with these extensions.
|
|
169
|
+
*
|
|
170
|
+
* @throws {TypeError} If any argument has an invalid type.
|
|
171
|
+
* @throws {Error} If the directory does not exist or contains invalid files.
|
|
172
|
+
*/
|
|
173
|
+
export function renameFileBatch(dirPath: string, renameFn: (original: string, index: number) => string, extensions?: string[]): void;
|
|
174
|
+
/**
|
|
175
|
+
* Renames files using regex replacement.
|
|
176
|
+
* @param {string} dirPath
|
|
177
|
+
* @param {RegExp} pattern - Regex to match in the filename.
|
|
178
|
+
* @param {string} replacement - Replacement string.
|
|
179
|
+
* @param {string[]} [extensions]
|
|
180
|
+
*/
|
|
181
|
+
export function renameFileRegex(dirPath: string, pattern: RegExp, replacement: string, extensions?: string[]): void;
|
|
182
|
+
/**
|
|
183
|
+
* Adds a prefix or suffix to filenames.
|
|
184
|
+
* @param {string} dirPath
|
|
185
|
+
* @param {{ prefix?: string, suffix?: string }} options
|
|
186
|
+
* @param {string[]} [extensions]
|
|
187
|
+
*/
|
|
188
|
+
export function renameFileAddPrefixSuffix(dirPath: string, { prefix, suffix }: {
|
|
189
|
+
prefix?: string;
|
|
190
|
+
suffix?: string;
|
|
191
|
+
}, extensions?: string[]): void;
|
|
192
|
+
/**
|
|
193
|
+
* Normalizes all filenames to lowercase (or uppercase).
|
|
194
|
+
* @param {string} dirPath
|
|
195
|
+
* @param {'lower' | 'upper' | 'title'} mode
|
|
196
|
+
* @param {string[]} [extensions]
|
|
197
|
+
* @param {boolean} [normalizeExt=false] - Whether to apply case change to file extensions too.
|
|
198
|
+
* @throws {Error} If mode is invalid.
|
|
199
|
+
*/
|
|
200
|
+
export function renameFileNormalizeCase(dirPath: string, mode?: "lower" | "upper" | "title", extensions?: string[], normalizeExt?: boolean): void;
|
|
201
|
+
/**
|
|
202
|
+
* Pads numbers in filenames (e.g., "img1.jpg" -> "img001.jpg").
|
|
203
|
+
* @param {string} dirPath
|
|
204
|
+
* @param {number} totalDigits
|
|
205
|
+
* @param {string[]} [extensions]
|
|
206
|
+
*/
|
|
207
|
+
export function renameFilePadNumbers(dirPath: string, totalDigits?: number, extensions?: string[]): void;
|
|
208
|
+
import fs from 'fs';
|
|
209
|
+
//# sourceMappingURL=fileManager.d.mts.map
|
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { toTitleCase } from './text.mjs';
|
|
4
|
+
/*========================*
|
|
5
|
+
* JSON Operations
|
|
6
|
+
*========================*/
|
|
7
|
+
/**
|
|
8
|
+
* Reads and parses a JSON file.
|
|
9
|
+
* Throws an error if the file content is not valid JSON.
|
|
10
|
+
* @param {string} filePath
|
|
11
|
+
* @returns {any}
|
|
12
|
+
*/
|
|
13
|
+
export function readJsonFile(filePath) {
|
|
14
|
+
if (!fs.existsSync(filePath))
|
|
15
|
+
throw new Error(`File not found: ${filePath}`);
|
|
16
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
17
|
+
return JSON.parse(content);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Saves an object as JSON to a file.
|
|
21
|
+
* Automatically creates the directory if it does not exist.
|
|
22
|
+
* @param {string} filePath
|
|
23
|
+
* @param {any} data
|
|
24
|
+
* @param {number} [spaces=2]
|
|
25
|
+
*/
|
|
26
|
+
export function writeJsonFile(filePath, data, spaces = 2) {
|
|
27
|
+
const json = JSON.stringify(data, null, spaces);
|
|
28
|
+
fs.writeFileSync(filePath, json, 'utf-8');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Reads and parses a JSON file.
|
|
32
|
+
* Throws an error if the file content is not valid JSON.
|
|
33
|
+
* @param {string} filePath
|
|
34
|
+
* @returns {Promise<any>}
|
|
35
|
+
*/
|
|
36
|
+
export async function readJsonFileAsync(filePath) {
|
|
37
|
+
if (!fs.existsSync(filePath))
|
|
38
|
+
throw new Error(`File not found: ${filePath}`);
|
|
39
|
+
const content = await fs.promises.readFile(filePath, 'utf-8');
|
|
40
|
+
return JSON.parse(content);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Saves an object as JSON to a file.
|
|
44
|
+
* Automatically creates the directory if it does not exist.
|
|
45
|
+
* @param {string} filePath
|
|
46
|
+
* @param {any} data
|
|
47
|
+
* @param {number} [spaces=2]
|
|
48
|
+
* @returns {Promise<void>}
|
|
49
|
+
*/
|
|
50
|
+
export function writeJsonFileAsync(filePath, data, spaces = 2) {
|
|
51
|
+
const json = JSON.stringify(data, null, spaces);
|
|
52
|
+
return fs.promises.writeFile(filePath, json, 'utf-8');
|
|
53
|
+
}
|
|
54
|
+
/*========================*
|
|
55
|
+
* Directory Management
|
|
56
|
+
*========================*/
|
|
57
|
+
/**
|
|
58
|
+
* Ensures that the directory exists, creating it recursively if needed.
|
|
59
|
+
* @param {string} dirPath
|
|
60
|
+
*/
|
|
61
|
+
export function ensureDirectory(dirPath) {
|
|
62
|
+
if (!fs.existsSync(dirPath)) {
|
|
63
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Clears all contents inside a directory but keeps the directory.
|
|
68
|
+
* @param {string} dirPath
|
|
69
|
+
*/
|
|
70
|
+
export function clearDirectory(dirPath) {
|
|
71
|
+
if (!fs.existsSync(dirPath))
|
|
72
|
+
return;
|
|
73
|
+
const files = fs.readdirSync(dirPath);
|
|
74
|
+
for (const file of files) {
|
|
75
|
+
const fullPath = path.join(dirPath, file);
|
|
76
|
+
const stat = fs.lstatSync(fullPath);
|
|
77
|
+
if (stat.isDirectory()) {
|
|
78
|
+
fs.rmSync(fullPath, { recursive: true, force: true });
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
fs.unlinkSync(fullPath);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/*========================*
|
|
86
|
+
* File Checks
|
|
87
|
+
*========================*/
|
|
88
|
+
/**
|
|
89
|
+
* Checks whether a file exists.
|
|
90
|
+
* @param {string} filePath
|
|
91
|
+
* @returns {boolean}
|
|
92
|
+
*/
|
|
93
|
+
export function fileExists(filePath) {
|
|
94
|
+
return fs.existsSync(filePath) && fs.lstatSync(filePath).isFile();
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Checks whether a directory exists.
|
|
98
|
+
* @param {string} dirPath
|
|
99
|
+
* @returns {boolean}
|
|
100
|
+
*/
|
|
101
|
+
export function dirExists(dirPath) {
|
|
102
|
+
return fs.existsSync(dirPath) && fs.lstatSync(dirPath).isDirectory();
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Checks whether a directory is empty.
|
|
106
|
+
* @param {string} dirPath
|
|
107
|
+
* @returns {boolean}
|
|
108
|
+
*/
|
|
109
|
+
export function isDirEmpty(dirPath) {
|
|
110
|
+
return fs.existsSync(dirPath) && fs.readdirSync(dirPath).length === 0;
|
|
111
|
+
}
|
|
112
|
+
/*========================*
|
|
113
|
+
* File Operations
|
|
114
|
+
*========================*/
|
|
115
|
+
/**
|
|
116
|
+
* Copies a file to a destination.
|
|
117
|
+
* @param {string} src
|
|
118
|
+
* @param {string} dest
|
|
119
|
+
* @param {number} [mode]
|
|
120
|
+
*/
|
|
121
|
+
export function ensureCopyFile(src, dest, mode) {
|
|
122
|
+
ensureDirectory(path.dirname(dest));
|
|
123
|
+
fs.copyFileSync(src, dest, mode);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Deletes a file (If the file exists).
|
|
127
|
+
* @param {string} filePath
|
|
128
|
+
* @returns {boolean}
|
|
129
|
+
*/
|
|
130
|
+
export function tryDeleteFile(filePath) {
|
|
131
|
+
if (fileExists(filePath)) {
|
|
132
|
+
fs.unlinkSync(filePath);
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Copies a file to a destination.
|
|
139
|
+
* @param {string} src
|
|
140
|
+
* @param {string} dest
|
|
141
|
+
* @param {number} [mode]
|
|
142
|
+
* @returns {Promise<void>}
|
|
143
|
+
*/
|
|
144
|
+
export function ensureCopyFileAsync(src, dest, mode) {
|
|
145
|
+
ensureDirectory(path.dirname(dest));
|
|
146
|
+
return fs.promises.copyFile(src, dest, mode);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Deletes a file (If the file exists).
|
|
150
|
+
* @param {string} filePath
|
|
151
|
+
* @returns {Promise<boolean>}
|
|
152
|
+
*/
|
|
153
|
+
export async function tryDeleteFileAsync(filePath) {
|
|
154
|
+
if (fileExists(filePath)) {
|
|
155
|
+
await fs.promises.unlink(filePath);
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
/*========================*
|
|
161
|
+
* Text Operations
|
|
162
|
+
*========================*/
|
|
163
|
+
/**
|
|
164
|
+
* Writes text to a file (Ensures that the directory exists, creating it recursively if needed).
|
|
165
|
+
* @param {string} filePath
|
|
166
|
+
* @param {string} content
|
|
167
|
+
* @param {fs.WriteFileOptions} [ops='utf-8']
|
|
168
|
+
*/
|
|
169
|
+
export function writeTextFile(filePath, content, ops = 'utf-8') {
|
|
170
|
+
const dir = path.dirname(filePath);
|
|
171
|
+
ensureDirectory(dir);
|
|
172
|
+
fs.writeFileSync(filePath, content, ops);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Writes text to a file (Ensures that the directory exists, creating it recursively if needed).
|
|
176
|
+
* @param {string} filePath
|
|
177
|
+
* @param {string} content
|
|
178
|
+
* @param {fs.WriteFileOptions} [ops='utf-8']
|
|
179
|
+
* @returns {Promise<void>}
|
|
180
|
+
*/
|
|
181
|
+
export function writeTextFileAsync(filePath, content, ops = 'utf-8') {
|
|
182
|
+
const dir = path.dirname(filePath);
|
|
183
|
+
ensureDirectory(dir);
|
|
184
|
+
return fs.promises.writeFile(filePath, content, ops);
|
|
185
|
+
}
|
|
186
|
+
/*========================*
|
|
187
|
+
* Directory Listings
|
|
188
|
+
*========================*/
|
|
189
|
+
/**
|
|
190
|
+
* Lists all files and dirs in a directory (optionally recursive).
|
|
191
|
+
* @param {string} dirPath
|
|
192
|
+
* @param {boolean} [recursive=false]
|
|
193
|
+
* @returns {{ files: string[]; dirs: string[] }}
|
|
194
|
+
*/
|
|
195
|
+
export function listFiles(dirPath, recursive = false) {
|
|
196
|
+
/** @type {{ files: string[]; dirs: string[] }} */
|
|
197
|
+
const results = { files: [], dirs: [] };
|
|
198
|
+
if (!dirExists(dirPath))
|
|
199
|
+
return results;
|
|
200
|
+
const entries = fs.readdirSync(dirPath);
|
|
201
|
+
for (const entry of entries) {
|
|
202
|
+
const fullPath = path.join(dirPath, entry);
|
|
203
|
+
const stat = fs.lstatSync(fullPath);
|
|
204
|
+
if (stat.isDirectory()) {
|
|
205
|
+
results.dirs.push(fullPath);
|
|
206
|
+
if (recursive) {
|
|
207
|
+
const results2 = listFiles(fullPath, true);
|
|
208
|
+
results.files.push(...results2.files);
|
|
209
|
+
results.dirs.push(...results2.dirs);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
results.files.push(fullPath);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return results;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Lists all directories in a directory (optionally recursive).
|
|
220
|
+
* @param {string} dirPath
|
|
221
|
+
* @param {boolean} [recursive=false]
|
|
222
|
+
* @returns {string[]}
|
|
223
|
+
*/
|
|
224
|
+
export function listDirs(dirPath, recursive = false) {
|
|
225
|
+
/** @type {string[]} */
|
|
226
|
+
const results = [];
|
|
227
|
+
if (!dirExists(dirPath))
|
|
228
|
+
return results;
|
|
229
|
+
const entries = fs.readdirSync(dirPath);
|
|
230
|
+
for (const entry of entries) {
|
|
231
|
+
const fullPath = path.join(dirPath, entry);
|
|
232
|
+
const stat = fs.lstatSync(fullPath);
|
|
233
|
+
if (stat.isDirectory()) {
|
|
234
|
+
results.push(fullPath);
|
|
235
|
+
if (recursive) {
|
|
236
|
+
results.push(...listDirs(fullPath, true));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return results;
|
|
241
|
+
}
|
|
242
|
+
/*========================*
|
|
243
|
+
* File Info
|
|
244
|
+
*========================*/
|
|
245
|
+
/**
|
|
246
|
+
* Returns the size of a file in bytes.
|
|
247
|
+
* @param {string} filePath
|
|
248
|
+
* @returns {number}
|
|
249
|
+
*/
|
|
250
|
+
export function fileSize(filePath) {
|
|
251
|
+
if (!fileExists(filePath))
|
|
252
|
+
return 0;
|
|
253
|
+
const stats = fs.statSync(filePath);
|
|
254
|
+
return stats.size;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Returns the total size of a directory in bytes.
|
|
258
|
+
* @param {string} dirPath
|
|
259
|
+
* @returns {number}
|
|
260
|
+
*/
|
|
261
|
+
export function dirSize(dirPath) {
|
|
262
|
+
let total = 0;
|
|
263
|
+
const files = listFiles(dirPath, true).files;
|
|
264
|
+
for (const file of files) {
|
|
265
|
+
total += fileSize(file);
|
|
266
|
+
}
|
|
267
|
+
return total;
|
|
268
|
+
}
|
|
269
|
+
/*========================*
|
|
270
|
+
* Backup Utilities
|
|
271
|
+
*========================*/
|
|
272
|
+
/**
|
|
273
|
+
* Creates a backup copy of a file with .bak timestamp suffix.
|
|
274
|
+
* @param {string} filePath
|
|
275
|
+
* @param {string} [ext='bak']
|
|
276
|
+
*/
|
|
277
|
+
export function backupFile(filePath, ext = 'bak') {
|
|
278
|
+
if (!fileExists(filePath))
|
|
279
|
+
return;
|
|
280
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
281
|
+
const backupPath = `${filePath}.${ext}.${timestamp}`;
|
|
282
|
+
ensureCopyFile(filePath, backupPath);
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Returns the most recent backup file path for a given file.
|
|
286
|
+
* @param {string} filePath
|
|
287
|
+
* @param {string} [ext='bak']
|
|
288
|
+
* @returns {string} Full path to the most recent backup
|
|
289
|
+
*/
|
|
290
|
+
export function getLatestBackupPath(filePath, ext = 'bak') {
|
|
291
|
+
const dir = path.dirname(filePath);
|
|
292
|
+
const baseName = path.basename(filePath);
|
|
293
|
+
const backups = fs
|
|
294
|
+
.readdirSync(dir)
|
|
295
|
+
.filter((name) => name.startsWith(`${baseName}.${ext}.`))
|
|
296
|
+
.sort()
|
|
297
|
+
.reverse();
|
|
298
|
+
if (backups.length === 0)
|
|
299
|
+
throw new Error(`No backups found for ${filePath}`);
|
|
300
|
+
return path.join(dir, backups[0]);
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Restores the most recent backup of a file.
|
|
304
|
+
* @param {string} filePath
|
|
305
|
+
* @param {string} [ext='bak']
|
|
306
|
+
*/
|
|
307
|
+
export function restoreLatestBackup(filePath, ext = 'bak') {
|
|
308
|
+
const latestBackup = getLatestBackupPath(filePath, ext);
|
|
309
|
+
ensureCopyFile(latestBackup, filePath);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Restores the most recent backup of a file.
|
|
313
|
+
* @param {string} filePath
|
|
314
|
+
* @param {string} [ext='bak']
|
|
315
|
+
* @returns {Promise<void>}
|
|
316
|
+
*/
|
|
317
|
+
export function restoreLatestBackupAsync(filePath, ext = 'bak') {
|
|
318
|
+
const latestBackup = getLatestBackupPath(filePath, ext);
|
|
319
|
+
return ensureCopyFileAsync(latestBackup, filePath);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Creates a backup copy of a file with .bak timestamp suffix.
|
|
323
|
+
* @param {string} filePath
|
|
324
|
+
* @param {string} [ext='bak']
|
|
325
|
+
* @returns {Promise<void>}
|
|
326
|
+
*/
|
|
327
|
+
export async function backupFileAsync(filePath, ext = 'bak') {
|
|
328
|
+
if (!fileExists(filePath))
|
|
329
|
+
return;
|
|
330
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
331
|
+
const backupPath = `${filePath}.${ext}.${timestamp}`;
|
|
332
|
+
return ensureCopyFileAsync(filePath, backupPath);
|
|
333
|
+
}
|
|
334
|
+
/*========================*
|
|
335
|
+
* Rename Utilities
|
|
336
|
+
*========================*/
|
|
337
|
+
/**
|
|
338
|
+
* Renames multiple files in a directory using a rename function.
|
|
339
|
+
* @param {string} dirPath - The target directory.
|
|
340
|
+
* @param {(original: string, index: number) => string} renameFn - Function that returns new filename.
|
|
341
|
+
* @param {string[]} [extensions] - Optional: Only rename files with these extensions.
|
|
342
|
+
*
|
|
343
|
+
* @throws {TypeError} If any argument has an invalid type.
|
|
344
|
+
* @throws {Error} If the directory does not exist or contains invalid files.
|
|
345
|
+
*/
|
|
346
|
+
export function renameFileBatch(dirPath, renameFn, extensions = []) {
|
|
347
|
+
// Validate types
|
|
348
|
+
if (typeof dirPath !== 'string')
|
|
349
|
+
throw new TypeError('dirPath must be a string');
|
|
350
|
+
if (typeof renameFn !== 'function')
|
|
351
|
+
throw new TypeError('renameFn must be a function');
|
|
352
|
+
if (!Array.isArray(extensions))
|
|
353
|
+
throw new TypeError('extensions must be an array of strings');
|
|
354
|
+
if (!fs.existsSync(dirPath) || !fs.statSync(dirPath).isDirectory())
|
|
355
|
+
throw new Error(`Directory not found or invalid: ${dirPath}`);
|
|
356
|
+
for (const ext of extensions) {
|
|
357
|
+
if (typeof ext !== 'string' || !ext.startsWith('.'))
|
|
358
|
+
throw new TypeError(`Invalid extension: ${ext}`);
|
|
359
|
+
}
|
|
360
|
+
const files = listFiles(dirPath).files;
|
|
361
|
+
let index = 0;
|
|
362
|
+
for (const file of files) {
|
|
363
|
+
const ext = path.extname(file);
|
|
364
|
+
if (extensions.length && !extensions.includes(ext))
|
|
365
|
+
continue;
|
|
366
|
+
const originalName = path.basename(file);
|
|
367
|
+
const newName = renameFn(originalName, index++);
|
|
368
|
+
const newPath = path.join(dirPath, newName);
|
|
369
|
+
if (originalName === newName)
|
|
370
|
+
continue;
|
|
371
|
+
fs.renameSync(file, newPath);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Renames files using regex replacement.
|
|
376
|
+
* @param {string} dirPath
|
|
377
|
+
* @param {RegExp} pattern - Regex to match in the filename.
|
|
378
|
+
* @param {string} replacement - Replacement string.
|
|
379
|
+
* @param {string[]} [extensions]
|
|
380
|
+
*/
|
|
381
|
+
export function renameFileRegex(dirPath, pattern, replacement, extensions = []) {
|
|
382
|
+
renameFileBatch(dirPath, (filename) => {
|
|
383
|
+
const ext = path.extname(filename);
|
|
384
|
+
const name = path.basename(filename, ext).replace(pattern, replacement);
|
|
385
|
+
return `${name}${ext}`;
|
|
386
|
+
}, extensions);
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Adds a prefix or suffix to filenames.
|
|
390
|
+
* @param {string} dirPath
|
|
391
|
+
* @param {{ prefix?: string, suffix?: string }} options
|
|
392
|
+
* @param {string[]} [extensions]
|
|
393
|
+
*/
|
|
394
|
+
export function renameFileAddPrefixSuffix(dirPath, { prefix = '', suffix = '' }, extensions = []) {
|
|
395
|
+
renameFileBatch(dirPath, (filename) => {
|
|
396
|
+
const ext = path.extname(filename);
|
|
397
|
+
const name = path.basename(filename, ext);
|
|
398
|
+
return `${prefix}${name}${suffix}${ext}`;
|
|
399
|
+
}, extensions);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Normalizes all filenames to lowercase (or uppercase).
|
|
403
|
+
* @param {string} dirPath
|
|
404
|
+
* @param {'lower' | 'upper' | 'title'} mode
|
|
405
|
+
* @param {string[]} [extensions]
|
|
406
|
+
* @param {boolean} [normalizeExt=false] - Whether to apply case change to file extensions too.
|
|
407
|
+
* @throws {Error} If mode is invalid.
|
|
408
|
+
*/
|
|
409
|
+
export function renameFileNormalizeCase(dirPath, mode = 'lower', extensions = [], normalizeExt = false) {
|
|
410
|
+
if (typeof mode !== 'string' || !['lower', 'upper', 'title'].includes(mode))
|
|
411
|
+
throw new Error(`Invalid mode "${mode}". Must be 'lower', 'upper' or 'title'.`);
|
|
412
|
+
renameFileBatch(dirPath, (filename) => {
|
|
413
|
+
/**
|
|
414
|
+
* @param {string} text
|
|
415
|
+
* @returns {string}
|
|
416
|
+
*/
|
|
417
|
+
const changeToMode = (text) => {
|
|
418
|
+
if (mode === 'lower')
|
|
419
|
+
return text.toLowerCase();
|
|
420
|
+
else if (mode === 'upper')
|
|
421
|
+
return text.toUpperCase();
|
|
422
|
+
else if (mode === 'title')
|
|
423
|
+
return toTitleCase(text);
|
|
424
|
+
else
|
|
425
|
+
return text;
|
|
426
|
+
};
|
|
427
|
+
const rawExt = path.extname(filename);
|
|
428
|
+
const ext = normalizeExt ? changeToMode(rawExt) : rawExt;
|
|
429
|
+
const name = changeToMode(path.basename(filename, rawExt));
|
|
430
|
+
return `${name}${ext}`;
|
|
431
|
+
}, extensions);
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Pads numbers in filenames (e.g., "img1.jpg" -> "img001.jpg").
|
|
435
|
+
* @param {string} dirPath
|
|
436
|
+
* @param {number} totalDigits
|
|
437
|
+
* @param {string[]} [extensions]
|
|
438
|
+
*/
|
|
439
|
+
export function renameFilePadNumbers(dirPath, totalDigits = 3, extensions = []) {
|
|
440
|
+
renameFileBatch(dirPath, (filename) => {
|
|
441
|
+
return filename.replace(/\d+/, (match) => match.padStart(totalDigits, '0'));
|
|
442
|
+
}, extensions);
|
|
443
|
+
}
|