xshell 1.0.20 → 1.0.22
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/file.d.ts +1 -52
- package/file.js +1 -101
- package/file.js.map +1 -1
- package/i18n/dict.json +12 -0
- package/i18n/index.js +2 -1
- package/i18n/index.js.map +1 -1
- package/net.browser.js +22 -25
- package/net.browser.js.map +1 -1
- package/net.js +23 -27
- package/net.js.map +1 -1
- package/package.json +17 -26
- package/repl.js +14 -27
- package/repl.js.map +1 -1
- package/server.d.ts +2 -8
- package/server.js +17 -15
- package/server.js.map +1 -1
- package/tsconfig.json +1 -3
- package/utils.browser.d.ts +4 -0
- package/utils.browser.js +6 -4
- package/utils.browser.js.map +1 -1
- package/utils.d.ts +7 -6
- package/utils.js +15 -23
- package/utils.js.map +1 -1
- package/ufs.d.ts +0 -19
- package/ufs.js +0 -145
- package/ufs.js.map +0 -1
package/file.d.ts
CHANGED
|
@@ -5,16 +5,6 @@ import { promises as fsp, default as fs } from 'fs';
|
|
|
5
5
|
type FileHandle = fsp.FileHandle & {
|
|
6
6
|
fp: string;
|
|
7
7
|
};
|
|
8
|
-
import path from 'upath';
|
|
9
|
-
import MFS from 'memfs';
|
|
10
|
-
declare module 'memfs' {
|
|
11
|
-
interface IFs {
|
|
12
|
-
join: typeof path.join;
|
|
13
|
-
is_mfs: true;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
export * from './ufs.js';
|
|
17
|
-
export { MFS };
|
|
18
8
|
export type Encoding = 'utf-8' | 'gb18030' | 'shift-jis' | 'utf-16le';
|
|
19
9
|
export declare const encodings: readonly ["utf-8", "gb18030", "shift-jis", "utf-16le"];
|
|
20
10
|
/** fp 所指向的 文件/ 文件夹 是否存在
|
|
@@ -39,7 +29,6 @@ export declare function fopen(fp: string, flags: string | number, { mode, print
|
|
|
39
29
|
flags: string | number;
|
|
40
30
|
mode: fs.Mode;
|
|
41
31
|
}>;
|
|
42
|
-
export declare function create_mfs(): MFS.IFs;
|
|
43
32
|
export declare function fread(fp: string): Promise<string>;
|
|
44
33
|
export declare function fread(fp: string, { dir, encoding, print }?: {
|
|
45
34
|
dir?: string;
|
|
@@ -166,46 +155,6 @@ export declare function flink(fp_real: string, fp_link: string, { junction, prin
|
|
|
166
155
|
junction?: boolean;
|
|
167
156
|
print?: boolean;
|
|
168
157
|
}): Promise<void>;
|
|
169
|
-
export interface ZipOptions {
|
|
170
|
-
dirname?: string;
|
|
171
|
-
print?: {
|
|
172
|
-
info: boolean;
|
|
173
|
-
files: boolean;
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
/** 将文件夹压缩为 zip
|
|
177
|
-
- data:
|
|
178
|
-
- 被压缩文件夹路径 (fpd_src: string) 或
|
|
179
|
-
- 文件索引对象 (entries: Record<压缩后相对路径, 原文件绝对路径 (string) | 数据 (Buffer)>)
|
|
180
|
-
- fp_zip?:
|
|
181
|
-
- 传压缩包完整路径时压缩到文件, 函数返回值为 Promise<zip 路径>
|
|
182
|
-
- 传 undefined 时压缩到内存, 函数返回值为 Promise<zip buffer>
|
|
183
|
-
- options?:
|
|
184
|
-
- dirname?: `fpd_src.fname` 传入 fpd_src 才生效,修改 zip 中顶层的文件夹的名字(需要以 / 结尾),如 'web/', 为空字符串时去掉顶层文件夹,不要多一个文件夹层级 (flat)
|
|
185
|
-
- print?:
|
|
186
|
-
- info?: `true` 开始压缩、压缩完成
|
|
187
|
-
- files?: `true` 打印压缩文件列表 */
|
|
188
|
-
export declare function fzip(entries: Record<string, string | Buffer>, fp_zip?: undefined, options?: ZipOptions): Promise<Buffer>;
|
|
189
|
-
export declare function fzip(entries: Record<string, string | Buffer>, fp_zip: string, options?: ZipOptions): Promise<string>;
|
|
190
|
-
export declare function fzip(fpd_src: string, fp_zip?: undefined, options?: ZipOptions): Promise<Buffer>;
|
|
191
|
-
export declare function fzip(fpd_src: string, fp_zip: string, options?: ZipOptions): Promise<string>;
|
|
192
|
-
export declare let fwatchers: Record<string, fs.FSWatcher>;
|
|
193
|
-
/**
|
|
194
|
-
- fp: 文件或文件夹路径 path of file or directory
|
|
195
|
-
- callback: 文件修改时回调 called when modified
|
|
196
|
-
- exec: `true` 首次 watch 时执行 onchange call callback when watch is executed
|
|
197
|
-
|
|
198
|
-
创建的 fs.FSWatcher 保存在 watchers 中, 再次调用相同的 fp 会自动关闭已有的 watcher
|
|
199
|
-
save fs.FSWatcher in watchers, subsequent call will auto close existing watcher for the same fp
|
|
200
|
-
|
|
201
|
-
https://nodejs.org/dist/latest-v15.x/docs/api/fs.html#fs_fs_watch_filename_options_listener
|
|
202
|
-
The listener callback gets two arguments (event, fname).
|
|
203
|
-
event is either 'rename' or 'change', and filename is the name of the file which triggered the event.
|
|
204
|
-
On most platforms, 'rename' is emitted whenever a filename appears or disappears in the directory.
|
|
205
|
-
|
|
206
|
-
The listener callback is attached to the 'change' event fired by fs.FSWatcher, but it is not the same thing as the 'change' value of event. */
|
|
207
|
-
export declare function fwatch(fp: string, onchange: (event: string, fname: string) => any, { exec }?: {
|
|
208
|
-
exec?: boolean;
|
|
209
|
-
}): Promise<fs.FSWatcher>;
|
|
210
158
|
/** 打开一个文件并搜索替换某个 pattern open a file and replace certain pattern */
|
|
211
159
|
export declare function freplace(fp: string, pattern: string | RegExp, replacement: string): Promise<void>;
|
|
160
|
+
export {};
|
package/file.js
CHANGED
|
@@ -2,13 +2,9 @@ import { promises as fsp, default as fs, } from 'fs';
|
|
|
2
2
|
import { isUint8Array } from 'util/types';
|
|
3
3
|
import path from 'upath';
|
|
4
4
|
import fse from 'fs-extra';
|
|
5
|
-
import debounce from 'lodash/debounce.js';
|
|
6
|
-
import MFS from 'memfs';
|
|
7
5
|
import { t } from './i18n/instance.js';
|
|
8
6
|
import { to_json } from './prototype.js';
|
|
9
|
-
import { assert
|
|
10
|
-
export * from './ufs.js';
|
|
11
|
-
export { MFS };
|
|
7
|
+
import { assert } from './utils.js';
|
|
12
8
|
export const encodings = ['utf-8', 'gb18030', 'shift-jis', 'utf-16le'];
|
|
13
9
|
/** fp 所指向的 文件/ 文件夹 是否存在
|
|
14
10
|
Does the file/folder pointed to by fp exist? */
|
|
@@ -32,12 +28,6 @@ export async function fopen(fp, flags, { mode, print } = {}) {
|
|
|
32
28
|
console.log(t('打开文件'), fp);
|
|
33
29
|
return Object.assign(await fsp.open(fp, flags, mode), { fp, flags, mode });
|
|
34
30
|
}
|
|
35
|
-
export function create_mfs() {
|
|
36
|
-
let mfs = MFS.createFsFromVolume(new MFS.Volume());
|
|
37
|
-
mfs.join = path.join.bind(path);
|
|
38
|
-
mfs.is_mfs = true;
|
|
39
|
-
return mfs;
|
|
40
|
-
}
|
|
41
31
|
export async function fread(fp, { dir, encoding = 'utf-8', print = true } = {}) {
|
|
42
32
|
if (dir) {
|
|
43
33
|
assert(dir.endsWith('/'), t('dir 必须以 / 结尾'));
|
|
@@ -274,96 +264,6 @@ export async function flink(fp_real, fp_link, { junction = false, print = true }
|
|
|
274
264
|
else
|
|
275
265
|
fsp.symlink(fp_real, fp_link, is_fpd_real ? 'dir' : 'file');
|
|
276
266
|
}
|
|
277
|
-
export async function fzip(data, fp_zip, { dirname, print = { files: true, info: true } } = {}) {
|
|
278
|
-
let entries;
|
|
279
|
-
let fpd_src;
|
|
280
|
-
if (typeof data === 'string') {
|
|
281
|
-
if (!path.isAbsolute(data) || !data.endsWith('/'))
|
|
282
|
-
throw new Error('fpd_src 必须是绝对路径且以 / 结尾');
|
|
283
|
-
fpd_src = data;
|
|
284
|
-
if (dirname === undefined)
|
|
285
|
-
dirname = fpd_src.fname;
|
|
286
|
-
if (!dirname.endsWith('/'))
|
|
287
|
-
throw new Error('dirname 需要以 / 结尾');
|
|
288
|
-
entries = Object.fromEntries((await flist(fpd_src, { print: false }))
|
|
289
|
-
.map(fp => ([dirname + fp, fpd_src + fp])));
|
|
290
|
-
}
|
|
291
|
-
else
|
|
292
|
-
entries = data;
|
|
293
|
-
if (print.info)
|
|
294
|
-
console.log(`开始压缩${fpd_src ? ` ${fpd_src}` : '文件索引'} → ${fp_zip ? `${fp_zip}/${dirname}` : '内存'}`);
|
|
295
|
-
const { default: archiver } = await import('archiver');
|
|
296
|
-
let archive = archiver('zip', { zlib: { chunkSize: 16 * 2 ** 20 /* 16 MB */ } });
|
|
297
|
-
let ostream = fp_zip ? fs.createWriteStream(fp_zip) : new WritableMemoryStream();
|
|
298
|
-
const size = await new Promise((resolve, reject) => {
|
|
299
|
-
ostream.once('close', () => {
|
|
300
|
-
resolve(archive.pointer());
|
|
301
|
-
});
|
|
302
|
-
archive.once('error', reject);
|
|
303
|
-
archive.on('warning', error => {
|
|
304
|
-
console.log(error);
|
|
305
|
-
});
|
|
306
|
-
archive.pipe(ostream);
|
|
307
|
-
for (const fp in entries) {
|
|
308
|
-
const fdata = entries[fp];
|
|
309
|
-
if (fdata instanceof Buffer) {
|
|
310
|
-
if (print.files)
|
|
311
|
-
console.log(`压缩 ${fdata.length.to_fsize_str()} → ${fp}`);
|
|
312
|
-
archive.append(fdata, { name: fp });
|
|
313
|
-
}
|
|
314
|
-
else {
|
|
315
|
-
assert(fp.endsWith('/') === fdata.endsWith('/'));
|
|
316
|
-
assert(path.isAbsolute(fdata));
|
|
317
|
-
if (print.files)
|
|
318
|
-
console.log(`压缩 ${fdata} → ${fp}`);
|
|
319
|
-
if (fp.endsWith('/'))
|
|
320
|
-
archive.directory(fdata, fp);
|
|
321
|
-
else
|
|
322
|
-
archive.file(fdata, { name: fp });
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
archive.finalize();
|
|
326
|
-
});
|
|
327
|
-
if (print.info)
|
|
328
|
-
console.log(`压缩完成,总大小 ${size.to_fsize_str()}`);
|
|
329
|
-
return fp_zip || ostream.pbuffer;
|
|
330
|
-
}
|
|
331
|
-
export let fwatchers = {};
|
|
332
|
-
/**
|
|
333
|
-
- fp: 文件或文件夹路径 path of file or directory
|
|
334
|
-
- callback: 文件修改时回调 called when modified
|
|
335
|
-
- exec: `true` 首次 watch 时执行 onchange call callback when watch is executed
|
|
336
|
-
|
|
337
|
-
创建的 fs.FSWatcher 保存在 watchers 中, 再次调用相同的 fp 会自动关闭已有的 watcher
|
|
338
|
-
save fs.FSWatcher in watchers, subsequent call will auto close existing watcher for the same fp
|
|
339
|
-
|
|
340
|
-
https://nodejs.org/dist/latest-v15.x/docs/api/fs.html#fs_fs_watch_filename_options_listener
|
|
341
|
-
The listener callback gets two arguments (event, fname).
|
|
342
|
-
event is either 'rename' or 'change', and filename is the name of the file which triggered the event.
|
|
343
|
-
On most platforms, 'rename' is emitted whenever a filename appears or disappears in the directory.
|
|
344
|
-
|
|
345
|
-
The listener callback is attached to the 'change' event fired by fs.FSWatcher, but it is not the same thing as the 'change' value of event. */
|
|
346
|
-
export async function fwatch(fp, onchange, { exec = true } = {}) {
|
|
347
|
-
if (!path.isAbsolute(fp))
|
|
348
|
-
throw new Error(t('fp 必须是完整路径'));
|
|
349
|
-
const _watcher = fwatchers[fp];
|
|
350
|
-
if (_watcher)
|
|
351
|
-
_watcher.close();
|
|
352
|
-
if (exec)
|
|
353
|
-
await onchange('change', fp.fname);
|
|
354
|
-
const start = new Date().getTime();
|
|
355
|
-
const debounced_onchange = debounce((event, fname) => {
|
|
356
|
-
if (new Date().getTime() - start < 800)
|
|
357
|
-
return;
|
|
358
|
-
console.log(t('文件修改 (') + event + '): ' + fname);
|
|
359
|
-
onchange(event, path.normalize(fname));
|
|
360
|
-
}, 500, { leading: false, trailing: true });
|
|
361
|
-
let watcher = fs.watch(fp, debounced_onchange);
|
|
362
|
-
watcher.on('error', error => {
|
|
363
|
-
console.error(error);
|
|
364
|
-
});
|
|
365
|
-
return fwatchers[fp] = watcher;
|
|
366
|
-
}
|
|
367
267
|
/** 打开一个文件并搜索替换某个 pattern open a file and replace certain pattern */
|
|
368
268
|
export async function freplace(fp, pattern, replacement) {
|
|
369
269
|
await fwrite(fp, (await fread(fp))
|
package/file.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.js","sourceRoot":"","sources":["file.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n promises as fsp,\n default as fs,\n} from 'fs'\ntype FileHandle = fsp.FileHandle & { fp: string }\n\nimport { isUint8Array } from 'util/types'\n\n\nimport path from 'upath'\nimport fse from 'fs-extra'\n\nimport debounce from 'lodash/debounce.js'\n\n\nimport MFS from 'memfs'\ndeclare module 'memfs' {\n interface IFs {\n join: typeof path.join\n is_mfs: true\n }\n}\n\n\nimport { t } from './i18n/instance.js'\nimport { to_json } from './prototype.js'\nimport { assert, WritableMemoryStream } from './utils.js'\n\n\nexport * from './ufs.js'\n\nexport { MFS }\n\nexport type Encoding = 'utf-8' | 'gb18030' | 'shift-jis' | 'utf-16le'\n\nexport const encodings = ['utf-8', 'gb18030', 'shift-jis', 'utf-16le'] as const\n\n/** fp 所指向的 文件/ 文件夹 是否存在 \n Does the file/folder pointed to by fp exist? */\nexport function fexists (fp: string, { print = true }: { print?: boolean } = { }) {\n const exists = fs.existsSync(fp)\n \n if (print)\n console.log(exists ? t('已存在') : t('不存在'), fp)\n \n return exists\n}\n\n\n/** 打开文件,返回 FileHandle \n open file, return FileHandle \n Some characters (`< > : \" / \\ | ? *`) are reserved under Windows as documented\n by [Naming Files, Paths, and Namespaces](https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file). Under NTFS, if the filename contains\n a colon, Node.js will open a file system stream, as described by [this MSDN page](https://docs.microsoft.com/en-us/windows/desktop/FileIO/using-streams).\n \n - flags: `'r'`\n - options?:\n - mode?: `'0o666'` Sets the file mode (permission and sticky bits) if the file is created. */\nexport async function fopen (\n fp: string,\n flags: string | number,\n { mode, print }: { mode?: fs.Mode, print?: boolean } = { }\n) {\n if (print)\n console.log(t('打开文件'), fp)\n \n return Object.assign(\n await fsp.open(fp, flags, mode),\n { fp, flags, mode }\n )\n}\n\n\nexport function create_mfs () {\n let mfs = MFS.createFsFromVolume(\n new MFS.Volume()\n )\n \n mfs.join = path.join.bind(path)\n mfs.is_mfs = true\n \n return mfs\n}\n\n\nexport async function fread (fp: string): Promise<string>\nexport async function fread (fp: string, { dir, encoding, print }?: { dir?: string, encoding: 'binary', print?: boolean }): Promise<Buffer>\nexport async function fread (fp: string, { dir, encoding, print }?: { dir?: string, encoding?: Encoding, print?: boolean }): Promise<string>\nexport async function fread (fp: string, {\n dir, \n encoding = 'utf-8', \n print = true\n}: {\n dir?: string\n encoding?: Encoding | 'binary'\n print?: boolean } = { }\n) {\n if (dir) {\n assert(dir.endsWith('/'), t('dir 必须以 / 结尾'))\n fp = dir + fp\n }\n \n assert(!fp.endsWith('/'), t('fp 必须是文件,不能以 / 结尾'))\n assert(path.isAbsolute(fp), `${t('fp 必须是绝对路径:')} ${fp}`)\n assert((encoding as string) !== 'auto')\n \n if (print)\n console.log(t('读取'), fp)\n \n switch (encoding) {\n case 'utf-8':\n return fsp.readFile(fp, { encoding: 'utf-8' })\n \n case 'binary':\n return fsp.readFile(fp)\n \n default:\n return new TextDecoder(encoding)\n .decode(await fsp.readFile(fp))\n }\n}\n\nexport async function fread_lines (fp: string, options: { dir?: string, encoding?: Encoding, print?: boolean } = { }) {\n return (await fread(fp, options))\n .split_lines()\n}\n\nexport async function fread_json <T = any> (fp: string, options: { dir?: string, encoding?: Encoding, print?: boolean } = { }): Promise<T> {\n return JSON.parse(await fread(fp, options))\n}\n\n\n/** 写入 data 到 fp 路径所指的文件 \n - fp: 目标文件完整路径\n - data: 支持下面几种类型\n - string: 写入文本\n - Uint8Array, Buffer: 写入二进制 buffer\n - any: 通过 JSON.stringify 转为文本后写入文件 */\nexport async function fwrite (\n fp: string | FileHandle,\n data: string | Uint8Array | any,\n {\n dir,\n print = true,\n mkdir = false,\n }: {\n dir?: string\n print?: boolean\n mkdir?: boolean\n } = { }\n) {\n const is_handle = typeof fp === 'object' && fp && 'fd' in fp\n if (is_handle) {\n if (print)\n console.log(t('写入'), (fp as FileHandle).fp)\n } else {\n if (dir) {\n assert(dir.endsWith('/'), t('dir 必须以 / 结尾'))\n fp = dir + fp\n }\n \n assert(path.isAbsolute(fp as string), `${t('fp 必须是绝对路径,当前为:')} ${fp}`)\n \n if (print)\n console.log(t('写入'), fp)\n }\n \n if (!isUint8Array(data) && typeof data !== 'string')\n data = to_json(data)\n \n try {\n await fsp.writeFile(fp, data)\n } catch (error) {\n if (!mkdir || error.code !== 'ENOENT' || is_handle)\n throw error\n \n await fmkdir((fp as string).fdir)\n await fsp.writeFile(fp, data)\n }\n}\n\nexport async function fappend (fp: string, data: string | Uint8Array, { dir, print = true }: { dir?: string, print?: boolean } = { }) {\n if (dir) {\n assert(dir.endsWith('/'), t('dir 必须以 / 结尾'))\n fp = dir + fp\n }\n \n assert(path.isAbsolute(fp), `${t('fp 必须是绝对路径,当前为:')} ${fp}`)\n \n if (print)\n console.log(t('追加'), fp)\n \n assert(isUint8Array(data) || typeof data === 'string')\n \n await fsp.appendFile(fp, data)\n}\n\n\nexport type FStats = fs.BigIntStats & { fp: string }\n\nexport interface FListOptions {\n filter?: RegExp | ((fp: string) => any)\n deep?: boolean\n absolute?: boolean\n print?: boolean\n stats?: boolean\n}\n\n/**\n - fpd: 文件夹完整路径 absolute path of directory\n - options?:\n - deep?: `false` 递归遍历 recursively\n - absolute?: `false` 返回、打印完整路径而不是相对路径 Return, print full path instead of relative path\n - print?: `true`\n - filter?: `true` RegExp | (fp: string) => any 注意当 deep = true 时被 filter 过滤掉的目录及目录中的文件不会包含在结果中 \n Note that when deep = true, directories and files in directories that are filtered out by the filter will not be included in the results \n - stats?: `false` 启用后返回 FStats 列表, 不能和 deep 一起使用 \n Returns the FStats list when enabled, cannot be used with deep */\nexport async function flist (fpd: string): Promise<string[]>\nexport async function flist (fpd: string, options?: FListOptions & { stats: true }): Promise<FStats[]>\nexport async function flist (fpd: string, options?: FListOptions): Promise<string[]>\nexport async function flist (fpd: string, options: FListOptions = { }): Promise<string[] | FStats[]> {\n const {\n filter,\n deep = false,\n absolute = false,\n print = true,\n stats = false\n } = options\n \n if (!path.isAbsolute(fpd))\n throw new Error(t('参数 fpd: ') + fpd + t(' 必须是绝对路径'))\n \n if (!fpd.endsWith('/'))\n throw new Error(t('参数 fpd: ') + fpd + t(' 必须以 / 结尾'))\n \n // readdir withFileTypes 参数在底层有什么区别,速度上有什么差异\n // 都调用了 uv_fs_scandir, 且调用参数相同,仅仅是 Node.js 侧的回调不同 AfterScanDir / AfterScanDirWithTypes\n // 回调中通过 uv_fs_scandir_next 获取到每个条目的信息,而 uv_fs_scandir_next 中都会读取 type\n // 速度上:都在 0.2 ms 左右就可以完成\n \n const files = await fsp.readdir(fpd, { withFileTypes: true, encoding: 'utf-8' })\n \n const filter_regexp = filter instanceof RegExp\n const filter_fn = Boolean(filter && !filter_regexp)\n \n let fps: string[] = [ ]\n \n for (const file of files) {\n const fp = \n (absolute ? fpd : '') +\n file.name +\n (file.isDirectory() ? '/' : '')\n \n if (filter_regexp && !filter.test(fp))\n continue\n \n if (filter_fn && !(filter as Function)(fp))\n continue\n \n if (print)\n console.log(fp)\n \n fps.push(fp)\n }\n \n if (deep)\n return (\n await Promise.all(\n fps.map(async fp => \n fp.endsWith('/') ?\n [\n fp,\n ... (await flist(\n absolute ? fp : fpd + fp,\n options\n )).map(fp_ => absolute ? fp_ : fp + fp_)\n ]\n :\n fp))\n ).flat()\n else\n if (stats)\n return Promise.all(\n fps.map(fp => fstat(absolute ? fp : fpd + fp))\n )\n else\n return fps\n}\n\n\nexport async function fstat (fp: string) {\n if (!path.isAbsolute(fp))\n throw new Error('fp: ' + fp + t(' 必须是绝对路径'))\n \n let stat = await fsp.stat(fp, { bigint: true })\n ;(stat as any).fp = fp\n \n return stat as FStats\n}\n\n\n/** 删除文件或文件夹 delete files or folders \n - fp: 文件或文件夹的完整路径 The full path to the file or folder\n - options?:\n - print?: `true`\n \n 返回是否实际进行了删除操作 \n Returns whether the delete operation actually took place */\nexport async function fdelete (fp: string, { print = true }: { print?: boolean } = { }) {\n assert(fp.length >= 6, `fp: ${fp} ${t('不能太短,防止误删文件')}`)\n assert(path.isAbsolute(fp), t('fp 必须是绝对路径'))\n \n try {\n await fsp.rm(fp, { recursive: true })\n if (print)\n if (fp.endsWith('/'))\n console.log((t('删除了文件夹: ') + fp).red)\n else\n console.log((t('删除了文件: ') + fp).red)\n return true\n } catch (error) {\n if (error.code === 'ENOENT') {\n if (print)\n if (fp.endsWith('/'))\n console.log(t('文件夹已不存在: ') + fp)\n else\n console.log(t('文件已不存在: ') + fp)\n return false\n }\n \n throw error\n }\n}\n\n\n/** 复制文件或文件夹 copy file or direcotry\n - fp_src: 源 文件/文件夹 完整路径 src file/directory absolute path\n - fp_dst: 目标 文件/文件夹 完整路径 dst file/directory absolute path\n - options?:\n - print?: `true`\n - overwrite?: `true`\n \n @example\n fcopy('d:/temp/camera/', 'd:/camera/') */\nexport async function fcopy (fp_src: string, fp_dst: string, {\n print = true,\n overwrite = true,\n}: {\n print?: boolean\n overwrite?: boolean\n} = { }) {\n assert(fp_src.endsWith('/') === fp_dst.endsWith('/'), t('fp_src 和 fp_dst 必须同为文件路径或文件夹路径'))\n assert(path.isAbsolute(fp_src) && path.isAbsolute(fp_dst), t('fp_src 和 fp_dst 必须为完整路径'))\n \n if (print)\n console.log(t('复制'), fp_src, '→', fp_dst)\n \n await fse.copy(fp_src, fp_dst, { overwrite, errorOnExist: true })\n}\n\n\n/** 移动文件或文件夹 move file or direcotry\n - src: 源 文件/文件夹 完整路径 src file/directory absolute path\n - dst: 目标 文件/文件夹 完整路径 dst file/directory absolute path\n @example\n fmove('d:/temp/camera/', 'd:/camera/') */\nexport async function fmove (src: string, dst: string, {\n overwrite = false,\n print = true\n}: {\n overwrite?: boolean\n print?: boolean\n} = { }) {\n if (src.endsWith('/') !== dst.endsWith('/'))\n throw new Error(t('src 和 dst 必须同为文件路径或文件夹路径'))\n \n if (!path.isAbsolute(src) || !path.isAbsolute(dst))\n throw new Error(t('src 和 dst 必须为完整路径'))\n \n if (print)\n console.log(t('移动'), src, '→', dst)\n \n await fse.move(src, dst, { overwrite })\n}\n\n\n/** 重命名文件 rename file \n - fp: 当前文件名/路径 current filename/path\n - fp_: 新的文件名/路径 new filename/path\n - options?:\n - fpd?: fp 和 fp_ 在同一文件夹内 fp and fp_ is in same directory\n - print?: `true`\n - overwrite?: `true` 默认覆盖(不检查效率更高) better performance without check */\nexport async function frename (\n fp: string, \n fp_: string,\n {\n fpd,\n print = true,\n overwrite = true\n }: {\n fpd?: string\n print?: boolean\n overwrite?: boolean\n } = { }\n) {\n if (fpd) {\n fp = path.join(fpd, fp)\n fp_ = path.join(fpd, fp_)\n } else if (!path.isAbsolute(fp) || !path.isAbsolute(fp_))\n throw new Error(t('fp 和 fp_ 必须是绝对路径'))\n \n if (print)\n console.log(t('重命名'), fp, '→', fp_)\n \n if (!overwrite && fexists(fp_))\n throw new Error(t('文件已存在:') + fp_)\n \n await fsp.rename(fp, fp_)\n}\n\n\n/**\n 递归创建文件夹,确保 fpd 指向的文件夹存在 Create folders recursively, make sure the folder pointed to by fpd exists \n 返回首个创建的文件夹或 undefined Returns the first created folder or undefined\n \n - fpd: 文件夹完整路径 Folder full path\n - options?:\n - print?: `true`\n - mode?: `'0o777'` */\nexport async function fmkdir (\n fpd: string,\n {\n print = true,\n mode,\n }: {\n print?: boolean\n \n /** `0o777` A file mode. If a string is passed, it is parsed as an octal integer. */\n mode?: string | number\n } = { }\n) {\n assert(path.isAbsolute(fpd), t('fpd 必须是绝对路径: ') + fpd)\n assert(fpd.endsWith('/'), t('fpd 必须以 / 结尾: ') + fpd)\n \n // CallingfsPromises.mkdir() when path is a directory that exists results in a rejection only when recursive is false.\n const fpd_ = (\n await fsp.mkdir(fpd, { recursive: true, mode })\n )?.replaceAll('\\\\', '/')\n \n if (fpd_) {\n if (print)\n console.log(t('已创建文件夹'), fpd)\n } else\n if (print)\n console.log(t('已存在文件夹'), fpd)\n \n return fpd_\n}\n\n\n/** 创建软链接 Create soft links \n - fp_real: 现在真实文件/文件夹的路径 current real file/directory path\n - fp_link: 目标链接文件/文件夹的路径 target file/directory path */\nexport async function flink (\n fp_real: string, \n fp_link: string, \n {\n junction = false,\n print = true \n }: { \n junction?: boolean\n print?: boolean\n} = { }) {\n assert(path.isAbsolute(fp_real) && path.isAbsolute(fp_link), t('fp 必须是绝对路径'))\n \n const is_fpd_real = fp_real.endsWith('/')\n const is_fpd_link = fp_link.endsWith('/')\n \n assert(is_fpd_real === is_fpd_link, t('fp_real 和 fp_link 必须同为文件路径或文件夹路径'))\n \n if (fexists(fp_link))\n throw new Error(t('存在同名') + (is_fpd_link ? t('文件夹') : t('文件')) + ': ' + fp_link + t(',无法创建链接'))\n \n if (print)\n console.log(t('已将源文件 ') + fp_real + t(' 链接到 ') + fp_link)\n \n if (junction)\n fsp.symlink(fp_real, fp_link, 'junction')\n else\n fsp.symlink(fp_real, fp_link, is_fpd_real ? 'dir' : 'file')\n}\n\n\nexport interface ZipOptions {\n dirname?: string\n print?: {\n info: boolean\n files: boolean\n }\n}\n\n\n/** 将文件夹压缩为 zip \n - data: \n - 被压缩文件夹路径 (fpd_src: string) 或\n - 文件索引对象 (entries: Record<压缩后相对路径, 原文件绝对路径 (string) | 数据 (Buffer)>) \n - fp_zip?:\n - 传压缩包完整路径时压缩到文件, 函数返回值为 Promise<zip 路径>\n - 传 undefined 时压缩到内存, 函数返回值为 Promise<zip buffer>\n - options?:\n - dirname?: `fpd_src.fname` 传入 fpd_src 才生效,修改 zip 中顶层的文件夹的名字(需要以 / 结尾),如 'web/', 为空字符串时去掉顶层文件夹,不要多一个文件夹层级 (flat)\n - print?:\n - info?: `true` 开始压缩、压缩完成\n - files?: `true` 打印压缩文件列表 */\nexport async function fzip (entries: Record<string, string | Buffer>, fp_zip?: undefined, options?: ZipOptions): Promise<Buffer>\nexport async function fzip (entries: Record<string, string | Buffer>, fp_zip: string, options?: ZipOptions): Promise<string>\nexport async function fzip (fpd_src: string, fp_zip?: undefined, options?: ZipOptions): Promise<Buffer>\nexport async function fzip (fpd_src: string, fp_zip: string, options?: ZipOptions): Promise<string>\nexport async function fzip (\n data: string | Record<string, string | Buffer>,\n fp_zip?: string,\n {\n dirname,\n print = { files: true, info: true }\n }: ZipOptions = { }\n): Promise<string | Buffer> {\n let entries: Record<string, string | Buffer>\n let fpd_src: string\n \n if (typeof data === 'string') {\n if (!path.isAbsolute(data) || !data.endsWith('/'))\n throw new Error('fpd_src 必须是绝对路径且以 / 结尾')\n \n fpd_src = data\n \n if (dirname === undefined)\n dirname = fpd_src.fname\n \n if (!dirname.endsWith('/'))\n throw new Error('dirname 需要以 / 结尾')\n \n entries = Object.fromEntries(\n (await flist(fpd_src, { print: false }))\n .map(fp => ([dirname + fp, fpd_src + fp]))\n )\n } else\n entries = data\n \n \n if (print.info)\n console.log(`开始压缩${fpd_src ? ` ${fpd_src}` : '文件索引'} → ${fp_zip ? `${fp_zip}/${dirname}` : '内存'}`)\n \n const { default: archiver } = await import('archiver')\n \n let archive = archiver('zip', { zlib: { chunkSize: 16 * 2**20 /* 16 MB */ } })\n \n let ostream = fp_zip ? fs.createWriteStream(fp_zip) : new WritableMemoryStream()\n \n const size = await new Promise<number>((resolve, reject) => {\n ostream.once('close', () => {\n resolve(archive.pointer())\n })\n \n archive.once('error', reject)\n \n archive.on('warning', error => {\n console.log(error)\n })\n \n archive.pipe(ostream)\n \n for (const fp in entries) {\n const fdata = entries[fp]\n \n if (fdata instanceof Buffer) {\n if (print.files)\n console.log(`压缩 ${fdata.length.to_fsize_str()} → ${fp}`)\n archive.append(fdata, { name: fp })\n } else {\n assert(fp.endsWith('/') === fdata.endsWith('/'))\n assert(path.isAbsolute(fdata))\n \n if (print.files)\n console.log(`压缩 ${fdata} → ${fp}`)\n \n if (fp.endsWith('/'))\n archive.directory(fdata, fp)\n else\n archive.file(fdata, { name: fp })\n }\n }\n \n archive.finalize()\n })\n \n if (print.info)\n console.log(`压缩完成,总大小 ${size.to_fsize_str()}`)\n \n return fp_zip || (ostream as WritableMemoryStream).pbuffer\n}\n\n\nexport let fwatchers: Record<string, fs.FSWatcher> = { }\n\n/**\n - fp: 文件或文件夹路径 path of file or directory\n - callback: 文件修改时回调 called when modified\n - exec: `true` 首次 watch 时执行 onchange call callback when watch is executed\n \n 创建的 fs.FSWatcher 保存在 watchers 中, 再次调用相同的 fp 会自动关闭已有的 watcher \n save fs.FSWatcher in watchers, subsequent call will auto close existing watcher for the same fp\n \n https://nodejs.org/dist/latest-v15.x/docs/api/fs.html#fs_fs_watch_filename_options_listener \n The listener callback gets two arguments (event, fname). \n event is either 'rename' or 'change', and filename is the name of the file which triggered the event.\n On most platforms, 'rename' is emitted whenever a filename appears or disappears in the directory.\n \n The listener callback is attached to the 'change' event fired by fs.FSWatcher, but it is not the same thing as the 'change' value of event. */\nexport async function fwatch (\n fp: string,\n onchange: (event: string, fname: string) => any, \n { exec = true }: { exec?: boolean } = { }\n) {\n if (!path.isAbsolute(fp))\n throw new Error(t('fp 必须是完整路径'))\n \n const _watcher = fwatchers[fp]\n if (_watcher)\n _watcher.close()\n \n if (exec)\n await onchange('change', fp.fname)\n \n const start = new Date().getTime()\n \n const debounced_onchange = debounce(\n (event, fname) => {\n if (new Date().getTime() - start < 800)\n return\n console.log(t('文件修改 (') + event + '): ' + fname)\n onchange(event, path.normalize(fname))\n },\n 500,\n { leading: false, trailing: true }\n )\n \n let watcher = fs.watch(fp, debounced_onchange)\n watcher.on('error', error => {\n console.error(error)\n })\n return fwatchers[fp] = watcher\n}\n\n\n/** 打开一个文件并搜索替换某个 pattern open a file and replace certain pattern */\nexport async function freplace (fp: string, pattern: string | RegExp, replacement: string) {\n await fwrite(\n fp,\n (await fread(fp))\n .replaceAll(pattern, replacement)\n )\n}\n\n"]}
|
|
1
|
+
{"version":3,"file":"file.js","sourceRoot":"","sources":["file.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n promises as fsp,\n default as fs,\n} from 'fs'\ntype FileHandle = fsp.FileHandle & { fp: string }\n\nimport { isUint8Array } from 'util/types'\n\n\nimport path from 'upath'\nimport fse from 'fs-extra'\n\n\nimport { t } from './i18n/instance.js'\nimport { to_json } from './prototype.js'\nimport { assert } from './utils.js'\n\n\nexport type Encoding = 'utf-8' | 'gb18030' | 'shift-jis' | 'utf-16le'\n\nexport const encodings = ['utf-8', 'gb18030', 'shift-jis', 'utf-16le'] as const\n\n/** fp 所指向的 文件/ 文件夹 是否存在 \n Does the file/folder pointed to by fp exist? */\nexport function fexists (fp: string, { print = true }: { print?: boolean } = { }) {\n const exists = fs.existsSync(fp)\n \n if (print)\n console.log(exists ? t('已存在') : t('不存在'), fp)\n \n return exists\n}\n\n\n/** 打开文件,返回 FileHandle \n open file, return FileHandle \n Some characters (`< > : \" / \\ | ? *`) are reserved under Windows as documented\n by [Naming Files, Paths, and Namespaces](https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file). Under NTFS, if the filename contains\n a colon, Node.js will open a file system stream, as described by [this MSDN page](https://docs.microsoft.com/en-us/windows/desktop/FileIO/using-streams).\n \n - flags: `'r'`\n - options?:\n - mode?: `'0o666'` Sets the file mode (permission and sticky bits) if the file is created. */\nexport async function fopen (\n fp: string,\n flags: string | number,\n { mode, print }: { mode?: fs.Mode, print?: boolean } = { }\n) {\n if (print)\n console.log(t('打开文件'), fp)\n \n return Object.assign(\n await fsp.open(fp, flags, mode),\n { fp, flags, mode }\n )\n}\n\n\nexport async function fread (fp: string): Promise<string>\nexport async function fread (fp: string, { dir, encoding, print }?: { dir?: string, encoding: 'binary', print?: boolean }): Promise<Buffer>\nexport async function fread (fp: string, { dir, encoding, print }?: { dir?: string, encoding?: Encoding, print?: boolean }): Promise<string>\nexport async function fread (fp: string, {\n dir, \n encoding = 'utf-8', \n print = true\n}: {\n dir?: string\n encoding?: Encoding | 'binary'\n print?: boolean } = { }\n) {\n if (dir) {\n assert(dir.endsWith('/'), t('dir 必须以 / 结尾'))\n fp = dir + fp\n }\n \n assert(!fp.endsWith('/'), t('fp 必须是文件,不能以 / 结尾'))\n assert(path.isAbsolute(fp), `${t('fp 必须是绝对路径:')} ${fp}`)\n assert((encoding as string) !== 'auto')\n \n if (print)\n console.log(t('读取'), fp)\n \n switch (encoding) {\n case 'utf-8':\n return fsp.readFile(fp, { encoding: 'utf-8' })\n \n case 'binary':\n return fsp.readFile(fp)\n \n default:\n return new TextDecoder(encoding)\n .decode(await fsp.readFile(fp))\n }\n}\n\nexport async function fread_lines (fp: string, options: { dir?: string, encoding?: Encoding, print?: boolean } = { }) {\n return (await fread(fp, options))\n .split_lines()\n}\n\nexport async function fread_json <T = any> (fp: string, options: { dir?: string, encoding?: Encoding, print?: boolean } = { }): Promise<T> {\n return JSON.parse(await fread(fp, options))\n}\n\n\n/** 写入 data 到 fp 路径所指的文件 \n - fp: 目标文件完整路径\n - data: 支持下面几种类型\n - string: 写入文本\n - Uint8Array, Buffer: 写入二进制 buffer\n - any: 通过 JSON.stringify 转为文本后写入文件 */\nexport async function fwrite (\n fp: string | FileHandle,\n data: string | Uint8Array | any,\n {\n dir,\n print = true,\n mkdir = false,\n }: {\n dir?: string\n print?: boolean\n mkdir?: boolean\n } = { }\n) {\n const is_handle = typeof fp === 'object' && fp && 'fd' in fp\n if (is_handle) {\n if (print)\n console.log(t('写入'), (fp as FileHandle).fp)\n } else {\n if (dir) {\n assert(dir.endsWith('/'), t('dir 必须以 / 结尾'))\n fp = dir + fp\n }\n \n assert(path.isAbsolute(fp as string), `${t('fp 必须是绝对路径,当前为:')} ${fp}`)\n \n if (print)\n console.log(t('写入'), fp)\n }\n \n if (!isUint8Array(data) && typeof data !== 'string')\n data = to_json(data)\n \n try {\n await fsp.writeFile(fp, data)\n } catch (error) {\n if (!mkdir || error.code !== 'ENOENT' || is_handle)\n throw error\n \n await fmkdir((fp as string).fdir)\n await fsp.writeFile(fp, data)\n }\n}\n\nexport async function fappend (fp: string, data: string | Uint8Array, { dir, print = true }: { dir?: string, print?: boolean } = { }) {\n if (dir) {\n assert(dir.endsWith('/'), t('dir 必须以 / 结尾'))\n fp = dir + fp\n }\n \n assert(path.isAbsolute(fp), `${t('fp 必须是绝对路径,当前为:')} ${fp}`)\n \n if (print)\n console.log(t('追加'), fp)\n \n assert(isUint8Array(data) || typeof data === 'string')\n \n await fsp.appendFile(fp, data)\n}\n\n\nexport type FStats = fs.BigIntStats & { fp: string }\n\nexport interface FListOptions {\n filter?: RegExp | ((fp: string) => any)\n deep?: boolean\n absolute?: boolean\n print?: boolean\n stats?: boolean\n}\n\n/**\n - fpd: 文件夹完整路径 absolute path of directory\n - options?:\n - deep?: `false` 递归遍历 recursively\n - absolute?: `false` 返回、打印完整路径而不是相对路径 Return, print full path instead of relative path\n - print?: `true`\n - filter?: `true` RegExp | (fp: string) => any 注意当 deep = true 时被 filter 过滤掉的目录及目录中的文件不会包含在结果中 \n Note that when deep = true, directories and files in directories that are filtered out by the filter will not be included in the results \n - stats?: `false` 启用后返回 FStats 列表, 不能和 deep 一起使用 \n Returns the FStats list when enabled, cannot be used with deep */\nexport async function flist (fpd: string): Promise<string[]>\nexport async function flist (fpd: string, options?: FListOptions & { stats: true }): Promise<FStats[]>\nexport async function flist (fpd: string, options?: FListOptions): Promise<string[]>\nexport async function flist (fpd: string, options: FListOptions = { }): Promise<string[] | FStats[]> {\n const {\n filter,\n deep = false,\n absolute = false,\n print = true,\n stats = false\n } = options\n \n if (!path.isAbsolute(fpd))\n throw new Error(t('参数 fpd: ') + fpd + t(' 必须是绝对路径'))\n \n if (!fpd.endsWith('/'))\n throw new Error(t('参数 fpd: ') + fpd + t(' 必须以 / 结尾'))\n \n // readdir withFileTypes 参数在底层有什么区别,速度上有什么差异\n // 都调用了 uv_fs_scandir, 且调用参数相同,仅仅是 Node.js 侧的回调不同 AfterScanDir / AfterScanDirWithTypes\n // 回调中通过 uv_fs_scandir_next 获取到每个条目的信息,而 uv_fs_scandir_next 中都会读取 type\n // 速度上:都在 0.2 ms 左右就可以完成\n \n const files = await fsp.readdir(fpd, { withFileTypes: true, encoding: 'utf-8' })\n \n const filter_regexp = filter instanceof RegExp\n const filter_fn = Boolean(filter && !filter_regexp)\n \n let fps: string[] = [ ]\n \n for (const file of files) {\n const fp = \n (absolute ? fpd : '') +\n file.name +\n (file.isDirectory() ? '/' : '')\n \n if (filter_regexp && !filter.test(fp))\n continue\n \n if (filter_fn && !(filter as Function)(fp))\n continue\n \n if (print)\n console.log(fp)\n \n fps.push(fp)\n }\n \n if (deep)\n return (\n await Promise.all(\n fps.map(async fp => \n fp.endsWith('/') ?\n [\n fp,\n ... (await flist(\n absolute ? fp : fpd + fp,\n options\n )).map(fp_ => absolute ? fp_ : fp + fp_)\n ]\n :\n fp))\n ).flat()\n else\n if (stats)\n return Promise.all(\n fps.map(fp => fstat(absolute ? fp : fpd + fp))\n )\n else\n return fps\n}\n\n\nexport async function fstat (fp: string) {\n if (!path.isAbsolute(fp))\n throw new Error('fp: ' + fp + t(' 必须是绝对路径'))\n \n let stat = await fsp.stat(fp, { bigint: true })\n ;(stat as any).fp = fp\n \n return stat as FStats\n}\n\n\n/** 删除文件或文件夹 delete files or folders \n - fp: 文件或文件夹的完整路径 The full path to the file or folder\n - options?:\n - print?: `true`\n \n 返回是否实际进行了删除操作 \n Returns whether the delete operation actually took place */\nexport async function fdelete (fp: string, { print = true }: { print?: boolean } = { }) {\n assert(fp.length >= 6, `fp: ${fp} ${t('不能太短,防止误删文件')}`)\n assert(path.isAbsolute(fp), t('fp 必须是绝对路径'))\n \n try {\n await fsp.rm(fp, { recursive: true })\n if (print)\n if (fp.endsWith('/'))\n console.log((t('删除了文件夹: ') + fp).red)\n else\n console.log((t('删除了文件: ') + fp).red)\n return true\n } catch (error) {\n if (error.code === 'ENOENT') {\n if (print)\n if (fp.endsWith('/'))\n console.log(t('文件夹已不存在: ') + fp)\n else\n console.log(t('文件已不存在: ') + fp)\n return false\n }\n \n throw error\n }\n}\n\n\n/** 复制文件或文件夹 copy file or direcotry\n - fp_src: 源 文件/文件夹 完整路径 src file/directory absolute path\n - fp_dst: 目标 文件/文件夹 完整路径 dst file/directory absolute path\n - options?:\n - print?: `true`\n - overwrite?: `true`\n \n @example\n fcopy('d:/temp/camera/', 'd:/camera/') */\nexport async function fcopy (fp_src: string, fp_dst: string, {\n print = true,\n overwrite = true,\n}: {\n print?: boolean\n overwrite?: boolean\n} = { }) {\n assert(fp_src.endsWith('/') === fp_dst.endsWith('/'), t('fp_src 和 fp_dst 必须同为文件路径或文件夹路径'))\n assert(path.isAbsolute(fp_src) && path.isAbsolute(fp_dst), t('fp_src 和 fp_dst 必须为完整路径'))\n \n if (print)\n console.log(t('复制'), fp_src, '→', fp_dst)\n \n await fse.copy(fp_src, fp_dst, { overwrite, errorOnExist: true })\n}\n\n\n/** 移动文件或文件夹 move file or direcotry\n - src: 源 文件/文件夹 完整路径 src file/directory absolute path\n - dst: 目标 文件/文件夹 完整路径 dst file/directory absolute path\n @example\n fmove('d:/temp/camera/', 'd:/camera/') */\nexport async function fmove (src: string, dst: string, {\n overwrite = false,\n print = true\n}: {\n overwrite?: boolean\n print?: boolean\n} = { }) {\n if (src.endsWith('/') !== dst.endsWith('/'))\n throw new Error(t('src 和 dst 必须同为文件路径或文件夹路径'))\n \n if (!path.isAbsolute(src) || !path.isAbsolute(dst))\n throw new Error(t('src 和 dst 必须为完整路径'))\n \n if (print)\n console.log(t('移动'), src, '→', dst)\n \n await fse.move(src, dst, { overwrite })\n}\n\n\n/** 重命名文件 rename file \n - fp: 当前文件名/路径 current filename/path\n - fp_: 新的文件名/路径 new filename/path\n - options?:\n - fpd?: fp 和 fp_ 在同一文件夹内 fp and fp_ is in same directory\n - print?: `true`\n - overwrite?: `true` 默认覆盖(不检查效率更高) better performance without check */\nexport async function frename (\n fp: string, \n fp_: string,\n {\n fpd,\n print = true,\n overwrite = true\n }: {\n fpd?: string\n print?: boolean\n overwrite?: boolean\n } = { }\n) {\n if (fpd) {\n fp = path.join(fpd, fp)\n fp_ = path.join(fpd, fp_)\n } else if (!path.isAbsolute(fp) || !path.isAbsolute(fp_))\n throw new Error(t('fp 和 fp_ 必须是绝对路径'))\n \n if (print)\n console.log(t('重命名'), fp, '→', fp_)\n \n if (!overwrite && fexists(fp_))\n throw new Error(t('文件已存在:') + fp_)\n \n await fsp.rename(fp, fp_)\n}\n\n\n/**\n 递归创建文件夹,确保 fpd 指向的文件夹存在 Create folders recursively, make sure the folder pointed to by fpd exists \n 返回首个创建的文件夹或 undefined Returns the first created folder or undefined\n \n - fpd: 文件夹完整路径 Folder full path\n - options?:\n - print?: `true`\n - mode?: `'0o777'` */\nexport async function fmkdir (\n fpd: string,\n {\n print = true,\n mode,\n }: {\n print?: boolean\n \n /** `0o777` A file mode. If a string is passed, it is parsed as an octal integer. */\n mode?: string | number\n } = { }\n) {\n assert(path.isAbsolute(fpd), t('fpd 必须是绝对路径: ') + fpd)\n assert(fpd.endsWith('/'), t('fpd 必须以 / 结尾: ') + fpd)\n \n // CallingfsPromises.mkdir() when path is a directory that exists results in a rejection only when recursive is false.\n const fpd_ = (\n await fsp.mkdir(fpd, { recursive: true, mode })\n )?.replaceAll('\\\\', '/')\n \n if (fpd_) {\n if (print)\n console.log(t('已创建文件夹'), fpd)\n } else\n if (print)\n console.log(t('已存在文件夹'), fpd)\n \n return fpd_\n}\n\n\n/** 创建软链接 Create soft links \n - fp_real: 现在真实文件/文件夹的路径 current real file/directory path\n - fp_link: 目标链接文件/文件夹的路径 target file/directory path */\nexport async function flink (\n fp_real: string, \n fp_link: string, \n {\n junction = false,\n print = true \n }: { \n junction?: boolean\n print?: boolean\n} = { }) {\n assert(path.isAbsolute(fp_real) && path.isAbsolute(fp_link), t('fp 必须是绝对路径'))\n \n const is_fpd_real = fp_real.endsWith('/')\n const is_fpd_link = fp_link.endsWith('/')\n \n assert(is_fpd_real === is_fpd_link, t('fp_real 和 fp_link 必须同为文件路径或文件夹路径'))\n \n if (fexists(fp_link))\n throw new Error(t('存在同名') + (is_fpd_link ? t('文件夹') : t('文件')) + ': ' + fp_link + t(',无法创建链接'))\n \n if (print)\n console.log(t('已将源文件 ') + fp_real + t(' 链接到 ') + fp_link)\n \n if (junction)\n fsp.symlink(fp_real, fp_link, 'junction')\n else\n fsp.symlink(fp_real, fp_link, is_fpd_real ? 'dir' : 'file')\n}\n\n\n/** 打开一个文件并搜索替换某个 pattern open a file and replace certain pattern */\nexport async function freplace (fp: string, pattern: string | RegExp, replacement: string) {\n await fwrite(\n fp,\n (await fread(fp))\n .replaceAll(pattern, replacement)\n )\n}\n\n"]}
|
package/i18n/dict.json
CHANGED
|
@@ -307,5 +307,17 @@
|
|
|
307
307
|
},
|
|
308
308
|
"尝试释放未锁定的锁,这不应该发生": {
|
|
309
309
|
"en": "Attempt to release an unlocked lock, this should not happen"
|
|
310
|
+
},
|
|
311
|
+
"超时错误": {
|
|
312
|
+
"en": "timeout error"
|
|
313
|
+
},
|
|
314
|
+
"xshell 启动成功,用时 {{duration}},正在监听: http://localhost:8421\n": {
|
|
315
|
+
"en": "xshell started successfully, took {{duration}}, is listening: http://localhost:8421\n"
|
|
316
|
+
},
|
|
317
|
+
"xshell 启动成功,用时 ": {
|
|
318
|
+
"en": "xshell started successfully, it took "
|
|
319
|
+
},
|
|
320
|
+
"正在监听: http://localhost:8421\n": {
|
|
321
|
+
"en": "listening: http://localhost:8421\n"
|
|
310
322
|
}
|
|
311
323
|
}
|
package/i18n/index.js
CHANGED
|
@@ -6,7 +6,7 @@ export const LANGUAGES = ['zh', 'en', 'ja', 'ko'];
|
|
|
6
6
|
提供翻译文本功能,自动解析当前语言
|
|
7
7
|
@see https://github.com/ShenHongFei/xshell/tree/master/i18n
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
class I18N {
|
|
10
10
|
static LANGUAGE_REGEXP = /^(zh|en|ja|jp|ko)$/;
|
|
11
11
|
/** (ISO 639-1 标准语言代码) 可能取 zh, en, ja, ko */
|
|
12
12
|
language;
|
|
@@ -116,4 +116,5 @@ export class I18N {
|
|
|
116
116
|
};
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
+
export { I18N };
|
|
119
120
|
//# sourceMappingURL=index.js.map
|
package/i18n/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,WAAW,CAAA;AAC/B,OAAO,EAAE,OAAO,IAAI,OAAO,EAAwB,MAAM,SAAS,CAAA;AAGlE,OAAO,EAAE,IAAI,EAAyB,MAAM,WAAW,CAAA;AAKvD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAU,CAAA;AAS1D;;;EAGE;AACF,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import Cookies from 'js-cookie'\nimport { default as i18next, type i18n as I18Next } from 'i18next'\nimport type { Trans } from 'react-i18next'\n\nimport { Dict, type _Dict, type Item } from './dict.js'\n\n\nexport type Language = 'zh' | 'en' | 'ja' | 'ko'\n\nexport const LANGUAGES = ['zh', 'en', 'ja', 'ko'] as const\n\ndeclare global {\n interface Window {\n language: Language\n }\n}\n\n\n/**\n 提供翻译文本功能,自动解析当前语言\n @see https://github.com/ShenHongFei/xshell/tree/master/i18n\n*/\nexport class I18N {\n static LANGUAGE_REGEXP = /^(zh|en|ja|jp|ko)$/\n \n \n /** (ISO 639-1 标准语言代码) 可能取 zh, en, ja, ko */\n language: Language\n \n /** hostname shortcuts */\n hosts: Hosts\n \n /** url prefix shortcuts */\n roots: Roots\n \n /** 标记静态文本,以便扫描词条,并在运行时根据当前语言获取翻译 */\n t : (text: string, options?: { language?: Language, context?: string, count?: number, [key: string]: any }) => string\n \n /** render: 翻译配置字段 */\n r : (field: Item | undefined | null, language?: Language) => string\n \n i18next: I18Next\n \n /** react-i18next <Trans/> 组件 */\n Trans: typeof Trans = ({ children }) => children as any\n \n \n /** ```ts\n import dict from './dict.json' // { \"添加\": { \"en\": \"Add\", \"ja\": \"追加\", \"ko\": \"추가\" } }\n \n const i18n = new I18N(dict, 'zh') // 创建实例,传入词典 dict 并指定语言(NodeJS 环境),\n const i18n = new I18N(dict) // 创建实例,传入词典 dict 并自动判断当前语言(浏览器环境),\n const i18n = new I18N({ }) // 创建实例,传入空词典\n ```\n @see https://github.com/ShenHongFei/xshell/tree/master/i18n\n */\n constructor (_dict: _Dict, language?: Language) {\n const is_browser = typeof window !== 'undefined' && typeof location !== 'undefined'\n \n const dict = new Dict(_dict)\n \n if (!language && is_browser)\n language = (\n new URLSearchParams(location.search).get('language') || \n window.language || \n Cookies.get('language')\n ) as Language\n \n if (!language)\n language = Intl.DateTimeFormat().resolvedOptions().locale.slice(0, 2) as Language\n \n if (!I18N.LANGUAGE_REGEXP.test(language)) {\n if (language)\n console.error('invalid language:', language)\n language = 'zh'\n }\n \n // console.log('language:', language)\n \n this.language = language\n \n this.t = (text, options) => {\n options = options || { }\n \n const language = options.language || this.language\n \n return this.i18next.t(text, { ...options, lng: language, defaultValue: text })\n }\n \n this.r = (field, language = this.language) => \n field ?\n field[language] || field.zh || field.en || field as any || ''\n :\n field || ''\n \n // --- init i18next\n this.i18next = i18next.createInstance()\n \n if (is_browser)\n try {\n // 在无 React 的浏览器环境下避免 react-i18next 中执行 React.createContext() 报错\n // const React = require('react') as typeof import('react')\n const { initReactI18next, Trans: I18NextTrans } = require('react-i18next') as typeof import('react-i18next')\n this.i18next.use(initReactI18next)\n const _i18next = this.i18next\n // 绑定 Trans 组件的 i18n 到 this.i18next, 解决多个 i18next 冲突的问题\n // react-i18next/context.js 中 i18n 实例只在模块级别维护,多次 this.i18next.use(initReactI18next) 会覆盖前面的 i18n,导致 Trans 无法翻译\n // https://github.com/i18next/react-i18next/issues/726\n this.Trans = function Trans ({ i18n = _i18next, ...others }) {\n // 简单转发,性能更好\n return I18NextTrans({ i18n, ...others })\n // return React.createElement(I18NextTrans, { i18n, ...others } as any, children)\n // return <I18NextTrans {...{ i18n, ...others } }>{children}</I18NextTrans>\n }\n } catch { }\n \n this.i18next.init({\n lng: this.language,\n // LOCAL\n // debug: true,\n debug: false,\n fallbackLng: {\n en: ['zh'],\n ja: ['en', 'zh'],\n ko: ['en', 'zh'],\n },\n // 禁用 : 和 . 作为 seperator\n keySeparator: false,\n nsSeparator: false,\n resources: dict.to_resources(),\n interpolation: {\n escapeValue: false\n },\n react: {\n transKeepBasicHtmlNodesFor: []\n },\n })\n \n \n if (typeof window !== 'undefined' && window && !('i18n' in window))\n (window as any).i18n = this\n }\n \n \n /** 加载词典文件 (需要将这两行单独放一个文件里,以保证在 import 其他文件之前执行) \n \n @example\n import dict from './dict.json' // { \"添加\": { \"en\": \"Add\", \"ja\": \"追加\", \"ko\": \"추가\" } }\n i18n.init(dict)\n */\n init (dict: _Dict) {\n const resources = new Dict(dict).to_resources()\n for (const language in resources)\n this.i18next.addResources(language, 'translation', resources[language].translation)\n }\n \n toJSON () {\n return {\n language: this.language,\n }\n }\n}\n\n\nexport interface Hosts {\n \n}\n\n\nexport interface Roots {\n \n}\n\nexport type { _Dict, Item }\n\nexport interface I18NBasic {\n intl: boolean\n language: Language\n}\n"]}
|
package/net.browser.js
CHANGED
|
@@ -288,6 +288,7 @@ export class Remote {
|
|
|
288
288
|
else
|
|
289
289
|
data_[i] = item;
|
|
290
290
|
}
|
|
291
|
+
// 有可能 data_json 含有循环引用导致 JSON.stringify 报错
|
|
291
292
|
const data_json = {
|
|
292
293
|
id,
|
|
293
294
|
...func ? { func } : {},
|
|
@@ -323,29 +324,29 @@ export class Remote {
|
|
|
323
324
|
return;
|
|
324
325
|
else if (!this.url)
|
|
325
326
|
throw new Error(t('创建 Remote 时传入的 websocket 连接已断开'));
|
|
326
|
-
|
|
327
|
+
else
|
|
328
|
+
// 假设有多个请求想要并发连接 websocket, 且此时 websocket 是断开的状态
|
|
329
|
+
// 应该排队依次连接,而不是后续的连接直接使用第一次连接的 promise,后续调用还是应该尝试重连(不止连接一次)
|
|
330
|
+
return this.lwebsocket.request(async (websocket) => {
|
|
331
|
+
// 保存的 rpc 状态在 this.handlers, 与 websocket 无关,因此即使断开重连也不影响 rpc 的运行,即
|
|
332
|
+
// 底层连接断开后自动重连对上层应该是无感知的,除非再次连接时失败
|
|
333
|
+
if (websocket?.readyState === WebSocket.OPEN)
|
|
334
|
+
return;
|
|
335
|
+
else if (!this.url)
|
|
336
|
+
throw new Error(t('创建 Remote 时传入的 websocket 连接已断开'));
|
|
337
|
+
else // 重连
|
|
338
|
+
this.lwebsocket.resource = await connect_websocket(this.url, {
|
|
339
|
+
on_message: (data, websocket) => {
|
|
340
|
+
this.handle(new Uint8Array(data), websocket);
|
|
341
|
+
},
|
|
342
|
+
on_error: this.on_error.bind(this)
|
|
343
|
+
});
|
|
344
|
+
});
|
|
327
345
|
}
|
|
328
346
|
else if (websocket.readyState === WebSocket.OPEN)
|
|
329
347
|
return;
|
|
330
348
|
else
|
|
331
349
|
throw new Error(t('传入的 websocket 连接已断开'));
|
|
332
|
-
// 假设有多个请求想要并发连接 websocket, 且此时 websocket 是断开的状态
|
|
333
|
-
// 应该排队依次连接,而不是后续的连接直接使用第一次连接的 promise,后续调用还是应该尝试重连(不止连接一次)
|
|
334
|
-
return this.lwebsocket.request(async (websocket) => {
|
|
335
|
-
// 保存的 rpc 状态在 this.handlers, 与 websocket 无关,因此即使断开重连也不影响 rpc 的运行,即
|
|
336
|
-
// 底层连接断开后自动重连对上层应该是无感知的,除非再次连接时失败
|
|
337
|
-
if (websocket?.readyState === WebSocket.OPEN)
|
|
338
|
-
return;
|
|
339
|
-
else if (!this.url)
|
|
340
|
-
throw new Error(t('创建 Remote 时传入的 websocket 连接已断开'));
|
|
341
|
-
else // 重连
|
|
342
|
-
this.lwebsocket.resource = await connect_websocket(this.url, {
|
|
343
|
-
on_message: (data, websocket) => {
|
|
344
|
-
this.handle(new Uint8Array(data), websocket);
|
|
345
|
-
},
|
|
346
|
-
on_error: this.on_error.bind(this)
|
|
347
|
-
});
|
|
348
|
-
});
|
|
349
350
|
}
|
|
350
351
|
disconnect() {
|
|
351
352
|
this.lwebsocket.resource?.close(1000);
|
|
@@ -401,16 +402,12 @@ export class Remote {
|
|
|
401
402
|
throw new Error(`${t('找不到 rpc handler')}: ${func ? `func: ${func.quote()}` : `id: ${id}`}`);
|
|
402
403
|
}
|
|
403
404
|
catch (error) {
|
|
404
|
-
//
|
|
405
|
+
// handler 出错并不意味着 rpc 一定会结束,可能 error 是运行中的正常数据,所以不能清理 handler
|
|
405
406
|
if (websocket.readyState === WebSocket.OPEN &&
|
|
406
407
|
!message.error // 防止无限循环往对方发送 error, 只有在对方无错误时才可以发送
|
|
407
408
|
)
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
}
|
|
411
|
-
catch { }
|
|
412
|
-
// 再往上层抛出错误没有意义了,上层调用栈是 websocket.on('message') 之类的
|
|
413
|
-
console.log(error);
|
|
409
|
+
await this.send({ id, error, /* 不能设置 done 清理对面 handler, 理由同上 */ }, websocket);
|
|
410
|
+
throw error;
|
|
414
411
|
}
|
|
415
412
|
}
|
|
416
413
|
/** 调用 remote 中的 func, 只适用于最简单的一元 rpc (请求, 响应) */
|