xshell 1.0.23 → 1.0.25
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/package.json +7 -8
- package/tsconfig.json +1 -1
- package/utils.browser.d.ts +1 -1
- package/utils.browser.js +4 -4
- package/utils.d.ts +1 -1
- package/utils.js +1 -1
- package/chalk.browser.js.map +0 -1
- package/file.js.map +0 -1
- package/i18n/dict.js.map +0 -1
- package/i18n/i18n-scan.js.map +0 -1
- package/i18n/index.js.map +0 -1
- package/i18n/instance.js.map +0 -1
- package/i18n/rwdict.js.map +0 -1
- package/i18n/scanner/checker.js.map +0 -1
- package/i18n/scanner/index.js.map +0 -1
- package/i18n/scanner/parser.js.map +0 -1
- package/i18n/utils.js.map +0 -1
- package/index.js.map +0 -1
- package/net.browser.js.map +0 -1
- package/net.js.map +0 -1
- package/process.js.map +0 -1
- package/prototype.browser.js.map +0 -1
- package/prototype.js.map +0 -1
- package/repl.js.map +0 -1
- package/server.js.map +0 -1
- package/toaster.browser.js.map +0 -1
- package/utils.browser.js.map +0 -1
- package/utils.js.map +0 -1
- package/xshell.js.map +0 -1
- /package/patches/{koa@2.14.1.patch → koa@2.14.2.patch} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xshell",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.25",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"bin": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"interactive programming"
|
|
17
17
|
],
|
|
18
18
|
"engines": {
|
|
19
|
-
"node": ">=19.
|
|
19
|
+
"node": ">=19.9.0",
|
|
20
20
|
"vscode": ">=1.77.0"
|
|
21
21
|
},
|
|
22
22
|
"author": "ShenHongFei <shen.hongfei@outlook.com> (https://github.com/ShenHongFei)",
|
|
@@ -60,14 +60,13 @@
|
|
|
60
60
|
"emoji-regex": "^10.2.1",
|
|
61
61
|
"fetch-cookie": "^2.1.0",
|
|
62
62
|
"fs-extra": "^11.1.1",
|
|
63
|
-
"fs-monkey": "^1.0.3",
|
|
64
63
|
"gulp-sort": "^2.0.0",
|
|
65
64
|
"hash-string": "^1.0.0",
|
|
66
65
|
"i18next": "^22.4.14",
|
|
67
66
|
"i18next-scanner": "^4.2.0",
|
|
68
67
|
"js-cookie": "^3.0.1",
|
|
69
|
-
"koa": "^2.14.
|
|
70
|
-
"koa-compress": "^5.1.
|
|
68
|
+
"koa": "^2.14.2",
|
|
69
|
+
"koa-compress": "^5.1.1",
|
|
71
70
|
"koa-useragent": "^4.1.0",
|
|
72
71
|
"lodash": "^4.17.21",
|
|
73
72
|
"map-stream": "0.0.7",
|
|
@@ -80,8 +79,8 @@
|
|
|
80
79
|
"through2": "^4.0.2",
|
|
81
80
|
"tough-cookie": "^4.1.2",
|
|
82
81
|
"tslib": "^2.5.0",
|
|
83
|
-
"typescript": "^5.0.
|
|
84
|
-
"undici": "^5.21.
|
|
82
|
+
"typescript": "^5.0.4",
|
|
83
|
+
"undici": "^5.21.2",
|
|
85
84
|
"upath": "^2.0.1",
|
|
86
85
|
"vinyl": "^3.0.0",
|
|
87
86
|
"vinyl-fs": "^3.0.3",
|
|
@@ -100,7 +99,7 @@
|
|
|
100
99
|
"@types/lodash": "^4.14.192",
|
|
101
100
|
"@types/node": "^18.15.11",
|
|
102
101
|
"@types/qs": "^6.9.7",
|
|
103
|
-
"@types/react": "^18.0.
|
|
102
|
+
"@types/react": "^18.0.35",
|
|
104
103
|
"@types/through2": "^2.0.38",
|
|
105
104
|
"@types/tough-cookie": "^4.0.2",
|
|
106
105
|
"@types/vinyl-fs": "^3.0.1",
|
package/tsconfig.json
CHANGED
package/utils.browser.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export interface Deferred<TValue> extends Promise<TValue> {
|
|
|
14
14
|
- initial?: `undefined` 传入非 undefined 值(包括 null)时直接设置为 resolved 状态 */
|
|
15
15
|
export declare function defer<TValue>(initial?: TValue): Deferred<TValue>;
|
|
16
16
|
export interface LockedAction<TResource, TResult> {
|
|
17
|
-
(resource: TResource): Promise<TResult>;
|
|
17
|
+
(resource: TResource): TResult | Promise<TResult>;
|
|
18
18
|
}
|
|
19
19
|
/** @example
|
|
20
20
|
let lock = new Lock(redis)
|
package/utils.browser.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { t } from './i18n/instance.js';
|
|
2
2
|
export const noop = () => { };
|
|
3
3
|
export function assert(assertion, message) {
|
|
4
|
-
if (assertion)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
if (!assertion) {
|
|
5
|
+
debugger;
|
|
6
|
+
throw Object.assign(new Error(`断言失败: ${message ? `${message}: ` : ''}${assertion}`), { assertion });
|
|
7
|
+
}
|
|
8
8
|
}
|
|
9
9
|
export async function delay(milliseconds) {
|
|
10
10
|
return new Promise(resolve => {
|
package/utils.d.ts
CHANGED
|
@@ -54,7 +54,7 @@ export interface Deferred<TValue> extends Promise<TValue> {
|
|
|
54
54
|
- initial?: `undefined` 传入非 undefined 值(包括 null)时直接设置为 resolved 状态 */
|
|
55
55
|
export declare function defer<TValue>(initial?: TValue): Deferred<TValue>;
|
|
56
56
|
export interface LockedAction<TResource, TResult> {
|
|
57
|
-
(resource: TResource): Promise<TResult>;
|
|
57
|
+
(resource: TResource): TResult | Promise<TResult>;
|
|
58
58
|
}
|
|
59
59
|
/** @example
|
|
60
60
|
let lock = new Lock(redis)
|
package/utils.js
CHANGED
|
@@ -25,7 +25,7 @@ export function set_inspect_options() {
|
|
|
25
25
|
export function assert(assertion, message) {
|
|
26
26
|
if (!assertion) {
|
|
27
27
|
debugger;
|
|
28
|
-
throw new Error(
|
|
28
|
+
throw Object.assign(new Error(`断言失败: ${message ? `${message}: ` : ''}${inspect(assertion, { colors: false, compact: true })}`), { assertion });
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
export function dedent(templ, ...values) {
|
package/chalk.browser.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chalk.browser.js","sourceRoot":"","sources":["chalk.browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAE7B,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAA;AAErC,MAAM,EACF,GAAG,EACH,KAAK,EACL,MAAM,EACN,IAAI,EACJ,OAAO,EACP,IAAI,EACJ,IAAI,EAEJ,SAAS,EAAE,IAAI,EACf,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,OAAO,EACrB,UAAU,EAAE,KAAK,EACjB,aAAa,EAAE,QAAQ,EACvB,UAAU,EAAE,KAAK,EAEjB,SAAS,GACZ,GAAG,KAAK,CAAA;AAET,OAAO,EACH,GAAG,EACH,KAAK,EACL,MAAM,EACN,IAAI,EACJ,OAAO,EACP,IAAI,EACJ,IAAI,EAEJ,IAAI,EACJ,MAAM,EACN,OAAO,EACP,KAAK,EACL,QAAQ,EACR,KAAK,EAEL,SAAS,EACZ,CAAA","sourcesContent":["import { Chalk } from 'chalk'\n\nconst chalk = new Chalk({ level: 2 })\n\nconst {\n red, \n green, \n yellow, \n blue, \n magenta, \n cyan, \n grey,\n \n redBright: red_, \n greenBright: green_, \n yellowBright: yellow_, \n blueBright: blue_, \n magentaBright: magenta_,\n cyanBright: cyan_,\n \n underline,\n} = chalk\n\nexport {\n red,\n green,\n yellow,\n blue,\n magenta,\n cyan,\n grey,\n \n red_,\n green_,\n yellow_,\n blue_,\n magenta_,\n cyan_,\n \n underline\n}\n"]}
|
package/file.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dict.js","sourceRoot":"","sources":["dict.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,IAAI;IACb,KAAK,CAAO;IAEZ,YAAa,QAAe,EAAE;QAC1B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;IACtB,CAAC;IAID,GAAG,CAAE,GAAW,EAAE,QAAmB;QACjC,IAAI,CAAC,GAAG;YACJ,OAAO,EAAE,CAAA;QAEb,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAE5B,IAAI,QAAQ;YACR,OAAO,IAAI,CAAC,CAAC;gBACL,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;gBACxB,CAAC;oBACG,EAAE,CAAA;QAEd,OAAO,IAAI,CAAA;IACf,CAAC;IAED,YAAY;QACR,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAE,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE;YAC3D,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAE,CAAC,CAAE,QAAQ,EAAE,WAAW,CAAE,EAAE,EAAE;gBACxD,IAAI,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;oBAAE,OAAM;gBAC1C,GAAG,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,WAAW,CAAA;YAChD,CAAC,CAAC,CAAA;YACF,OAAO,GAAG,CAAA;QACd,CAAC,EAAE;YACC,EAAE,EAAE,EAAE,WAAW,EAAE,EAAG,EAAE;YACxB,EAAE,EAAE,EAAE,WAAW,EAAE,EAAG,EAAE;YACxB,EAAE,EAAE,EAAE,WAAW,EAAE,EAAG,EAAE;YACxB,EAAE,EAAE,EAAE,WAAW,EAAE,EAAG,EAAE;SAC3B,CAAC,CAAA;IACN,CAAC;CACJ","sourcesContent":["import type { Language } from './index.js'\n\nexport class Dict {\n _dict: _Dict\n \n constructor (_dict: _Dict = {}) {\n this._dict = _dict\n }\n \n get (key: string): Item | undefined\n get (key: string, language: Language): string | ''\n get (key: string, language?: Language) {\n if (!key)\n return ''\n \n const item = this._dict[key]\n \n if (language)\n return item ?\n item[language] || ''\n :\n ''\n \n return item\n }\n \n to_resources () {\n return Object.entries(this._dict).reduce( (acc, [key, item]) => {\n Object.entries(item).forEach( ([ language, translation ]) => {\n if (!translation || !acc[language]) return\n acc[language].translation[key] = translation\n })\n return acc\n }, {\n zh: { translation: { } },\n en: { translation: { } },\n ja: { translation: { } },\n ko: { translation: { } },\n })\n }\n}\n\n\n/** 配置字段 */\nexport type Item = {\n [language in Language]?: string\n}\n\n\n/** JSON.parse(词典文件.json) 得到的对象 */\nexport interface _Dict {\n [key: string]: Item\n}\n"]}
|
package/i18n/i18n-scan.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"i18n-scan.js","sourceRoot":"","sources":["i18n-scan.ts"],"names":[],"mappings":";AAEA,OAAO,IAAI,MAAM,OAAO,CAAA;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAEzC;AAAA,CAAC,KAAK,UAAU,IAAI;IACjB,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC;SACpB,MAAM,CAAC,yBAAyB,EAAK,eAAe,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;SACpF,MAAM,CAAC,qBAAqB,EAAS,6EAA6E,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;SACtI,MAAM,CAAC,uBAAuB,EAAO,6BAA6B,CAAC;SACnE,MAAM,CAAC,uBAAuB,EAAO,kHAAkH,EAAE,gBAAgB,CAAC;SAC1K,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAExB,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAA;IACzD,OAAO,CAAC,OAAO,EAAE;QACb,GAAI,MAAM,aAAa,CACnB,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAChC;QACD,GAAI,KAAK,CAAE,CAAC,CAAE,EAAE,KAAK,EAAE,CAAG,CAAC,CAAE,EAAG;QAChC,GAAI,MAAM,CAAC,CAAC,CAAE,EAAE,MAAM,EAAE,CAAE,CAAC,CAAE,EAAG;KACnC,CAAC,CAAA;AACN,CAAC,CAAC,EAAE,CAAA","sourcesContent":["#!/usr/bin/env node\n\nimport path from 'upath'\nimport { program } from 'commander'\n\nimport { scanner } from './scanner/index.js'\nimport { try_load_dict } from './utils.js'\n\n;(async function main () {\n program.name('i18n-scan')\n .option('-r, --rootdir [rootdir]' , '根目录:默认为当前工作目录', path.normalize(process.cwd()))\n .option('-i, --input [input]' , '扫描 pattern:多个 pattern 用分号分割,采用 glob pattern 匹配,如 `src/**/*.{js,jsx,ts,tsx}`', v => v.split(';'))\n .option('-o, --output [output]' , 'i18n 目录:默认为 <rootdir>/i18n/')\n .option('-c, --config [config]' , '自定义配置文件,默认为 <rootdir>/i18n/config.js ,可参考默认配置 xshell/i18n/index.ts 以及 https://github.com/i18next/i18next-scanner', 'i18n/config.js')\n .parse(process.argv)\n \n const { rootdir, config, input, output } = program.opts()\n scanner(rootdir, {\n ... await try_load_dict(\n path.resolve(rootdir, config)\n ),\n ... input ? { input } : { },\n ... output ? { output } : { },\n })\n})()\n"]}
|
package/i18n/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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/i18n/instance.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"instance.js","sourceRoot":"","sources":["instance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACjC,OAAO,KAAK,MAAM,aAAa,CAAC,SAAS,IAAI,EAAE,MAAM,EAAE,CAAA;AAEvD,MAAM,CAAC,IAAI,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAA;AACjC,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAA;AAC5B,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAA","sourcesContent":["import { I18N } from './index.js'\nimport _dict from './dict.json' assert { type: 'json' }\n\nexport let i18n = new I18N(_dict)\nconst { t, language } = i18n\nexport { t, language }\n"]}
|
package/i18n/rwdict.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rwdict.js","sourceRoot":"","sources":["rwdict.ts"],"names":[],"mappings":"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","sourcesContent":["import '../prototype.js'\n\nimport type { Language } from './index.js'\nimport {\n Dict,\n type Item,\n type _Dict,\n} from './dict.js'\n\n\n/** read write Dict for scanner */\nexport class RWDict extends Dict {\n /** 更新词条 */\n set_item (key: string, item: Item, { print = true, placeholder = false, overwrite = false, dryrun = false, create = false } = { }) {\n if (!key || !item || typeof item !== 'object') throw new Error('key/item 错误')\n \n if (!item.zh && !item.en && !item.ja && !item.ko) {\n if (placeholder) {\n const empty_item = { en: '', ja: '', ko: '' }\n if (!dryrun && create)\n this._dict[key] = empty_item\n if (print)\n console.log(`${'+ '.green + key}: ${JSON.stringify(empty_item)}`)\n } else\n if (print)\n console.log(`${'! 未翻译:'.red}${key}`)\n \n return\n }\n \n Object.entries(item).forEach( ([language, translation]: [Language, string]) => {\n this.set_translation(key, language, translation, { print, overwrite, dryrun, create })\n })\n }\n \n \n /** 更新词条翻译 */\n set_translation (key: string, language: Language, translation: string, {\n /** 允许新增词条 */\n create = true, \n /** 允许更新翻译 */\n overwrite = false,\n print = true, \n placeholder = false, \n dryrun = false\n } = { }) {\n if (!key || !language) throw new Error('key/language 不能为空')\n if (!translation) return\n \n // --- add item\n let item = this._dict[key]\n \n const id = `(${key.replace(/\\n/g, '\\\\n')}).${language}`\n \n if (!item) {\n if (!create) {\n console.log(`${'+ '.red + id} ${translation.replace(/\\n/g, '\\\\n')}`)\n return\n }\n if (print)\n console.log(`${'+ '.green}${key.replace(/\\n/g, '\\\\n')}`)\n \n item = { }\n \n if (!dryrun)\n this._dict[key] = item\n }\n \n \n // --- update translation\n const _translation = item[language]\n \n \n // add\n if (!_translation) {\n if (print)\n console.log(`${'+ '.green + id}: ${translation.replace(/\\n/g, '\\\\n')}`)\n if (!dryrun)\n item[language] = translation\n return\n }\n \n // modify\n if (_translation !== translation)\n if (!overwrite) {\n console.error(`${`已存在 ${id} 词条:`.red} ${JSON.stringify(item)}`)\n console.error(`${'M? '.yellow}${_translation.replace(/\\n/g, '\\\\n')} → ${translation.replace(/\\n/g, '\\\\n')}`)\n if (!dryrun)\n console.error(`如要更新翻译请设置 { overwrite: true },否则使用 i18n.t('text', { context: 'xxx' }) 标记文本以区分。\\n`)\n return\n } else {\n if (print)\n console.log(`${'M '.yellow}${_translation.replace(/\\n/g, '\\\\n')} → ${translation.replace(/\\n/g, '\\\\n')}`)\n if (!dryrun)\n item[language] = translation\n }\n }\n \n /** 合并、更新词典 \n print?: true \n dryrun?: false \n overwrite?: false \n create?: true \n */\n merge (_dict: _Dict, { print = true, overwrite = false, dryrun = false, create = true } = { }) {\n Object.entries(_dict).forEach( ([key, item]) => {\n this.set_item(key, item, { print, overwrite, dryrun, create })\n })\n \n if (dryrun) {\n console.log('dry run completed'.green)\n return\n }\n \n if (print)\n console.log('词典合并完成'.green)\n \n return this\n }\n \n \n \n /** trim?: [true] 是否过滤掉空词条及空翻译 */ \n to_json (trim: boolean = true) {\n if (trim)\n this._dict = Object.fromEntries(\n (Object.entries(this._dict)\n .map( ([key, item]) => ([\n key,\n Object.fromEntries(\n Object.entries(item).filter( ([ language, translation ]) => translation )\n )\n ])\n ).filter( ([ key, item ]: [string, Item]) => Object.keys(item).length )\n )\n )\n \n return JSON.stringify(this._dict, null, 4)\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"checker.js","sourceRoot":"","sources":["checker.ts"],"names":[],"mappings":"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","sourcesContent":["import * as types from '@babel/types'\nimport { PluginItem } from '@babel/core'\n\nexport let unmarkeds = []\n\nlet t = 0\nlet Trans = 0\n\nfunction is_t (node: types.Node) {\n if (types.isCallExpression(node)) {\n // t('chtext')\n if (types.isIdentifier(node.callee) && node.callee.name === \"t\")\n return true\n \n // i18n.t('chtext') | i18n.__('chtext')\n if (\n types.isMemberExpression(node.callee) &&\n types.isIdentifier(node.callee.object) &&\n types.isIdentifier(node.callee.property) &&\n node.callee.object.name === \"i18n\" &&\n (node.callee.property.name === \"t\" || node.callee.property.name === '__')\n )\n return true\n }\n return false\n}\n\nfunction is_trans (node: types.Node) {\n // <Trans>\n return (\n types.isJSXElement(node) &&\n types.isJSXOpeningElement(node.openingElement) &&\n types.isJSXIdentifier(node.openingElement.name) &&\n node.openingElement.name.name === \"Trans\"\n )\n}\n\nconst has_unmarked_chinese_characters = (str: string) => \n !t && !Trans && /[\\u4e00-\\u9fa5]/.test(str)\n\n\nexport function Checker ({ filepath }) {\n return {\n CallExpression: {\n enter({ node }) {\n if (is_t(node))\n t++\n },\n exit({ node }) {\n if (is_t(node))\n t--\n },\n },\n JSXElement: {\n enter({ node }) {\n if (is_trans(node))\n Trans++\n },\n exit({ node }) {\n if (is_trans(node))\n Trans--\n },\n },\n JSXText: ({ node }) => {\n if (has_unmarked_chinese_characters(node.value))\n unmarkeds.push({ filepath, loc: node.loc, value: node.value })\n },\n StringLiteral: ({ node }) => {\n if (has_unmarked_chinese_characters(node.value))\n unmarkeds.push({ filepath, loc: node.loc, value: node.value })\n },\n TemplateElement: ({ node }) => {\n if (has_unmarked_chinese_characters(node.value.raw))\n unmarkeds.push({ filepath, loc: node.loc, value: node.value.cooked })\n },\n } as PluginItem\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Transform } from 'stream'\n\nimport i18n_scanner from 'i18next-scanner'\nimport path from 'upath'\nimport vfs from 'vinyl-fs'\nimport sort from 'gulp-sort'\nimport ora from 'ora'\nimport cli_truncate from 'cli-truncate'\nimport Vinyl from 'vinyl'\nimport through2 from 'through2'\nimport CliTable from 'cli-table3'\n\nimport '../../prototype.js'\nimport { map_stream } from '../../utils.js'\n\nimport {\n LANGUAGES,\n type Language,\n} from '../index.js'\nimport { RWDict } from '../rwdict.js'\nimport type { _Dict } from '../dict.js'\nimport { try_load_dict } from '../utils.js'\n\n\nimport { mix_parse_trans_from_string_by_babel } from './parser.js'\n\n\n\n/** 默认 i18next 扫描配置 */\nconst DEFAULT_CONFIG = {\n debug: false,\n \n input: [\n // 'src/**/*.{js,jsx,ts,tsx}',\n '!i18n/**', // Use ! to filter out files or directories\n '!node_modules/**',\n '!**/*.d.ts',\n ],\n \n // 相对于根目录\n output: 'i18n/',\n \n // 若是相对路径,则以 output 为基准进行解析\n dict: ['dict.json', 'untranslateds.json'],\n \n lngs: ['zh', 'en', 'ja', 'ko'],\n ns: ['translation'],\n defaultLng: 'zh',\n defaultNs: 'translation',\n\n func: {\n list: [ 'i18next.t', 'i18n.t', 'i18n.__', 't', '__' ],\n extensions: [ ], // 避免在 transform 中执行原生的 parseFuncFromString\n },\n \n trans: {\n extensions: [ ], // 避免在 transform 中执行原生的 parseTransFromString\n fallbackKey: true,\n \n babylon: {\n sourceType: 'module',\n \n allowAwaitOutsideFunction: true,\n \n // https://babeljs.io/docs/en/babel-parser\n plugins: [\n // Language extensions\n 'jsx',\n 'typescript',\n \n // ECMAScript proposals\n 'classProperties',\n 'classPrivateProperties',\n 'classPrivateMethods',\n 'classStaticBlock',\n 'decimal',\n ['decorators', { decoratorsBeforeExport: true }],\n 'doExpressions',\n 'exportDefaultFrom',\n 'functionBind',\n 'importAssertions',\n 'moduleBlocks',\n 'moduleStringNames',\n 'partialApplication',\n ['pipelineOperator', { proposal: 'smart' }],\n 'privateIn',\n ['recordAndTuple', { syntaxType: 'bar' }],\n 'throwExpressions',\n 'topLevelAwait',\n ],\n } as import('@babel/parser').ParserOptions,\n \n // 实际并没有用到 acorn, 用了 babel\n acorn: {\n ecmaVersion: 'latest',\n sourceType: 'module', // defaults to 'module'\n // Check out https://github.com/acornjs/acorn/tree/master/acorn#interface for additional options\n }\n },\n \n // 禁用 : 和 . 作为 seperator\n keySeparator: false, // char to separate keys\n nsSeparator: false, // char to split namespace from key\n \n // Context Form\n context: true, // whether to add context form key\n contextFallback: true, // whether to add a fallback key as well as the context form key\n contextSeparator: '_', // char to split context from key\n\n // Plural\n // whether to add plural form key\n plural (language: string, ns: string, key: string, options: any /** Config */) {\n return language === 'en'\n }, \n pluralFallback: true, // whether to add a fallback key as well as the plural form key\n pluralSeparator: '_', // char to split plural from key\n \n // interpolation options\n interpolation: {\n prefix: '{{', // prefix for interpolation\n suffix: '}}' // suffix for interpolation\n }\n}\n\nconst VALID_EXTENTIONS = new Set(['.js', '.jsx', '.ts', '.tsx'])\n\nexport type Config = Partial<(typeof DEFAULT_CONFIG) & {\n defaultValue?: string\n resource?: { loadPath?: string, savePath?: string, jsonIndent?: number, lineEnding?: '\\n' }\n}>\n\n\n/** 扫描源码中的词条,以及收集未翻译的词条,将结果保存到 dict.json 和 untranslateds.json\n - `process.cwd()` rootdir 要扫描根目录\n - config 配置信息\n*/\nexport async function scanner (rootdir: string = path.normalize(process.cwd()), config: Config = { }) {\n const output = path.resolve(rootdir, config.output || DEFAULT_CONFIG.output)\n \n if (!config.input.length)\n throw new Error('运行 i18n-scan 请指定 --input')\n \n const input = [...config.input, ...DEFAULT_CONFIG.input]\n \n config = {\n ...DEFAULT_CONFIG,\n ...config,\n input,\n output,\n resource: {\n loadPath: '',\n savePath: path.resolve(output, 'translation/{{lng}}.js'),\n jsonIndent: 4,\n lineEnding: '\\n'\n }\n }\n \n let dict = new RWDict()\n \n for (const fp_dict of config.dict)\n dict.merge(\n await try_load_dict(\n path.resolve(output, fp_dict)\n ), { print: false, overwrite: true }\n )\n \n \n let c_files = 0\n let c_scanneds = 0\n let error_handlers = []\n \n // 所有语言的扫描统计信息\n let stats: Record<Language, { translateds: Set<string>, untranslateds: Set<string> }> = { } as any\n \n for (const language of LANGUAGES)\n stats[language] = {\n translateds: new Set<string>(),\n untranslateds: new Set<string>()\n }\n \n \n let spinner = ora({ interval: 66 }).start('Scanning...')\n \n \n \n function on_scanned (text: string, { language, key, defaultValue, count, context }: { language?: Language, key?: string, defaultValue?: string, count?: number, context?: string }) {\n // console.log(text, { language, key, defaultValue, count, context })\n \n text = text || defaultValue\n \n if (!key)\n key = context ? `${text}_${context}` : text\n \n if (!language) {\n for (const language of LANGUAGES)\n on_scanned(text, { language, key, count, context })\n return\n }\n \n // console.log(text, { language, key, defaultValue, count, context })\n // debugger\n \n const stat = stats[language]\n \n // 获取已有翻译\n const translation = \n dict.get(key, language) || \n language === 'zh' && text || \n ''\n \n if (language === 'zh' && !context)\n return\n \n if (translation)\n stat.translateds.add(key)\n else\n stat.untranslateds.add(key)\n \n if (language === 'en' && count !== undefined)\n on_scanned(text, { language, key: `${key}_plural`, context })\n }\n \n \n function new_vinyl_file (_path: string, data: string | object) {\n return new Vinyl({\n cwd: rootdir,\n base: rootdir,\n path: path.resolve(config.output, _path),\n contents: Buffer.from(typeof data === 'string' ? data : JSON.stringify(data, null, 4))\n })\n }\n \n return new Promise<number>((resolve, reject) => {\n // ------------ scan by file\n vfs\n .src(config.input, { cwd: rootdir, sync: false })\n \n // 每个文件扫描前,统计文件数量\n .pipe(\n map_stream((file: Vinyl, cb: Function) => {\n // 支持 `// @i18n-noscan` 忽略扫描\n if (/\\/\\/\\s*@i18n-noscan\\s/.test(file.contents.toString()))\n return cb()\n c_files++\n cb(null, file)\n })\n )\n \n // 对文件进行排序,保证词条有一定的顺序\n .pipe(\n sort()\n )\n \n // 分析代码提取词条\n .pipe(\n i18n_scanner.createStream( config, function transform (this: { parser: any }, file: Vinyl, encoding: string, callback: Function): void {\n const { parser } = this\n const ext = path.extname(file.path)\n \n // 只扫描源码文件\n if (!VALID_EXTENTIONS.has(ext)) {\n callback()\n return\n }\n \n c_scanneds++\n const percent = Math.round(\n 100 * c_scanneds / c_files\n )\n const text = `Scanning (${percent}%): ${file.path.blue}`\n spinner.text = cli_truncate(text, process.stdout.columns - 5, { position: 'middle', })\n \n let code = file.contents.toString()\n \n // --- 添加代码中扫描到的 i18n.t('key') 中的 key 到 parser\n // parser.parseFuncFromString 使用 esprima 来解析代码,esprima 仍然不支持 optional chaining !!\n parser.parseFuncFromString(code.replace(/\\?\\.\\[/g, '[').replace(/\\?\\.\\(/g, '(').replace(/\\?\\./g, '.'), on_scanned)\n \n // --- 添加代码中扫描到的 Trans 组件中的 key 到 parser\n if (ext === '.jsx' || ext === '.tsx') {\n // parser.parseTransFromString 使用 acorn 解析代码,不支持 TypeScript,添加 parser.parseTransFromStringByBabel\n mix_parse_trans_from_string_by_babel(parser)\n parser.parseTransFromStringByBabel(\n code,\n { filepath: file.path },\n on_scanned,\n (error: Error) => {\n error_handlers.push(error)\n }\n )\n }\n \n setTimeout(callback, 0)\n })\n )\n \n // 创建词条文件\n .pipe(\n through2.obj(\n /** i18n-scanner 会把扫描结果以每个语言一个文件的形式提供,这里解析扫描结果\n * file: 翻译 resource 文件,其中 file.contents 包含翻译的扫描结果\n */\n function write (this: Transform, file: Vinyl, encoding: string, cb: Function) { cb() },\n \n /** 生成 stats.json, unmarkeds.md; 打印 untranslated / unmarkeds */\n function flush (this: Transform, cb: Function) {\n // ------------ stats.json\n this.push(new_vinyl_file('stats.json', \n Object.fromEntries(\n Object.entries(stats).map( ([l, { translateds, untranslateds }]) => \n [l, { translateds: Array.from(translateds), untranslateds: Array.from(untranslateds) }])\n )\n ))\n \n \n // ------------ 打印 cli 统计表\n const table = new CliTable({\n head: [\n '语言',\n '未翻译'.red,\n '已翻译'.green,\n ],\n colAligns: ['right', 'right', 'right', 'right'],\n style: { head: [] },\n chars: {\n top: '',\n 'top-mid': '',\n 'top-left': '',\n 'top-right': '',\n bottom: '',\n 'bottom-mid': '',\n 'bottom-left': '',\n 'bottom-right': '',\n left: '',\n 'left-mid': '',\n mid: '',\n 'mid-mid': '',\n right: '',\n 'right-mid': '',\n middle: ' ',\n },\n })\n \n Object.entries(stats).forEach( ([lang, stat]) => {\n table.push([\n lang, \n String(stat.untranslateds.size).red, \n String(stat.translateds.size).green\n ] as any)\n })\n \n \n \n spinner.stop()\n console.log(`Scanned ${c_files} files. Occured ${error_handlers.length} errors.`)\n console.log(table.toString())\n \n \n // ------------ 生成 unmarkeds.md 统计\n /*\n const fp_unmarked = path.resolve(config.output, 'unmarkeds.md')\n \n if (fs.existsSync(fp_unmarked))\n rimraf.sync(fp_unmarked)\n \n if (unmarkeds.length) {\n console.log(colors.yellow(`\\n⚠️ 发现未标记的中文字符 ${unmarkeds.length} 处:\\n`))\n unmarkeds.forEach(({ value, filepath, loc: { start } }, index) => {\n if (index >= 5) return\n console.log( ` ${colors.white(`'${value}'`)}\\t${colors.blue.underline(`${path.relative(rootdir, filepath)}:${start.line}:${start.column + 1}`)}` )\n })\n }\n \n this.push( new_vinyl_file( fp_unmarked, \n unmarkeds.map( ({ value, filepath, loc }) =>\n '- [' + value.trim() + '](' + path.relative( config.output, path.resolve(rootdir, filepath || '') ) + '#L' + loc.start.line + ')'\n ).join('\\n') + '\\n'\n ))\n \n \n if (unmarkeds.length > 5) {\n console.log(' ...')\n console.log(colors.yellow(`\\n 完整未标记词条请查看 ${colors.blue.underline(path.relative(rootdir, fp_unmarked))}`))\n }\n */\n \n const en_untranslateds = stats.en.untranslateds\n if (en_untranslateds.size) {\n console.log('\\n缺少英文翻译的词条:'.yellow)\n let i = 0\n for (const untranslated of en_untranslateds) {\n if (i >= 10)\n break\n console.log(untranslated)\n i++\n }\n if (en_untranslateds.size > 10) {\n console.log('...')\n console.log(`--- 共 ${en_untranslateds.size} 个未翻译的英文词条 ---`)\n }\n } else\n console.log('\\n所有词条都至少含有英文翻译'.green)\n \n \n // ------------ 生成 untranslateds.json (扫描到词条还没有英文翻译)\n const fp_untranslateds = path.resolve(config.output, 'untranslateds.json')\n \n let untranslateds: _Dict = { }\n \n for (const key of stats.en.untranslateds) {\n let item = { ...dict.get(key) }\n item.en ||= ''\n item.ja ||= ''\n item.ko ||= ''\n untranslateds[key] = item\n }\n \n this.push(\n new_vinyl_file(fp_untranslateds, untranslateds)\n )\n \n \n // ------------ 写入 dict.json\n const fp_dict_new = path.resolve(output, 'dict.json')\n this.push(\n new_vinyl_file(\n fp_dict_new,\n dict.to_json(true) + '\\n'\n )\n )\n \n console.log(\n `\\n\\n${'请手动补全未翻译的词条: '.yellow}${fp_untranslateds.underline.blue}\\n` +\n `${'请检查新生成的词典文件: '.yellow}${fp_dict_new.underline.blue}\\n` +\n '\\n' +\n '补全 untranslateds.json 后需要重新运行扫描,会根据 untranslateds.json 更新 dict.json\\n'.yellow +\n '最后 dict.json 所包含的词条会被打包进 js, 通过 new I18N(<dict.json>) 或 i18n.init(<dict.json>) 加载\\n\\n'.yellow +\n `${'详细文档请查看: '.yellow}${'https://github.com/ShenHongFei/xshell/tree/master/i18n'.blue.underline}`\n )\n \n cb()\n }\n )\n )\n \n // 写入词条文件\n .pipe(\n vfs.dest(rootdir)\n )\n \n .on('end', () => {\n if (error_handlers.length) {\n for (const error_handler of error_handlers)\n error_handler()\n \n console.log(`以上错误可能是由不规范的词条标记导致,标记规范可见:\\n${'https://www.i18next.com/translation-function/essentials'.blue.underline}`)\n }\n \n resolve(stats.en.untranslateds.size)\n })\n })\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parser.js","sourceRoot":"","sources":["parser.ts"],"names":[],"mappings":"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","sourcesContent":["import castArray from 'lodash/castArray.js'\nimport trim from 'lodash/trim.js'\nimport _get from 'lodash/get.js'\n\nimport babel_traverse from '@babel/traverse'\nconst { default: traverse } = babel_traverse\n\nimport { parse } from '@babel/parser'\nimport t from '@babel/types'\n\nimport '../../prototype.js'\n\n\n// import { Checker } from './checker'\n\n/** file:///D:/0/i18next-scanner/src/parser.js */\nexport function mix_parse_trans_from_string_by_babel (parser) {\n parser.parseTransFromStringByBabel = function parse_trans_from_string_by_babel (\n code: string, \n options = { }, \n custom_handler = null,\n on_error: (callback: Function) => void \n = () => { }\n ) {\n if (typeof options === 'function') {\n custom_handler = options\n options = { }\n }\n \n const {\n transformOptions = { }, // object\n component = this.options.trans.component, // string\n i18nKey = this.options.trans.i18nKey, // string\n defaultsKey = this.options.trans.defaultsKey, // string\n fallbackKey = this.options.trans.fallbackKey, // boolean|function\n babylon: babylon_options = this.options.trans.babylon, // object\n filepath,\n } = options as any\n \n const parseJSXElement = ({ node }) => {\n if (!node) return\n \n if (node.openingElement.name.name !== component) return\n \n \n const getLiteralValue = literal => {\n if (t.isTemplateLiteral(literal))\n return literal.quasis.map(element => element.value.cooked).join(\"\")\n \n return literal.value\n }\n \n const attr = castArray(node.openingElement.attributes).reduce(\n (acc, attribute) => {\n if (\n !t.isJSXAttribute(attribute) ||\n !t.isJSXIdentifier(attribute.name)\n ) return acc\n \n const { name } = attribute.name\n const value = attribute.value\n if (t.isLiteral(value))\n acc[name] = getLiteralValue(value)\n else if (t.isJSXExpressionContainer(value)) {\n const expression = value.expression\n if (t.isIdentifier(expression))\n acc[name] = expression.name\n else if (t.isLiteral(expression))\n acc[name] = getLiteralValue(expression)\n else if (t.isObjectExpression(expression)) {\n const properties = castArray(expression.properties)\n acc[name] = properties.reduce((obj, property) => {\n if (!t.isObjectProperty(property)) return obj\n if (t.isLiteral(property.value))\n obj[(property.key as any).name] = getLiteralValue(property.value)\n else // Unable to get value of the property\n obj[(property.key as any).name] = \"\"\n return obj\n }, { })\n /**\n * 防止 count 被忽略,如\n * ```jsx\n * <Trans count={arr.length}>\n * 一二三{{ count: arr.length }}\n * </Trans>\n * ```\n */\n } else if (name === \"count\")\n acc[name] = 0\n }\n return acc\n },\n { }\n )\n const transKey = trim(attr[i18nKey])\n \n const defaultsString = attr[defaultsKey] || \"\"\n if (typeof defaultsString !== \"string\")\n this.log(`defaults value must be a static string, saw ${defaultsString.yellow}`)\n \n \n // https://www.i18next.com/translation-function/essentials#overview-options\n const tOptions = attr.tOptions\n const options = {\n ...tOptions,\n defaultValue: defaultsString || nodes_to_string(node.children, filepath, on_error),\n fallbackKey,\n }\n \n if (Object.prototype.hasOwnProperty.call(attr, \"count\"))\n options.count = Number(attr.count) || 0\n \n \n if (Object.prototype.hasOwnProperty.call(attr, \"ns\")) {\n if (typeof options.ns !== \"string\")\n this.log(`The ns attribute must be a string, saw ${attr.ns?.yellow}`)\n \n options.ns = attr.ns\n }\n \n if (custom_handler) {\n custom_handler(transKey, options)\n return\n }\n \n this.set(transKey, options)\n }\n \n try {\n const ast = parse(code, { ...babylon_options })\n traverse(ast, { JSXElement: parseJSXElement, })\n // traverse(ast, Checker({ filepath }))\n } catch (err) {\n on_error(() => {\n console.error('')\n const { line, column } = (err && err.loc) || { line: 1, column: 1 }\n console.error([filepath, line, column].join(\":\").yellow)\n console.error(`Unable to parse ${component?.blue} component.\\n`.red)\n if (!filepath)\n console.error(String(code).red)\n console.error((\" \" + err.message).red)\n })\n }\n \n return this\n }\n}\n\n\nfunction nodes_to_string (nodes, filepath, onError) {\n let memo = ''\n let node_index = 0\n nodes.forEach((node, i) => {\n if (t.isJSXText(node) || t.isStringLiteral(node)) {\n const value = node.value\n .replace(/^[\\r\\n]+\\s*/g, \"\") // remove leading spaces containing a leading newline character\n .replace(/[\\r\\n]+\\s*$/g, \"\") // remove trailing spaces containing a leading newline character\n .replace(/[\\r\\n]+\\s*/g, \" \") // replace spaces containing a leading newline character with a single space character\n \n if (!value) return\n \n memo += value\n } else if (t.isJSXExpressionContainer(node)) {\n const { expression = { } } = node\n \n if (t.isNumericLiteral(expression)) // Numeric literal is ignored in react-i18next\n memo += ''\n if (t.isStringLiteral(expression))\n memo += expression.value\n else if (\n t.isObjectExpression(expression) &&\n t.isObjectProperty(_get(expression, 'properties[0]'))\n )\n memo += '{{' + (expression.properties[0] as any).key.name + '}}'\n else\n onError(() => {\n const { line, column } = (node.expression && node.expression.loc.start) || { line: 1, column: 1 }\n console.error('')\n console.error([filepath, line, column].join(\":\").yellow)\n console.error('Unsupported JSX expression. Only static values or {{interpolation}} blocks are supported.'.red)\n })\n \n } else if (node.children)\n memo += `<${node_index}>${nodes_to_string(node.children, filepath, onError)}</${node_index}>`\n \n \n node_index++\n })\n \n return memo\n}\n\n"]}
|
package/i18n/utils.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAEvC,MAAM,CAAC,KAAK,UAAU,aAAa,CAAE,OAAe;IAChD,IAAI;QACA,OAAO,MAAM,UAAU,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAA;KACrD;IAAC,MAAM;QACJ,4CAA4C;QAC5C,OAAO,EAAG,CAAA;KACb;AACL,CAAC","sourcesContent":["import { fread_json } from '../file.js'\n\nexport async function try_load_dict (fp_dict: string) {\n try {\n return await fread_json(fp_dict, { print: false })\n } catch {\n // console.error('未找到或解析错误,跳过加载:' + modpath)\n return { }\n }\n}\n"]}
|
package/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA","sourcesContent":["export * from './prototype.js'\nexport * from './utils.js'\nexport * from './file.js'\nexport * from './process.js'\nexport * from './net.js'\n"]}
|
package/net.browser.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"net.browser.js","sourceRoot":"","sources":["net.browser.ts"],"names":[],"mappings":"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","sourcesContent":["import { t } from './i18n/instance.js'\nimport './prototype.browser.js' // to_time_str()\nimport { assert, concat, genid, delay, Lock } from './utils.browser.js'\n\n\n// ------------------------------------ fetch, request\nexport interface BasicAuth {\n type: 'basic',\n username: string\n password: string\n}\n\nexport interface BearerAuth {\n type: 'bearer',\n token: string\n}\n\n\nexport interface RequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'HEAD' | 'DELETE' | 'PATCH'\n \n queries?: Record<string, any>\n \n headers?: Record<string, string> | Headers\n \n body?: string | Record<string, any> | ArrayBufferView | ArrayBuffer | Blob |\n URLSearchParams | FormData\n \n type?: 'application/json' | 'application/x-www-form-urlencoded' | 'multipart/form-data'\n \n encoding?: 'binary'\n \n retries?: true | number\n \n timeout?: number\n \n auth?: BasicAuth | BearerAuth\n \n cookies?: Record<string, string>\n \n cors?: boolean\n}\n\nexport interface RequestRawOptions extends RequestOptions {\n raw: true\n}\n\n\nasync function fetch_retry (url: URL, options: RequestInit, timeout: number, retries = 0, count = 0): Promise<Response> {\n try {\n options.signal = AbortSignal.timeout(timeout)\n return await fetch(url, options)\n } catch (error) {\n if (\n count >= retries ||\n error.name !== 'TimeoutError' && !['ECONNRESET', 'ETIMEDOUT', 'ESOCKETTIMEDOUT'].includes(error.cause?.code)\n )\n throw error\n else {\n const duration = 2 ** count\n console.log(`${t('等待 {{duration}} 秒后重试 fetch ({{_count}}) …', { duration, _count: count })} ${url.toString()}`)\n await delay(1000 * duration)\n return fetch_retry(url, options, timeout, retries, count + 1)\n }\n }\n}\n\n\nexport interface RequestError extends Error {\n url: URL\n \n options: RequestInit\n \n response?: {\n /** 状态码 */\n status: number\n \n url: string\n \n headers: Headers\n \n ok: boolean\n \n type: ResponseType\n \n text: string\n \n redirected: boolean\n }\n}\n\n\n/**\n - url: 可以只有 pathname 部分\n - options?:\n - method?: `有 body 时为 POST, 否则为 GET` 'GET' | 'POST' | ···\n - queries?: 添加到 url 上的参数,是 Record<string, any>,true/false 会被转换为 0/1\n - headers?: http 请求头 (Record<string, string> 或者 Headers 类型),其中 key 必须是小写的\n - body?: http 请求体,可以是 string, Record<string, any> (会自动 JSON.stringify), ArrayBuffer(View), Blob, \n URLSearchParams (type 为 x-www-form-urlencoded), FormData (type 为 form-data)\n - type?: `'application/json'` 有 body 时设置 http 请求头中的 content-type 头\n - encoding?: 设置为 'binary' 时返回 ArrayBuffer 的 body\n - retries?: `false` 可以传入 true (默认 2 次) 或 重试次数\n - timeout?: `5 * 1000`\n - auth?: BasicAuth | BearerAuth\n - raw?: `false` 传入后返回整个 response */\nexport async function request (url: string | URL): Promise<string>\nexport async function request (url: string | URL, options: RequestRawOptions): Promise<Response>\nexport async function request (url: string | URL, options: RequestOptions & { encoding: 'binary' }): Promise<ArrayBuffer>\nexport async function request (url: string | URL, options: RequestOptions): Promise<string>\nexport async function request (url: string | URL, {\n method,\n \n queries,\n \n headers: _headers,\n \n body,\n \n type = 'application/json',\n \n encoding,\n \n retries,\n \n timeout = 5 * 1000,\n \n auth,\n \n raw = false,\n \n cors,\n}: RequestOptions & { raw?: boolean } = { }) {\n url = new URL(url, location.href)\n \n if (queries)\n for (const key in queries) {\n let value = queries[key]\n if (typeof value === 'boolean')\n value = value ? '1' : '0'\n url.searchParams.append(key, value)\n }\n \n if (body !== undefined && !method)\n method = 'POST'\n \n if (retries === true)\n retries = 2\n \n \n // --- headers, http/2 开始都用小写的 headers\n let headers = new Headers()\n \n if (body !== undefined)\n headers.set('content-type', type)\n \n if (auth)\n headers.set(\n 'authorization',\n auth.type === 'basic' ? `Basic ${`${auth.username}:${auth.password}`.to_base64()}` : `Bearer ${auth.token}`\n )\n \n if (_headers)\n if (_headers instanceof Headers)\n // @ts-ignore: ts 类型不支持,实际上已经有了\n for (const [key, value] of _headers)\n headers.set(key, value)\n else\n for (const key in _headers) {\n const value = _headers[key]\n if (!value.startsWith(':')) { // 可能在 http/2 的 response 中会有这样开头的保留 headers, 在透传时忽略比较好\n assert(key === key.toLowerCase(), t('传入 request 的 headers 参数中 key 应该都是小写的,实际为 {{key}}', { key }))\n headers[key] = value\n }\n }\n \n \n let options: RequestInit = {\n ... method ? { method } : { },\n \n keepalive: true,\n \n redirect: 'follow',\n \n credentials: 'include',\n \n ... cors ? { mode: 'cors' } : { },\n \n headers,\n \n // --- body\n body: (() => {\n if (body === undefined)\n return\n \n switch (type) {\n case 'application/json':\n return typeof body === 'string' || \n ArrayBuffer.isView(body) || \n body instanceof ArrayBuffer ||\n body instanceof Blob ?\n body as (string | NodeJS.ArrayBufferView | ArrayBuffer | Blob)\n :\n JSON.stringify(body)\n \n case 'application/x-www-form-urlencoded':\n return body instanceof URLSearchParams ? body : new URLSearchParams(body as Record<string, any>)\n \n case 'multipart/form-data':\n if (body instanceof FormData)\n return body\n else {\n let form = new FormData()\n for (const key in body as Record<string, any>) {\n let value = body[key]\n form.set(key, value)\n }\n return form\n }\n }\n })(),\n }\n \n \n let response: Response\n \n try {\n response = await fetch_retry(url, options, timeout, retries)\n \n if (!response.ok)\n throw Object.assign(\n new Error(t('状态码 {{status}}, 非 2xx', { status: response.status })),\n { name: 'StatusCodeError' }\n )\n } catch (error) {\n error.url = url\n error.options = options\n \n if (response)\n error.response = {\n status: response.status,\n url: response.url,\n headers: response.headers,\n ok: response.ok,\n type: response.type,\n text: await response.text(),\n redirected: response.redirected\n }\n \n throw error\n }\n \n if (raw)\n return response\n \n if (!response.body)\n return response.body\n \n if (encoding === 'binary')\n return response.arrayBuffer()\n else\n return response.text()\n}\n\n\n/** 发起 http 请求并将响应体作为 json 解析 */\nexport async function request_json <T = any> (url: string, options?: RequestOptions): Promise<T> {\n const resp = await request(url, options)\n if (!resp)\n return\n try {\n return JSON.parse(resp)\n } catch (error) {\n console.error(resp)\n throw error\n }\n}\n\n\n\nlet decoder = new TextDecoder()\n\nlet encoder = new TextEncoder()\n\n\nexport class WebSocketConnectionError extends Error {\n override name = 'WebSocketConnectionError'\n \n websocket: WebSocket\n \n event: CloseEvent | /* error 事件时的 event,没有 event.error */ Event\n \n type: 'close' | 'error'\n \n code?: number\n \n reason?: string\n \n \n constructor (websocket: WebSocket, event: CloseEvent | Event, message?: string) {\n super(`${websocket.url} ${t('连接出错了')}. ${message || ''}`)\n this.websocket = websocket\n this.event = event\n this.type = event.type as 'close' | 'error'\n if (this.type === 'close') {\n this.code = (event as CloseEvent).code\n this.reason = (event as CloseEvent).reason\n }\n }\n}\n\n\n/** 连接 websocket url, 设置各种事件监听器。在 open 事件后 resolve, 返回 websocket \n 遇到 error 时会创建 WebSocketConnectionError: \n - reject 掉返回的 promise (若此时未 settle) \n - 作为参数调用 on_error (已 settle 且有 on_error 回调) \n 可以用 WebSocket.bufferedAmount 来显示大消息的发送进度 \n https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/bufferedAmount\n - url\n - options:\n - protocols?\n - on_message: 根据 websocket frame 的 opcode 不同 (text frame 或 binary frame),event 中的 data 对应为 ArrayBuffer 或者 string \n https://datatracker.ietf.org/doc/html/rfc6455#section-5.2\n - on_error?: 在 websocket 出错和非正常关闭 (close, error 事件) 时都调用,可以根据 error.type 来区分,error 的类型是 WebSocketConnectionError, \n type 为 'close' 时有 code 和 reason 属性 \n - on_close?: 和 websocket 的 'close' 事件不相同,只在正常关闭 (close code 为 1000) 时才调用,否则都会调用 on_error \n https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#Status_codes */\nexport async function connect_websocket (\n url: string | URL,\n {\n protocols,\n on_message,\n on_error,\n on_close,\n }: {\n protocols?: string | string[]\n on_message (data: ArrayBuffer | string, websocket: WebSocket): any\n on_error? (error: WebSocketConnectionError, websocket: WebSocket): any\n on_close? (event: CloseEvent, websocket: WebSocket): any\n }\n) {\n let websocket = new WebSocket(url, protocols)\n \n // https://stackoverflow.com/questions/11821096/what-is-the-difference-between-an-arraybuffer-and-a-blob/39951543\n websocket.binaryType = 'arraybuffer'\n \n return new Promise<WebSocket>((resolve, reject) => {\n let settled = false\n \n websocket.addEventListener('open', event => {\n console.log(\n websocket.url +\n (protocols ? \n ' ' + (\n typeof protocols === 'string' ? protocols : protocols.join(', ').bracket('square')\n ).bracket()\n :\n '') +\n t(' 已连接')\n )\n \n settled = true\n resolve(websocket)\n })\n \n websocket.addEventListener('close', event => {\n if (event.code === 1000) // 正常关闭\n if (on_close)\n on_close(event, websocket)\n else\n console.log(`${websocket.url} ${t('已正常关闭')}`)\n else { // 异常关闭,认为发生了错误,进行错误处理\n const error = new WebSocketConnectionError(websocket, event, `${t('连接被关闭')}, code: ${event.code}${ event.reason ? `, ${t('原因')}: ${event.reason}` : '' }`)\n \n if (settled) {\n if (on_error)\n on_error(error, websocket)\n else // 既然用户不传 on_error, 就当 unhandled error 抛出来\n throw error\n } else {\n settled = true\n reject(error)\n }\n }\n })\n \n websocket.addEventListener('error', event => {\n const error = new WebSocketConnectionError(websocket, event)\n \n // https://blog.insiderattack.net/promises-next-ticks-and-immediates-nodejs-event-loop-part-3-9226cbe7a6aa\n // close 的错误信息比较多,这里延后触发 error 事件,放到微任务队列之后的 timers 队列中\n setTimeout(() => {\n if (settled) {\n if (on_error)\n on_error(error, websocket)\n else // 既然用户不传 on_error, 就当 unhandled error 抛出来\n throw error\n } else {\n settled = true\n reject(error)\n }\n })\n })\n \n websocket.addEventListener('message', event => {\n on_message(event.data, websocket)\n })\n })\n}\n\n\n/** 接收到消息后的处理函数 \n 返回值可以是:\n - 数组: 会自动被封装为 { id: 相同, data: 返回值, done: true } 这样的消息并调用 websocket.send 将其发送\n - void: 什么都不做\n - 以上的 promise */\nexport type MessageHandler = (message: Message, websocket?: WebSocket) => void | any[] | Promise<void | any[]>\n\n\n/** 二进制消息格式 \n - json.length (小端序): 4 字节\n - json 数据\n - binary 数据 */\nexport interface Message <TData extends any[] = any[]> {\n /** rpc id: 在 rpc 系统中认为是唯一的。用来在单个 websocket 连接上复用多个 rpc 请求。多个相同 id 的 message 组成一个请求流 */\n id?: number\n \n /** 只在 rpc 发起时指定被调用的 function name,发起时 rpc 时必传 */\n func?: string\n \n /** 通过这个 flag 主动表明这是发往对方的最后一个 message, 对方可以销毁 handler 了 \n 并非强制,可以不说明,由双方的函数自己约定\n */\n done?: boolean\n \n /** 通知对方这里产生的错误,本质上类似 data 也是一种数据,并不代表 rpc 的结束,后续可能继续有 rpc message 交换 */\n error?: Error\n \n /** data 是一个数组, 作为:\n - rpc 发起方调用 func 的参数,或者请求流 message 携带的数据\n - 结果或者响应流的数据,传给请求发起方\n \n 里面是可序列化为 json 的 js 变量,或者是 Uint8Array \n Uint8Array 的参数处理后被替换为 Uint8Array.byteLength, 并将下标记录在 bins 中\n \n 注意: 数组中如果有 undefined 值,传输到对面会变成 null 值 */\n data?: TData\n \n /** bins: data 中哪些下标对应的原始值是 Uint8Array 类型的,如: [0, 3] */\n bins?: number[]\n}\n\n/** 通过创建 remote 对象对 websocket rpc 进行抽象 \n 调用方使用 remote.call 进行调用 \n 被调方在创建 remote 对象时传入 funcs 注册处理函数,并使用 remote.handle 方法处理 websocket message \n 未连接时自动连接,断开后自动重连 (保证执行 send 时已连接,否则报错) \n 从设计上与 rpc 状态与底层连接的状态无关 (通过传入 url 创建的),底层连接断开后,只要检测到断线,会尝试重连,如果重连成功,则不影响调用的状态 \n @example\n // Zero 继承自 Remote 并通过 call 实现了一些方法\n let zero = new Zero({ local: true })\n \n // 一元 rpc\n await zero.repl_ts('1234')\n \n // 订阅流\n const id = genid()\n \n zero.handlers.set(id, ({ data: [chunk] }: Message<[Uint8Array]>) => {\n term.write(chunk)\n })\n \n zero.send({ id, func: 'subscribe_stdio' }) */\nexport class Remote {\n /** 是否为建立 rpc 连接的发起方 */\n initiator: boolean\n \n /** websocket url */\n url?: string\n \n /** 主动发起 websocket 连接的客户端 (构造函数传 url) 有这个属性 */\n lwebsocket?: Lock<WebSocket>\n \n /** 通过 rpc message.func 被调用的 rpc 函数 */\n funcs: Record<string, MessageHandler>\n \n /** map<id, message handler>: 通过 rpc message.id 找到对应的 handler, unary rpc 接收方不需要设置 handlers, 发送方需要 */\n handlers = new Map<number, MessageHandler>()\n \n \n print = false\n \n pconnect: Promise<any>\n \n \n /** 使用 Uint8Array 作为参数更灵活 https://stackoverflow.com/a/74505197/7609214 */\n static parse <TData extends any[] = any[]> (buffer: Uint8Array) {\n const dv = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)\n \n const len_json = dv.getUint32(0, true)\n \n let offset = 4 + len_json\n \n let message: Message<TData> = JSON.parse(decoder.decode(buffer.subarray(4, offset)))\n \n if (message.bins) {\n const { bins } = message\n let { data } = message\n \n for (const ibin of bins) {\n const len_buf = data[ibin]\n data[ibin] = buffer.subarray(offset, offset + len_buf)\n offset += len_buf\n }\n }\n \n if (message.error)\n message.error = Object.assign(new Error(), message.error)\n \n return message\n }\n \n \n static pack ({ id, func, data = [ ], done, error }: Message) {\n let data_ = new Array(data.length)\n let bins: number[] = [ ]\n let bufs: Uint8Array[] = [ ]\n \n for (let i = 0; i < data.length; i++) {\n const item = data[i]\n if (item instanceof Uint8Array) {\n bins.push(i)\n bufs.push(item)\n data_[i] = item.length\n } else\n data_[i] = item\n }\n \n // 有可能 data_json 含有循环引用导致 JSON.stringify 报错\n const data_json = {\n id,\n ... func ? { func } : { },\n ... done ? { done } : { },\n ... error ? { error } : { },\n ... data_.length ? { data: data_ } : { },\n ... bins.length ? { bins } : { },\n }\n \n const str_json = encoder.encode(JSON.stringify(data_json))\n \n let dv = new DataView(new ArrayBuffer(4))\n \n dv.setUint32(0, str_json.length, true)\n \n return concat([dv, str_json, ... bufs])\n }\n \n \n /** 作为 rpc 发起方,可以通过传入 url 或者 websocket 定义远程 Remote \n 作为 rpc 接收方,可以不传 url 和 websocket 定义本地 Remote */\n constructor ({\n url,\n funcs = { },\n websocket,\n on_error\n }: {\n url?: string\n funcs?: Remote['funcs']\n websocket?: WebSocket\n on_error? (error: WebSocketConnectionError, websocket: WebSocket): void\n } = { }) {\n assert(!(url && websocket), t('构建 Remote 时 url 和 websocket 最多只能传一个'))\n this.initiator = Boolean(url || websocket)\n this.url = url\n this.funcs = funcs\n if (on_error)\n this.on_error = on_error\n this.lwebsocket = new Lock(websocket || null)\n }\n \n \n on_error? (error: WebSocketConnectionError, websocket: WebSocket) {\n throw error\n }\n \n \n /** 幂等,保证 websocket 已连接,否则抛出异常,不需要手动调用,在其它方法中已默认自动重连 \n 作为接收方需要传入使用的 websocket 连接,确保这个这个连接的状态 */\n async connect (websocket?: WebSocket) {\n if (this.initiator) {\n if (this.lwebsocket.resource?.readyState === WebSocket.OPEN)\n return\n else if (!this.url)\n throw new Error(t('创建 Remote 时传入的 websocket 连接已断开'))\n else\n // 假设有多个请求想要并发连接 websocket, 且此时 websocket 是断开的状态\n // 应该排队依次连接,而不是后续的连接直接使用第一次连接的 promise,后续调用还是应该尝试重连(不止连接一次)\n return this.lwebsocket.request(async websocket => {\n // 保存的 rpc 状态在 this.handlers, 与 websocket 无关,因此即使断开重连也不影响 rpc 的运行,即\n // 底层连接断开后自动重连对上层应该是无感知的,除非再次连接时失败\n \n if (websocket?.readyState === WebSocket.OPEN)\n return\n else if (!this.url)\n throw new Error(t('创建 Remote 时传入的 websocket 连接已断开'))\n else // 重连\n this.lwebsocket.resource = await connect_websocket(this.url, {\n on_message: (data: ArrayBuffer, websocket) => {\n this.handle(new Uint8Array(data), websocket)\n },\n on_error: this.on_error.bind(this)\n })\n })\n } else\n if (websocket.readyState === WebSocket.OPEN)\n return\n else\n throw new Error(t('传入的 websocket 连接已断开'))\n }\n \n \n disconnect () {\n this.lwebsocket.resource?.close(1000)\n }\n \n \n /** 接收 websocket 连接的本地 remote 必传 websocket 参数;发起端选传,如果传了必须等于 this.websocket_lock.resource \n 发送或连接出错时自动清理 message.id 对应的 handler */\n async send (message: Message, websocket?: WebSocket) {\n try {\n if (this.initiator) {\n assert(!websocket || websocket === this.lwebsocket.resource)\n await this.connect()\n websocket = this.lwebsocket.resource\n } else\n await this.connect(websocket)\n \n if (!message.id)\n message.id = genid()\n \n // 不需要独占 websocket\n websocket.send(Remote.pack(message))\n } catch (error) {\n if (message.id)\n this.handlers.delete(message.id)\n throw error\n }\n }\n \n \n /** 处理接收到的 websocket message 并解析, 根据 id dispatch 到对应的 handler 进行处理 \n 如果 message.done == true 则清理 handler \n 如果 handler 返回了值,则包装为 message 发送 \n 使用 Uint8Array 作为参数更灵活 https://stackoverflow.com/a/74505197/7609214 */\n async handle (data: Uint8Array, websocket: WebSocket) {\n const message = Remote.parse(data)\n \n const { id, func, done } = message\n \n if (this.print)\n console.log(message)\n \n let handler: MessageHandler\n \n if (func)\n handler = this.funcs[func]\n else {\n handler = this.handlers.get(id)\n if (done)\n this.handlers.delete(id)\n }\n \n try {\n if (handler) {\n const data = await handler(message, websocket)\n if (data)\n await this.send({ id, data }, websocket)\n } else if (message.error)\n throw message.error\n else\n throw new Error(`${t('找不到 rpc handler')}: ${func ? `func: ${func.quote()}` : `id: ${id}`}`)\n } catch (error) {\n // handler 出错并不意味着 rpc 一定会结束,可能 error 是运行中的正常数据,所以不能清理 handler\n \n if (\n websocket.readyState === WebSocket.OPEN &&\n !message.error // 防止无限循环往对方发送 error, 只有在对方无错误时才可以发送\n )\n await this.send({ id, error, /* 不能设置 done 清理对面 handler, 理由同上 */ }, websocket)\n \n throw error\n }\n }\n \n \n /** 调用 remote 中的 func, 只适用于最简单的一元 rpc (请求, 响应) */\n async call <TReturn extends any[] = any[]> (func: string, args?: any[]) {\n return new Promise<TReturn>(async (resolve, reject) => {\n const id = genid()\n \n this.handlers.set(id, (message: Message<TReturn>) => {\n const { error, data } = message\n if (error)\n reject(error)\n else\n resolve(data)\n this.handlers.delete(id)\n })\n \n try {\n await this.send({ id, func, data: args }) // 不需要 done: true, 因为对面的 remote.handlers 中不会有这个 id 的 handler\n } catch (error) {\n reject(error)\n }\n })\n }\n}\n\n"]}
|