xshell 1.1.9 → 1.1.11
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 +6 -6
- package/path.d.ts +3 -5
- package/path.js +11 -21
- package/process.d.ts +20 -10
- package/process.js +59 -23
- package/prototype.browser.d.ts +28 -21
- package/prototype.browser.js +57 -54
- package/prototype.d.ts +27 -20
- package/prototype.js +53 -39
- package/server.d.ts +13 -12
- package/server.js +10 -6
- package/stdin.d.ts +4 -0
- package/stdin.js +23 -0
- package/storage.d.ts +3 -3
- package/storage.js +3 -2
- package/utils.browser.d.ts +12 -7
- package/utils.browser.js +39 -10
- package/utils.d.ts +12 -7
- package/utils.js +37 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xshell",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"bin": {
|
|
@@ -57,16 +57,16 @@
|
|
|
57
57
|
"@svgr/webpack": "^8.1.0",
|
|
58
58
|
"@types/sass-loader": "^8.0.9",
|
|
59
59
|
"@types/ws": "^8.5.13",
|
|
60
|
-
"@typescript-eslint/eslint-plugin": "^8.18.
|
|
61
|
-
"@typescript-eslint/parser": "^8.18.
|
|
62
|
-
"@typescript-eslint/utils": "^8.18.
|
|
60
|
+
"@typescript-eslint/eslint-plugin": "^8.18.2",
|
|
61
|
+
"@typescript-eslint/parser": "^8.18.2",
|
|
62
|
+
"@typescript-eslint/utils": "^8.18.2",
|
|
63
63
|
"@xterm/addon-fit": "^0.10.0",
|
|
64
64
|
"@xterm/addon-web-links": "^0.11.0",
|
|
65
65
|
"@xterm/addon-webgl": "^0.18.0",
|
|
66
66
|
"@xterm/xterm": "^5.5.0",
|
|
67
67
|
"ali-oss": "^6.22.0",
|
|
68
68
|
"archiver": "^7.0.1",
|
|
69
|
-
"chalk": "^5.4.
|
|
69
|
+
"chalk": "^5.4.1",
|
|
70
70
|
"chardet": "^2.0.0",
|
|
71
71
|
"cli-table3": "^0.6.5",
|
|
72
72
|
"cli-truncate": "^4.0.0",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"emoji-regex": "^10.4.0",
|
|
77
77
|
"eslint": "^9.17.0",
|
|
78
78
|
"eslint-plugin-import": "^2.31.0",
|
|
79
|
-
"eslint-plugin-react": "^7.37.
|
|
79
|
+
"eslint-plugin-react": "^7.37.3",
|
|
80
80
|
"gulp-sort": "^2.0.0",
|
|
81
81
|
"hash-string": "^1.0.0",
|
|
82
82
|
"https-proxy-agent": "^7.0.6",
|
package/path.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { default as npath, type FormatInputPathObject } from 'path';
|
|
2
|
-
export declare function to_fp(str: string): string;
|
|
3
2
|
/** Normalize a string path, reducing '..' and '.' parts.
|
|
4
3
|
When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved.
|
|
5
4
|
@param path string path to normalize.
|
|
@@ -55,7 +54,7 @@ export declare function extname(path: string): string;
|
|
|
55
54
|
/** `/` */
|
|
56
55
|
export declare const sep = "/";
|
|
57
56
|
/** The platform-specific file delimiter. ';' or ':'. */
|
|
58
|
-
export declare const delimiter: "
|
|
57
|
+
export declare const delimiter: ";" | ":";
|
|
59
58
|
/** Returns an object from a path string - the opposite of format().
|
|
60
59
|
@param path path to evaluate.
|
|
61
60
|
@throws {TypeError} if `path` is not a string. */
|
|
@@ -67,12 +66,11 @@ export declare function format(pathObject: FormatInputPathObject): string;
|
|
|
67
66
|
If path is not a string, path will be returned without modifications.
|
|
68
67
|
This method is meaningful only on Windows system.
|
|
69
68
|
On POSIX systems, the method is non-operational and always returns path without modifications. */
|
|
70
|
-
export declare function toNamespacedPath(path: string):
|
|
69
|
+
export declare function toNamespacedPath(path: string): string;
|
|
71
70
|
export declare const posix: npath.PlatformPath;
|
|
72
71
|
export declare const win32: npath.PlatformPath;
|
|
73
72
|
/** 统一使用 / 作为分隔符的 path 模块 */
|
|
74
73
|
export declare let path: {
|
|
75
|
-
to_fp: typeof to_fp;
|
|
76
74
|
normalize: typeof normalize;
|
|
77
75
|
join: typeof join;
|
|
78
76
|
resolve: typeof resolve;
|
|
@@ -83,7 +81,7 @@ export declare let path: {
|
|
|
83
81
|
basename: typeof basename;
|
|
84
82
|
extname: typeof extname;
|
|
85
83
|
sep: string;
|
|
86
|
-
delimiter: "
|
|
84
|
+
delimiter: ";" | ":";
|
|
87
85
|
parse: typeof parse;
|
|
88
86
|
format: typeof format;
|
|
89
87
|
toNamespacedPath: typeof toNamespacedPath;
|
package/path.js
CHANGED
|
@@ -1,25 +1,16 @@
|
|
|
1
1
|
import { default as npath } from 'path';
|
|
2
|
-
export function to_fp(str) {
|
|
3
|
-
if (!str)
|
|
4
|
-
return str;
|
|
5
|
-
const fp = str.replaceAll('\\', '/');
|
|
6
|
-
// 转换小写盘符开头的路径
|
|
7
|
-
return fp[1] === ':' && 'a' <= fp[0] && fp[0] <= 'z'
|
|
8
|
-
? fp[0].toUpperCase() + fp.slice(1)
|
|
9
|
-
: fp;
|
|
10
|
-
}
|
|
11
2
|
/** Normalize a string path, reducing '..' and '.' parts.
|
|
12
3
|
When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved.
|
|
13
4
|
@param path string path to normalize.
|
|
14
5
|
@throws {TypeError} if `path` is not a string. */
|
|
15
6
|
export function normalize(path) {
|
|
16
|
-
return
|
|
7
|
+
return npath.normalize(path).fp;
|
|
17
8
|
}
|
|
18
9
|
/** Join all arguments together and normalize the resulting path.
|
|
19
10
|
@param paths paths to join.
|
|
20
11
|
@throws {TypeError} if any of the path segments is not a string. */
|
|
21
12
|
export function join(...paths) {
|
|
22
|
-
return
|
|
13
|
+
return npath.join(...paths.map(p => p.fp)).fp;
|
|
23
14
|
}
|
|
24
15
|
/** The right-most parameter is considered {to}. Other parameters are considered an array of {from}.
|
|
25
16
|
|
|
@@ -33,7 +24,7 @@ export function join(...paths) {
|
|
|
33
24
|
@param paths A sequence of paths or path segments.
|
|
34
25
|
@throws {TypeError} if any of the arguments is not a string. */
|
|
35
26
|
export function resolve(...paths) {
|
|
36
|
-
return
|
|
27
|
+
return npath.resolve(...paths.map(p => p.fp)).fp;
|
|
37
28
|
}
|
|
38
29
|
/** 和 resolve 一样,但是保留最后一个 path 结尾的 / */
|
|
39
30
|
export function resolve_with_slash(...paths) {
|
|
@@ -50,20 +41,20 @@ export function resolve_with_slash(...paths) {
|
|
|
50
41
|
@param path path to test.
|
|
51
42
|
@throws {TypeError} if `path` is not a string. */
|
|
52
43
|
export function isAbsolute(path) {
|
|
53
|
-
return npath.isAbsolute(
|
|
44
|
+
return npath.isAbsolute(path.fp);
|
|
54
45
|
}
|
|
55
46
|
/** Solve the relative path from {from} to {to} based on the current working directory.
|
|
56
47
|
At times we have two absolute paths, and we need to derive the relative path from one to the other. This is actually the reverse transform of path.resolve.
|
|
57
48
|
|
|
58
49
|
@throws {TypeError} if either `from` or `to` is not a string. */
|
|
59
50
|
export function relative(from, to) {
|
|
60
|
-
return
|
|
51
|
+
return npath.relative(from.fp, to.fp).fp;
|
|
61
52
|
}
|
|
62
53
|
/** Return the directory name of a path. Similar to the Unix dirname command.
|
|
63
54
|
@param path the path to evaluate.
|
|
64
55
|
@throws {TypeError} if `path` is not a string. */
|
|
65
56
|
export function dirname(path) {
|
|
66
|
-
return
|
|
57
|
+
return npath.dirname(path.fp).fp;
|
|
67
58
|
}
|
|
68
59
|
/** Return the last portion of a path. Similar to the Unix basename command.
|
|
69
60
|
Often used to extract the file name from a fully qualified path.
|
|
@@ -71,7 +62,7 @@ export function dirname(path) {
|
|
|
71
62
|
@param suffix optionally, an extension to remove from the result.
|
|
72
63
|
@throws {TypeError} if `path` is not a string or if `ext` is given and is not a string. */
|
|
73
64
|
export function basename(path, suffix) {
|
|
74
|
-
return npath.basename(
|
|
65
|
+
return npath.basename(path.fp, suffix);
|
|
75
66
|
}
|
|
76
67
|
/** Return the extension of the path, from the last '.' to end of string in the last portion of the path.
|
|
77
68
|
If there is no '.' in the last portion of the path or the first character of it is '.', then it returns an empty string.
|
|
@@ -79,7 +70,7 @@ export function basename(path, suffix) {
|
|
|
79
70
|
@param path the path to evaluate.
|
|
80
71
|
@throws {TypeError} if `path` is not a string. */
|
|
81
72
|
export function extname(path) {
|
|
82
|
-
return npath.extname(
|
|
73
|
+
return npath.extname(path.fp);
|
|
83
74
|
}
|
|
84
75
|
/** `/` */
|
|
85
76
|
export const sep = '/';
|
|
@@ -89,25 +80,24 @@ export const delimiter = npath.delimiter;
|
|
|
89
80
|
@param path path to evaluate.
|
|
90
81
|
@throws {TypeError} if `path` is not a string. */
|
|
91
82
|
export function parse(path) {
|
|
92
|
-
return npath.parse(
|
|
83
|
+
return npath.parse(path.fp);
|
|
93
84
|
}
|
|
94
85
|
/** Returns a path string from an object - the opposite of parse().
|
|
95
86
|
@param pathObject path to evaluate. */
|
|
96
87
|
export function format(pathObject) {
|
|
97
|
-
return
|
|
88
|
+
return npath.format(pathObject).fp;
|
|
98
89
|
}
|
|
99
90
|
/** On Windows systems only, returns an equivalent namespace-prefixed path for the given path.
|
|
100
91
|
If path is not a string, path will be returned without modifications.
|
|
101
92
|
This method is meaningful only on Windows system.
|
|
102
93
|
On POSIX systems, the method is non-operational and always returns path without modifications. */
|
|
103
94
|
export function toNamespacedPath(path) {
|
|
104
|
-
return
|
|
95
|
+
return npath.toNamespacedPath(path.fp).fp;
|
|
105
96
|
}
|
|
106
97
|
export const posix = npath.posix;
|
|
107
98
|
export const win32 = npath.win32;
|
|
108
99
|
/** 统一使用 / 作为分隔符的 path 模块 */
|
|
109
100
|
export let path = {
|
|
110
|
-
to_fp,
|
|
111
101
|
normalize,
|
|
112
102
|
join,
|
|
113
103
|
resolve,
|
package/process.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { type ChildProcess } from 'child_process';
|
|
|
2
2
|
import './prototype.ts';
|
|
3
3
|
import type { Encoding } from './file.ts';
|
|
4
4
|
import type { MyProxy } from './net.ts';
|
|
5
|
+
import { inspect } from './utils.ts';
|
|
5
6
|
export declare const sea: boolean;
|
|
6
7
|
export declare const exe_nodejs: string;
|
|
7
8
|
export declare const platform: NodeJS.Platform;
|
|
@@ -97,19 +98,25 @@ export interface CallResult<TOutput extends string | Buffer = string> {
|
|
|
97
98
|
stderr: TOutput;
|
|
98
99
|
code: number | null;
|
|
99
100
|
signal: NodeJS.Signals | null;
|
|
101
|
+
command: string;
|
|
102
|
+
message: string;
|
|
100
103
|
child: ChildProcess;
|
|
104
|
+
print: FullPrintOptions;
|
|
101
105
|
}
|
|
102
|
-
export
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
106
|
+
export declare class CallError<TOutput extends string | Buffer = string> extends Error {
|
|
107
|
+
name: string;
|
|
108
|
+
pid: number;
|
|
109
|
+
stdout: TOutput;
|
|
110
|
+
stderr: TOutput;
|
|
111
|
+
code: number;
|
|
112
|
+
signal: NodeJS.Signals;
|
|
113
|
+
command: string;
|
|
114
|
+
child: ChildProcess;
|
|
115
|
+
print: FullPrintOptions;
|
|
116
|
+
constructor({ message, pid, stdout, stderr, code, signal, command, child, print }: CallResult<TOutput>);
|
|
117
|
+
[inspect.custom](): string;
|
|
111
118
|
}
|
|
112
|
-
/**
|
|
119
|
+
/** 调用可执行文件,获取返回结果,错误时抛出 CallError
|
|
113
120
|
- exe: .exe 路径或文件名 (建议使用路径,跳过 path 搜索,性能更高)
|
|
114
121
|
- args: `[ ]` 参数列表
|
|
115
122
|
- options?:
|
|
@@ -122,6 +129,9 @@ export interface CallError<TOutput extends string | Buffer = string> {
|
|
|
122
129
|
- stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理
|
|
123
130
|
- input?: string, 启动子进程之后写入到子进程 stdin 中的内容,写完后关闭子进程 stdin
|
|
124
131
|
- on_child?: 可以传入回调函数及时获取通过 start 创建的子进程,便于执行 kill、获得 pid 等操作 */
|
|
132
|
+
export declare function call(exe: string, args: string[], options: CallOptions & {
|
|
133
|
+
encoding: 'binary';
|
|
134
|
+
}): Promise<CallResult<Buffer>>;
|
|
125
135
|
export declare function call(exe: string, args?: string[], options?: CallOptions): Promise<CallResult<string>>;
|
|
126
136
|
export interface CallNodeJsOptions extends CallOptions {
|
|
127
137
|
inspect?: number | true;
|
package/process.js
CHANGED
|
@@ -9,12 +9,6 @@ export const platform = os.platform();
|
|
|
9
9
|
export const username = os.userInfo().username;
|
|
10
10
|
export const noprint = { print: false };
|
|
11
11
|
export const print_no_command = { print: { command: false, code: false, stdout: true, stderr: true } };
|
|
12
|
-
function get_command(exe, args) {
|
|
13
|
-
return (short_exe_names[exe] || exe.quote_if_space()) +
|
|
14
|
-
(args.length
|
|
15
|
-
? ' ' + args.map(arg => arg.quote_if_space()).join(' ')
|
|
16
|
-
: '');
|
|
17
|
-
}
|
|
18
12
|
async function prepare_spawn(detached, exe, args, { cwd, window: _window = true, envs,
|
|
19
13
|
// @ts-ignore
|
|
20
14
|
input, fp_stdin, fp_stdout, fp_stderr, print = true, proxy,
|
|
@@ -84,9 +78,15 @@ stdio }) {
|
|
|
84
78
|
stdout: print,
|
|
85
79
|
stderr: print
|
|
86
80
|
};
|
|
87
|
-
|
|
81
|
+
const command = (short_exe_names[exe] || exe.quote_if_space()) +
|
|
82
|
+
(args.length
|
|
83
|
+
? ' ' +
|
|
84
|
+
args
|
|
85
|
+
.map(arg => arg.quote_if_space())
|
|
86
|
+
.join(' ')
|
|
87
|
+
: '');
|
|
88
88
|
if (print.command)
|
|
89
|
-
console.log(
|
|
89
|
+
console.log(command.blue);
|
|
90
90
|
return {
|
|
91
91
|
print,
|
|
92
92
|
command,
|
|
@@ -126,8 +126,35 @@ export async function start(exe, args = [], options = {}) {
|
|
|
126
126
|
await close_all_handles();
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
|
+
export class CallError extends Error {
|
|
130
|
+
name = 'CallError';
|
|
131
|
+
pid;
|
|
132
|
+
stdout;
|
|
133
|
+
stderr;
|
|
134
|
+
code;
|
|
135
|
+
signal;
|
|
136
|
+
command;
|
|
137
|
+
child;
|
|
138
|
+
print;
|
|
139
|
+
constructor({ message, pid, stdout, stderr, code, signal, command, child, print }) {
|
|
140
|
+
super(message);
|
|
141
|
+
this.pid = pid;
|
|
142
|
+
this.stdout = stdout;
|
|
143
|
+
this.stderr = stderr;
|
|
144
|
+
this.code = code;
|
|
145
|
+
this.signal = signal;
|
|
146
|
+
this.command = command;
|
|
147
|
+
this.child = child;
|
|
148
|
+
this.print = print;
|
|
149
|
+
}
|
|
150
|
+
[inspect.custom]() {
|
|
151
|
+
return (!this.print.stdout && this.stdout ? `标准输出:\n${this.stdout}\n` : '') +
|
|
152
|
+
(!this.print.stderr && this.stderr ? `标准错误:\n${this.stderr}\n` : '') +
|
|
153
|
+
this.stack;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
129
156
|
export async function call(exe, args = [], options = {}) {
|
|
130
|
-
const { print,
|
|
157
|
+
const { print, spawn_options, close_all_handles, command } = await prepare_spawn(false, exe, args, options);
|
|
131
158
|
let child;
|
|
132
159
|
try {
|
|
133
160
|
child = spawn(exe, args, spawn_options);
|
|
@@ -191,14 +218,11 @@ export async function call(exe, args = [], options = {}) {
|
|
|
191
218
|
resolve();
|
|
192
219
|
});
|
|
193
220
|
});
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
: '正常结束');
|
|
200
|
-
console.log(message[code_error ? 'red' : 'blue']);
|
|
201
|
-
}
|
|
221
|
+
const message = `进程 ${command} ` + (code
|
|
222
|
+
? `${throw_code ? '异常' : ''}结束,退出码: ${code}${signal ? `,信号: ${signal}` : ''}`
|
|
223
|
+
: '正常结束');
|
|
224
|
+
if (print.code && !code)
|
|
225
|
+
console.log(message.blue);
|
|
202
226
|
const result = {
|
|
203
227
|
pid: child.pid,
|
|
204
228
|
stdout: encoding === 'binary'
|
|
@@ -209,16 +233,28 @@ export async function call(exe, args = [], options = {}) {
|
|
|
209
233
|
: stderrs.join(''),
|
|
210
234
|
code,
|
|
211
235
|
signal,
|
|
236
|
+
command,
|
|
237
|
+
message,
|
|
212
238
|
child,
|
|
239
|
+
print,
|
|
213
240
|
[inspect.custom]() {
|
|
214
|
-
return inspect(this, {
|
|
241
|
+
return inspect(this, {
|
|
242
|
+
omit: [
|
|
243
|
+
'child',
|
|
244
|
+
'message',
|
|
245
|
+
'command',
|
|
246
|
+
'code',
|
|
247
|
+
'signal',
|
|
248
|
+
'pid',
|
|
249
|
+
'print',
|
|
250
|
+
...print.stdout ? ['stdout'] : [],
|
|
251
|
+
...print.stderr ? ['stderr'] : [],
|
|
252
|
+
]
|
|
253
|
+
});
|
|
215
254
|
}
|
|
216
255
|
};
|
|
217
|
-
if (
|
|
218
|
-
|
|
219
|
-
error.result = result;
|
|
220
|
-
throw error;
|
|
221
|
-
}
|
|
256
|
+
if (throw_code && (code || signal))
|
|
257
|
+
throw new CallError(result);
|
|
222
258
|
return result;
|
|
223
259
|
}
|
|
224
260
|
/** 调用 node <js> 并等待结果
|
package/prototype.browser.d.ts
CHANGED
|
@@ -57,12 +57,11 @@ declare global {
|
|
|
57
57
|
|
|
58
58
|
- preservations?: `''` 保留的正则表达式字符
|
|
59
59
|
- flags?: `''` 正则匹配选项
|
|
60
|
-
- pattern_placeholder?: `/\{.*?\}/g`
|
|
61
|
-
*/
|
|
60
|
+
- pattern_placeholder?: `/\{.*?\}/g` */
|
|
62
61
|
find(this: string, pattern: string, preservations?: string, flags?: string, pattern_placeholder?: RegExp): Record<string, string>;
|
|
63
62
|
/** 查找子串或字符出现的次数 */
|
|
64
63
|
count(this: string, search: string): number;
|
|
65
|
-
/** - type?: `'single'` */
|
|
64
|
+
/** - type?: `'single'` 引号类型 */
|
|
66
65
|
quote(this: string, type?: keyof typeof quotes | 'psh'): string;
|
|
67
66
|
/** - shape?: `'parenthesis'` */
|
|
68
67
|
bracket(this: string, shape?: keyof typeof brackets): string;
|
|
@@ -105,17 +104,25 @@ declare global {
|
|
|
105
104
|
slice_to(this: string, search: string, options?: SliceOptions): string;
|
|
106
105
|
/** 等价于 .endsWith('/') */
|
|
107
106
|
isdir: boolean;
|
|
108
|
-
/**
|
|
107
|
+
/** 转换为以 `/` 分割的路径,可能以 / 结尾 */
|
|
109
108
|
fp: string;
|
|
110
|
-
/**
|
|
109
|
+
/** 转换为以 `/` 分割的文件夹路径,一定以 / 结尾 */
|
|
111
110
|
fpd: string;
|
|
112
|
-
/**
|
|
111
|
+
/** 父文件夹路径,一定以 `/` 结尾,或为空
|
|
112
|
+
特殊情况:
|
|
113
|
+
- '/'.fdir === ''
|
|
114
|
+
- 'D:/'.fdir === '' */
|
|
113
115
|
fdir: string;
|
|
114
|
-
/**
|
|
116
|
+
/** 文件或文件夹名, 保留结尾的 /
|
|
117
|
+
常规情况:
|
|
115
118
|
- D:/0/aaa.txt -> aaa.txt
|
|
116
|
-
- D:/aaa/ -> aaa/
|
|
119
|
+
- D:/aaa/ -> aaa/
|
|
120
|
+
特殊情况:
|
|
121
|
+
- '/'.fname === '/'
|
|
122
|
+
- 'D:/'.fname === 'D:/' */
|
|
117
123
|
fname: string;
|
|
118
|
-
/**
|
|
124
|
+
/** 文件后缀名,不带点,如: txt, zip,没有后缀时返回空字符串
|
|
125
|
+
特殊情况: .aaa 的 fext 为 '' */
|
|
119
126
|
fext: string;
|
|
120
127
|
}
|
|
121
128
|
interface Date {
|
|
@@ -148,15 +155,15 @@ declare global {
|
|
|
148
155
|
/** 等价于 .at(-1) */
|
|
149
156
|
last: T;
|
|
150
157
|
indent(this: string[], width?: number, c?: string): string[];
|
|
151
|
-
/** 对数组中所有元素求和 (+), 返回结果,可传入
|
|
152
|
-
sum<TReturn = T>(this: T[],
|
|
153
|
-
/** 查找数组中最大的元素,可传入
|
|
154
|
-
max(this: T[],
|
|
155
|
-
/** 查找数组中最小的元素,可传入
|
|
156
|
-
min(this: T[],
|
|
157
|
-
/** 去除重复元素(可按
|
|
158
|
-
-
|
|
159
|
-
unique(this: T[],
|
|
158
|
+
/** 对数组中所有元素求和 (+), 返回结果,可传入 mapper 计算出某个值,用作求和 */
|
|
159
|
+
sum<TReturn = T>(this: T[], mapper?: keyof T | Mapper<T>): TReturn;
|
|
160
|
+
/** 查找数组中最大的元素,可传入 mapper 计算出某个值,用作大小比较 */
|
|
161
|
+
max(this: T[], mapper?: keyof T | Mapper<T>): T;
|
|
162
|
+
/** 查找数组中最小的元素,可传入 mapper 计算出某个值,用作大小比较 */
|
|
163
|
+
min(this: T[], mapper?: keyof T | Mapper<T>): T;
|
|
164
|
+
/** 去除重复元素(可按 mapper 选择或计算某个值来去重),重复值保留最后出现的那个
|
|
165
|
+
- mapper?: 可以是 key (string, number, symbol) 或 (obj: any) => any */
|
|
166
|
+
unique(this: T[], mapper?: keyof T | Mapper<T>): T[];
|
|
160
167
|
/**
|
|
161
168
|
- trim_line?: `true`
|
|
162
169
|
- rm_empty_lines?: `true`
|
|
@@ -179,7 +186,7 @@ declare global {
|
|
|
179
186
|
toJSON(this: Error): string;
|
|
180
187
|
}
|
|
181
188
|
interface Set<T> {
|
|
182
|
-
map<TResult>(
|
|
189
|
+
map<TResult>(mapper: (value: T, index: number) => TResult): TResult[];
|
|
183
190
|
}
|
|
184
191
|
}
|
|
185
192
|
interface SliceOptions {
|
|
@@ -189,8 +196,8 @@ interface SliceOptions {
|
|
|
189
196
|
export declare const emoji_regex: RegExp;
|
|
190
197
|
export declare const noop: () => void;
|
|
191
198
|
export declare const ident: <T>(x: T) => T;
|
|
192
|
-
export declare const
|
|
193
|
-
export type
|
|
199
|
+
export declare const build_mapper: <TObj>(key: keyof TObj) => (obj: TObj) => TObj[keyof TObj];
|
|
200
|
+
export type Mapper<TObj = any, TKey extends keyof TObj = keyof TObj> = (obj: TObj) => TObj[TKey];
|
|
194
201
|
/** value 不为 null 或 undefined */
|
|
195
202
|
export declare const not_empty: (value: any) => boolean;
|
|
196
203
|
export declare const empty: (value: any) => boolean;
|
package/prototype.browser.js
CHANGED
|
@@ -4,7 +4,7 @@ import { t } from "./i18n/instance.js";
|
|
|
4
4
|
export const emoji_regex = EmojiRegex();
|
|
5
5
|
export const noop = () => { };
|
|
6
6
|
export const ident = (x) => x;
|
|
7
|
-
export const
|
|
7
|
+
export const build_mapper = (key) => (obj) => obj[key];
|
|
8
8
|
/** value 不为 null 或 undefined */
|
|
9
9
|
export const not_empty = (value) => value !== null && value !== undefined;
|
|
10
10
|
export const empty = (value) => value === undefined || value === null;
|
|
@@ -42,16 +42,6 @@ export const brackets = {
|
|
|
42
42
|
fat: ['【', '】'],
|
|
43
43
|
tortoise_shell: ['〔', '〕'],
|
|
44
44
|
};
|
|
45
|
-
function to_fp(str) {
|
|
46
|
-
if (!str)
|
|
47
|
-
return str;
|
|
48
|
-
const fp = str.replaceAll('\\', '/');
|
|
49
|
-
// 转换小写盘符开头的路径
|
|
50
|
-
return fp[1] === ':' && 'a' <= fp[0] && fp[0] <= 'z' ?
|
|
51
|
-
fp[0].toUpperCase() + fp.slice(1)
|
|
52
|
-
:
|
|
53
|
-
fp;
|
|
54
|
-
}
|
|
55
45
|
// ------------------------------------ String.prototype
|
|
56
46
|
Object.defineProperties(String.prototype, {
|
|
57
47
|
...to_getter_property_descriptors({
|
|
@@ -223,6 +213,7 @@ Object.defineProperties(String.prototype, {
|
|
|
223
213
|
return Object.fromEntries(Object.entries($placeholders)
|
|
224
214
|
.map(([name, $i]) => [name, matches[$i] || '']));
|
|
225
215
|
},
|
|
216
|
+
/** 查找子串或字符出现的次数 */
|
|
226
217
|
count(search) {
|
|
227
218
|
if (!search)
|
|
228
219
|
throw new Error('count 的 search 不能为空');
|
|
@@ -320,9 +311,9 @@ Object.defineProperties(String.prototype, {
|
|
|
320
311
|
.replace(/(["']+)\s*(.+?)\s*(["']+)/g, '$1$2$3')
|
|
321
312
|
.replace(new RegExp(cjk + '([\\+\\-\\*\\/=&\\\\\\|<>])([A-Za-z0-9])', 'g'), '$1 $2 $3')
|
|
322
313
|
.replace(new RegExp('([A-Za-z0-9])([\\+\\-\\*\\/=&\\\\\\|<>])' + cjk, 'g'), '$1 $2 $3');
|
|
323
|
-
const
|
|
314
|
+
const text_bak = text_;
|
|
324
315
|
text_ = text_.replace(new RegExp(cjk + '([\\(\\[\\{<\u201c]+(.*?)[\\)\\]\\}>\u201d]+)' + cjk, 'g'), '$1 $2 $4');
|
|
325
|
-
if (text_ ===
|
|
316
|
+
if (text_ === text_bak)
|
|
326
317
|
text_ = text_
|
|
327
318
|
.replace(new RegExp(cjk + '([\\(\\[\\{<\u201c>])', 'g'), '$1 $2')
|
|
328
319
|
.replace(new RegExp('([\\)\\]\\}>\u201d<])' + cjk, 'g'), '$1 $2');
|
|
@@ -331,7 +322,7 @@ Object.defineProperties(String.prototype, {
|
|
|
331
322
|
.replace(new RegExp(cjk + '([~!;:,\\.\\?\u2026])([A-Za-z0-9])', 'g'), '$1$2 $3')
|
|
332
323
|
.replace(new RegExp(cjk + '([A-Za-z0-9`\\$%\\^&\\*\\-=\\+\\\\\\|\\/@\u00a1-\u00ff\u2022\u2027\u2150-\u218f])', 'g'), '$1 $2')
|
|
333
324
|
.replace(new RegExp('([A-Za-z0-9`\\$%\\^&\\*\\-=\\+\\\\\\|\\/@\u00a1-\u00ff\u2022\u2027\u2150-\u218f])' + cjk, 'g'), '$1 $2');
|
|
334
|
-
}
|
|
325
|
+
}
|
|
335
326
|
}),
|
|
336
327
|
// ------------ 文件路径操作
|
|
337
328
|
...to_getter_property_descriptors({
|
|
@@ -339,30 +330,43 @@ Object.defineProperties(String.prototype, {
|
|
|
339
330
|
return this.endsWith('/');
|
|
340
331
|
},
|
|
341
332
|
fp() {
|
|
342
|
-
return to_fp(this);
|
|
343
|
-
},
|
|
344
|
-
fpd() {
|
|
345
333
|
if (!this)
|
|
346
334
|
return this;
|
|
347
|
-
const fp =
|
|
335
|
+
const fp = this.replaceAll('\\', '/');
|
|
336
|
+
// 转换小写盘符开头的路径
|
|
337
|
+
return fp[1] === ':' && 'a' <= fp[0] && fp[0] <= 'z'
|
|
338
|
+
? fp[0].toUpperCase() + fp.slice(1)
|
|
339
|
+
: fp;
|
|
340
|
+
},
|
|
341
|
+
fpd() {
|
|
342
|
+
const { fp } = this;
|
|
348
343
|
return fp.endsWith('/') ? fp : `${fp}/`;
|
|
349
344
|
},
|
|
350
345
|
fdir() {
|
|
351
|
-
|
|
352
|
-
return this.slice(0, this.length - (fname.length + (this.endsWith('/') ? 1 : 0)));
|
|
346
|
+
return this.strip_end(this.fname);
|
|
353
347
|
},
|
|
354
348
|
fname() {
|
|
355
|
-
const
|
|
356
|
-
if (
|
|
357
|
-
return
|
|
358
|
-
|
|
359
|
-
|
|
349
|
+
const ilast = this.lastIndexOf('/');
|
|
350
|
+
if (ilast === -1)
|
|
351
|
+
return this; // 没有斜杠时返回整个字符串
|
|
352
|
+
// 以斜杠结尾的情况
|
|
353
|
+
if (ilast === this.length - 1) {
|
|
354
|
+
const iprev = this.lastIndexOf('/', ilast - 1);
|
|
355
|
+
return iprev === -1
|
|
356
|
+
? this // 只有一个斜杠且在末尾
|
|
357
|
+
: this.slice(iprev + 1);
|
|
358
|
+
}
|
|
359
|
+
// 返回最后一个斜杠后的内容
|
|
360
|
+
return this.slice(ilast + 1);
|
|
360
361
|
},
|
|
361
362
|
fext() {
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
363
|
+
const { fname } = this;
|
|
364
|
+
const index = fname.lastIndexOf('.');
|
|
365
|
+
return index <= 0
|
|
366
|
+
? ''
|
|
367
|
+
: fname.slice(index + 1);
|
|
368
|
+
}
|
|
369
|
+
})
|
|
366
370
|
});
|
|
367
371
|
// ------------------------------------ Date.prototype
|
|
368
372
|
Object.defineProperties(Date.prototype, to_method_property_descriptors({
|
|
@@ -418,10 +422,9 @@ function get_time_str(date, hour, ms, splitter) {
|
|
|
418
422
|
return String(hour).padStart(2, '0') + splitter +
|
|
419
423
|
String(date.getMinutes()).padStart(2, '0') + splitter +
|
|
420
424
|
String(date.getSeconds()).padStart(2, '0') +
|
|
421
|
-
(ms
|
|
422
|
-
'.' + String(date.getMilliseconds()).padStart(3, '0')
|
|
423
|
-
:
|
|
424
|
-
'');
|
|
425
|
+
(ms
|
|
426
|
+
? '.' + String(date.getMilliseconds()).padStart(3, '0')
|
|
427
|
+
: '');
|
|
425
428
|
}
|
|
426
429
|
// ------------------------------------ Number.prototype
|
|
427
430
|
Object.defineProperties(Number.prototype, to_method_property_descriptors({
|
|
@@ -473,27 +476,27 @@ Object.defineProperties(Array.prototype, {
|
|
|
473
476
|
const indent = character.repeat(width);
|
|
474
477
|
return this.map(line => indent + line);
|
|
475
478
|
},
|
|
476
|
-
sum(
|
|
479
|
+
sum(mapper) {
|
|
477
480
|
if (!this.length)
|
|
478
481
|
return undefined;
|
|
479
482
|
// 快捷路径
|
|
480
483
|
const first = this[0];
|
|
481
|
-
if ((typeof first === 'number' || typeof first === 'bigint') && !
|
|
484
|
+
if ((typeof first === 'number' || typeof first === 'bigint') && !mapper)
|
|
482
485
|
return this.reduce((acc, x) => acc + x, first);
|
|
483
|
-
if (is_key_type(
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
return this.reduce((acc, x) => acc +
|
|
486
|
+
if (is_key_type(mapper))
|
|
487
|
+
mapper = build_mapper(mapper);
|
|
488
|
+
mapper ??= ident;
|
|
489
|
+
return this.reduce((acc, x) => acc + mapper(x), mapper(first));
|
|
487
490
|
},
|
|
488
|
-
max(
|
|
491
|
+
max(mapper = ident) {
|
|
489
492
|
if (!this.length)
|
|
490
493
|
return undefined;
|
|
491
|
-
if (
|
|
492
|
-
|
|
493
|
-
let max =
|
|
494
|
+
if (is_key_type(mapper))
|
|
495
|
+
mapper = build_mapper(mapper);
|
|
496
|
+
let max = mapper(this[0]);
|
|
494
497
|
let imax = 0;
|
|
495
498
|
for (let i = 0; i < this.length; i++) {
|
|
496
|
-
const value =
|
|
499
|
+
const value = mapper(this[i]);
|
|
497
500
|
if (value > max) {
|
|
498
501
|
max = value;
|
|
499
502
|
imax = i;
|
|
@@ -501,15 +504,15 @@ Object.defineProperties(Array.prototype, {
|
|
|
501
504
|
}
|
|
502
505
|
return this[imax];
|
|
503
506
|
},
|
|
504
|
-
min(
|
|
507
|
+
min(mapper = ident) {
|
|
505
508
|
if (!this.length)
|
|
506
509
|
return undefined;
|
|
507
|
-
if (
|
|
508
|
-
|
|
509
|
-
let min =
|
|
510
|
+
if (is_key_type(mapper))
|
|
511
|
+
mapper = build_mapper(mapper);
|
|
512
|
+
let min = mapper(this[0]);
|
|
510
513
|
let imin = 0;
|
|
511
514
|
for (let i = 0; i < this.length; i++) {
|
|
512
|
-
const value =
|
|
515
|
+
const value = mapper(this[i]);
|
|
513
516
|
if (value < min) {
|
|
514
517
|
min = value;
|
|
515
518
|
imin = i;
|
|
@@ -517,14 +520,14 @@ Object.defineProperties(Array.prototype, {
|
|
|
517
520
|
}
|
|
518
521
|
return this[imin];
|
|
519
522
|
},
|
|
520
|
-
unique(
|
|
521
|
-
if (!
|
|
523
|
+
unique(mapper) {
|
|
524
|
+
if (!mapper)
|
|
522
525
|
return [...new Set(this)];
|
|
523
|
-
if (is_key_type(
|
|
524
|
-
|
|
526
|
+
if (is_key_type(mapper))
|
|
527
|
+
mapper = build_mapper(mapper);
|
|
525
528
|
let map = new Map();
|
|
526
529
|
for (const x of this)
|
|
527
|
-
map.set(
|
|
530
|
+
map.set(mapper(x), x);
|
|
528
531
|
return [...map.values()];
|
|
529
532
|
},
|
|
530
533
|
join_lines(append = true) {
|