xshell 1.1.6 → 1.1.7
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/builder.js +2 -1
- package/package.json +6 -6
- package/path.js +3 -4
- package/process.d.ts +0 -4
- package/process.js +0 -4
- package/prototype.browser.d.ts +18 -0
- package/prototype.browser.js +57 -2
- package/prototype.d.ts +18 -0
- package/prototype.js +57 -2
- package/utils.browser.d.ts +3 -5
- package/utils.browser.js +5 -6
- package/utils.d.ts +4 -8
- package/utils.js +13 -16
package/builder.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { fileURLToPath } from 'url';
|
|
2
|
+
import { not_empty } from "./prototype.js";
|
|
2
3
|
import { noprint } from "./process.js";
|
|
3
|
-
import { Lock, check, filter_values
|
|
4
|
+
import { Lock, check, filter_values } from "./utils.js";
|
|
4
5
|
import { fcopy, fmkdir, fwrite } from "./file.js";
|
|
5
6
|
import { path } from "./path.js";
|
|
6
7
|
const monaco_files = [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xshell",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"bin": {
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"commander": "^12.1.0",
|
|
76
76
|
"css-loader": "^7.1.2",
|
|
77
77
|
"emoji-regex": "^10.4.0",
|
|
78
|
-
"eslint": "^9.
|
|
78
|
+
"eslint": "^9.17.0",
|
|
79
79
|
"eslint-plugin-import": "^2.31.0",
|
|
80
80
|
"eslint-plugin-react": "^7.37.2",
|
|
81
81
|
"gulp-sort": "^2.0.0",
|
|
@@ -91,10 +91,10 @@
|
|
|
91
91
|
"mime-types": "^2.1.35",
|
|
92
92
|
"ora": "^8.1.1",
|
|
93
93
|
"react": "^19.0.0",
|
|
94
|
-
"react-i18next": "^15.
|
|
94
|
+
"react-i18next": "^15.2.0",
|
|
95
95
|
"react-object-model": "^1.2.20",
|
|
96
96
|
"resolve-path": "^1.4.0",
|
|
97
|
-
"sass": "^1.
|
|
97
|
+
"sass": "^1.83.0",
|
|
98
98
|
"sass-loader": "^16.0.4",
|
|
99
99
|
"source-map-loader": "^5.0.0",
|
|
100
100
|
"strip-ansi": "^7.1.0",
|
|
@@ -126,13 +126,13 @@
|
|
|
126
126
|
"@types/koa-compress": "^4.0.6",
|
|
127
127
|
"@types/lodash": "^4.17.13",
|
|
128
128
|
"@types/mime-types": "^2.1.4",
|
|
129
|
-
"@types/node": "^22.10.
|
|
129
|
+
"@types/node": "^22.10.2",
|
|
130
130
|
"@types/react": "^19.0.1",
|
|
131
131
|
"@types/through2": "^2.0.41",
|
|
132
132
|
"@types/tough-cookie": "^4.0.5",
|
|
133
133
|
"@types/ua-parser-js": "^0.7.39",
|
|
134
134
|
"@types/vinyl-fs": "^3.0.5",
|
|
135
|
-
"@types/vscode": "^1.
|
|
135
|
+
"@types/vscode": "^1.96.0",
|
|
136
136
|
"@types/webpack-bundle-analyzer": "^4.7.0"
|
|
137
137
|
},
|
|
138
138
|
"pnpm": {
|
package/path.js
CHANGED
|
@@ -4,10 +4,9 @@ export function to_fp(str) {
|
|
|
4
4
|
return str;
|
|
5
5
|
const fp = str.replaceAll('\\', '/');
|
|
6
6
|
// 转换小写盘符开头的路径
|
|
7
|
-
return fp[1] === ':' && 'a' <= fp[0] && fp[0] <= 'z'
|
|
8
|
-
fp[0].toUpperCase() + fp.slice(1)
|
|
9
|
-
:
|
|
10
|
-
fp;
|
|
7
|
+
return fp[1] === ':' && 'a' <= fp[0] && fp[0] <= 'z'
|
|
8
|
+
? fp[0].toUpperCase() + fp.slice(1)
|
|
9
|
+
: fp;
|
|
11
10
|
}
|
|
12
11
|
/** Normalize a string path, reducing '..' and '.' parts.
|
|
13
12
|
When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved.
|
package/process.d.ts
CHANGED
|
@@ -67,7 +67,6 @@ export interface StartOptions extends BaseOptions {
|
|
|
67
67
|
- envs?: `process.env` 覆盖/添加到 process.env 的环境变量,传 null 时可以取消设置该变量
|
|
68
68
|
- encoding?: `'utf-8'` 子进程输出编码
|
|
69
69
|
- print?: `true` 是否打印启动命令行
|
|
70
|
-
- stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理
|
|
71
70
|
- input?: string, 启动子进程之后写入到子进程 stdin 中的内容,写完后关闭子进程 stdin (pty 不关闭)
|
|
72
71
|
- fp_stdin?: 使用文件作为标准输入,设置 stdio 中对应的值
|
|
73
72
|
- fp_stdout?: 使用文件作为标准输出,设置 stdio 中对应的值
|
|
@@ -151,10 +150,7 @@ export interface StartNodeJsOptions extends StartOptions {
|
|
|
151
150
|
- options
|
|
152
151
|
- cwd?: `'T:/'`
|
|
153
152
|
- envs?: `process.env` 覆盖/添加到 process.env 的环境变量
|
|
154
|
-
- encoding?: `'utf-8'` 子进程输出编码
|
|
155
153
|
- print?: `true` print 选项,支持设置细项
|
|
156
|
-
- stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理
|
|
157
|
-
- detached?: `false` 是否断开和 child 的关系 (ignore stdio, unref)
|
|
158
154
|
- inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
|
|
159
155
|
- break?: break at first line */
|
|
160
156
|
export declare function start_nodejs(js: string, args?: string[], { inspect, break: _break, ...options }?: StartNodeJsOptions): Promise<ChildProcess>;
|
package/process.js
CHANGED
|
@@ -110,7 +110,6 @@ stdio }) {
|
|
|
110
110
|
- envs?: `process.env` 覆盖/添加到 process.env 的环境变量,传 null 时可以取消设置该变量
|
|
111
111
|
- encoding?: `'utf-8'` 子进程输出编码
|
|
112
112
|
- print?: `true` 是否打印启动命令行
|
|
113
|
-
- stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理
|
|
114
113
|
- input?: string, 启动子进程之后写入到子进程 stdin 中的内容,写完后关闭子进程 stdin (pty 不关闭)
|
|
115
114
|
- fp_stdin?: 使用文件作为标准输入,设置 stdio 中对应的值
|
|
116
115
|
- fp_stdout?: 使用文件作为标准输出,设置 stdio 中对应的值
|
|
@@ -248,10 +247,7 @@ export async function call_nodejs(js, args = [], { inspect, break: _break, ...op
|
|
|
248
247
|
- options
|
|
249
248
|
- cwd?: `'T:/'`
|
|
250
249
|
- envs?: `process.env` 覆盖/添加到 process.env 的环境变量
|
|
251
|
-
- encoding?: `'utf-8'` 子进程输出编码
|
|
252
250
|
- print?: `true` print 选项,支持设置细项
|
|
253
|
-
- stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理
|
|
254
|
-
- detached?: `false` 是否断开和 child 的关系 (ignore stdio, unref)
|
|
255
251
|
- inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
|
|
256
252
|
- break?: break at first line */
|
|
257
253
|
export async function start_nodejs(js, args = [], { inspect, break: _break, ...options } = {}) {
|
package/prototype.browser.d.ts
CHANGED
|
@@ -146,6 +146,15 @@ declare global {
|
|
|
146
146
|
/** 等价于 .at(-1) */
|
|
147
147
|
last: T;
|
|
148
148
|
indent(this: string[], width?: number, c?: string): string[];
|
|
149
|
+
/** 对数组中所有元素求和 (+), 返回结果 */
|
|
150
|
+
sum(this: T[]): T;
|
|
151
|
+
/** 查找数组中最大的元素,可传入 selector 选择某个属性,或者计算出某个值,用作大小比较 */
|
|
152
|
+
max(this: T[], selector?: keyof T | KeySelector<T>): T;
|
|
153
|
+
/** 查找数组中最小的元素,可传入 selector 选择某个属性,或者计算出某个值,用作大小比较 */
|
|
154
|
+
min(this: T[], selector?: keyof T | KeySelector<T>): T;
|
|
155
|
+
/** 去除重复元素(可按 selector 去重),重复值保留最后出现的那个
|
|
156
|
+
- selector?: 可以是 key (string, number, symbol) 或 (obj: any) => any */
|
|
157
|
+
unique(this: T[], selector?: keyof T | KeySelector<T>): T[];
|
|
149
158
|
/**
|
|
150
159
|
- trim_line?: `true`
|
|
151
160
|
- rm_empty_lines?: `true`
|
|
@@ -174,6 +183,15 @@ interface SliceOptions {
|
|
|
174
183
|
last?: boolean;
|
|
175
184
|
}
|
|
176
185
|
export declare const emoji_regex: RegExp;
|
|
186
|
+
export declare const noop: () => void;
|
|
187
|
+
export declare const ident: <T>(x: T) => T;
|
|
188
|
+
export declare const build_selector: <TObj>(key: keyof TObj) => (obj: TObj) => TObj[keyof TObj];
|
|
189
|
+
export type KeySelector<TObj = any, TKey extends keyof TObj = keyof TObj> = (key: TObj) => TObj[TKey];
|
|
190
|
+
/** value 不为 null 或 undefined */
|
|
191
|
+
export declare const not_empty: (value: any) => boolean;
|
|
192
|
+
export declare const empty: (value: any) => boolean;
|
|
193
|
+
export declare const is_key_type: IsKeyType;
|
|
194
|
+
type IsKeyType = (key: any) => key is string | number | symbol;
|
|
177
195
|
export declare function to_method_property_descriptors(methods: {
|
|
178
196
|
[name: string]: Function;
|
|
179
197
|
}): PropertyDescriptorMap;
|
package/prototype.browser.js
CHANGED
|
@@ -3,6 +3,14 @@ import byte_size from 'byte-size';
|
|
|
3
3
|
import EmojiRegex from 'emoji-regex';
|
|
4
4
|
import { t } from "./i18n/instance.js";
|
|
5
5
|
export const emoji_regex = EmojiRegex();
|
|
6
|
+
export const noop = () => { };
|
|
7
|
+
export const ident = (x) => x;
|
|
8
|
+
export const build_selector = (key) => (obj) => obj[key];
|
|
9
|
+
/** value 不为 null 或 undefined */
|
|
10
|
+
export const not_empty = (value) => value !== null && value !== undefined;
|
|
11
|
+
export const empty = (value) => value === undefined || value === null;
|
|
12
|
+
const key_types = ['string', 'number', 'symbol'];
|
|
13
|
+
export const is_key_type = ((key) => key_types.includes(typeof key));
|
|
6
14
|
export function to_method_property_descriptors(methods) {
|
|
7
15
|
return Object.fromEntries(Object.entries(methods)
|
|
8
16
|
.map(([name, value]) => ([name, {
|
|
@@ -444,10 +452,10 @@ Object.defineProperties(Array.prototype, {
|
|
|
444
452
|
if (trim_line)
|
|
445
453
|
lines = lines.map(line => line.trim());
|
|
446
454
|
if (rm_empty_lines)
|
|
447
|
-
return lines.filter(
|
|
455
|
+
return lines.filter(Boolean);
|
|
448
456
|
if (rm_last_empty_lines) {
|
|
449
457
|
lines.reverse();
|
|
450
|
-
const i_not_empty = lines.findIndex(
|
|
458
|
+
const i_not_empty = lines.findIndex(Boolean);
|
|
451
459
|
if (i_not_empty !== -1)
|
|
452
460
|
lines = lines.slice(i_not_empty);
|
|
453
461
|
lines.reverse();
|
|
@@ -459,6 +467,53 @@ Object.defineProperties(Array.prototype, {
|
|
|
459
467
|
const indent = character.repeat(width);
|
|
460
468
|
return this.map(line => indent + line);
|
|
461
469
|
},
|
|
470
|
+
sum() {
|
|
471
|
+
return this.length
|
|
472
|
+
? this.reduce((acc, x) => acc + x)
|
|
473
|
+
: undefined;
|
|
474
|
+
},
|
|
475
|
+
max(selector = ident) {
|
|
476
|
+
if (!this.length)
|
|
477
|
+
return undefined;
|
|
478
|
+
if (typeof selector === 'string')
|
|
479
|
+
selector = build_selector(selector);
|
|
480
|
+
let max = selector(this[0]);
|
|
481
|
+
let imax = 0;
|
|
482
|
+
for (let i = 0; i < this.length; i++) {
|
|
483
|
+
const value = selector(this[i]);
|
|
484
|
+
if (value > max) {
|
|
485
|
+
max = value;
|
|
486
|
+
imax = i;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return this[imax];
|
|
490
|
+
},
|
|
491
|
+
min(selector = ident) {
|
|
492
|
+
if (!this.length)
|
|
493
|
+
return undefined;
|
|
494
|
+
if (typeof selector === 'string')
|
|
495
|
+
selector = build_selector(selector);
|
|
496
|
+
let min = selector(this[0]);
|
|
497
|
+
let imin = 0;
|
|
498
|
+
for (let i = 0; i < this.length; i++) {
|
|
499
|
+
const value = selector(this[i]);
|
|
500
|
+
if (value < min) {
|
|
501
|
+
min = value;
|
|
502
|
+
imin = i;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return this[imin];
|
|
506
|
+
},
|
|
507
|
+
unique(selector) {
|
|
508
|
+
if (!selector)
|
|
509
|
+
return [...new Set(this)];
|
|
510
|
+
if (is_key_type(selector))
|
|
511
|
+
selector = build_selector(selector);
|
|
512
|
+
let map = new Map();
|
|
513
|
+
for (const x of this)
|
|
514
|
+
map.set(selector(x), x);
|
|
515
|
+
return [...map.values()];
|
|
516
|
+
},
|
|
462
517
|
join_lines(append = true) {
|
|
463
518
|
return `${this.join('\n')}${append ? '\n' : ''}`;
|
|
464
519
|
}
|
package/prototype.d.ts
CHANGED
|
@@ -171,6 +171,15 @@ declare global {
|
|
|
171
171
|
log(this: string[], limit?: number): void;
|
|
172
172
|
indent(this: string[], width?: number, c?: string): string[];
|
|
173
173
|
indent2to4(this: string[]): string[];
|
|
174
|
+
/** 对数组中所有元素求和 (+), 返回结果 */
|
|
175
|
+
sum(this: T[]): T;
|
|
176
|
+
/** 查找数组中最大的元素,可传入 selector 选择某个属性,或者计算出某个值,用作大小比较 */
|
|
177
|
+
max(this: T[], selector?: keyof T | KeySelector<T>): T;
|
|
178
|
+
/** 查找数组中最小的元素,可传入 selector 选择某个属性,或者计算出某个值,用作大小比较 */
|
|
179
|
+
min(this: T[], selector?: keyof T | KeySelector<T>): T;
|
|
180
|
+
/** 去除重复元素(可按 selector 去重),重复值保留最后出现的那个
|
|
181
|
+
- selector?: 可以是 key (string, number, symbol) 或 (obj: any) => any */
|
|
182
|
+
unique(this: T[], selector?: keyof T | KeySelector<T>): T[];
|
|
174
183
|
/**
|
|
175
184
|
- trim_line?: `true`
|
|
176
185
|
- rm_empty_lines?: `true`
|
|
@@ -206,6 +215,15 @@ interface SliceOptions {
|
|
|
206
215
|
import chalk from 'chalk';
|
|
207
216
|
export declare const emoji_regex: RegExp;
|
|
208
217
|
export { chalk };
|
|
218
|
+
export declare const noop: () => void;
|
|
219
|
+
export declare const ident: <T>(x: T) => T;
|
|
220
|
+
export declare const build_selector: <TObj>(key: keyof TObj) => (obj: TObj) => TObj[keyof TObj];
|
|
221
|
+
export type KeySelector<TObj = any, TKey extends keyof TObj = keyof TObj> = (key: TObj) => TObj[TKey];
|
|
222
|
+
/** value 不为 null 或 undefined */
|
|
223
|
+
export declare const not_empty: (value: any) => boolean;
|
|
224
|
+
export declare const empty: (value: any) => boolean;
|
|
225
|
+
export declare const is_key_type: IsKeyType;
|
|
226
|
+
type IsKeyType = (key: any) => key is string | number | symbol;
|
|
209
227
|
export declare function to_method_property_descriptors(methods: {
|
|
210
228
|
[name: string]: Function;
|
|
211
229
|
}): PropertyDescriptorMap;
|
package/prototype.js
CHANGED
|
@@ -7,6 +7,14 @@ import { t } from "./i18n/instance.js";
|
|
|
7
7
|
chalk.level = 2;
|
|
8
8
|
export const emoji_regex = EmojiRegex();
|
|
9
9
|
export { chalk };
|
|
10
|
+
export const noop = () => { };
|
|
11
|
+
export const ident = (x) => x;
|
|
12
|
+
export const build_selector = (key) => (obj) => obj[key];
|
|
13
|
+
/** value 不为 null 或 undefined */
|
|
14
|
+
export const not_empty = (value) => value !== null && value !== undefined;
|
|
15
|
+
export const empty = (value) => value === undefined || value === null;
|
|
16
|
+
const key_types = ['string', 'number', 'symbol'];
|
|
17
|
+
export const is_key_type = ((key) => key_types.includes(typeof key));
|
|
10
18
|
export function to_method_property_descriptors(methods) {
|
|
11
19
|
return Object.fromEntries(Object.entries(methods)
|
|
12
20
|
.map(([name, value]) => ([name, {
|
|
@@ -482,10 +490,10 @@ if (!globalThis.my_prototype_defined) {
|
|
|
482
490
|
if (trim_line)
|
|
483
491
|
lines = lines.map(line => line.trim());
|
|
484
492
|
if (rm_empty_lines)
|
|
485
|
-
return lines.filter(
|
|
493
|
+
return lines.filter(Boolean);
|
|
486
494
|
if (rm_last_empty_lines) {
|
|
487
495
|
lines.reverse();
|
|
488
|
-
const i_not_empty = lines.findIndex(
|
|
496
|
+
const i_not_empty = lines.findIndex(Boolean);
|
|
489
497
|
if (i_not_empty !== -1)
|
|
490
498
|
lines = lines.slice(i_not_empty);
|
|
491
499
|
lines.reverse();
|
|
@@ -512,6 +520,53 @@ if (!globalThis.my_prototype_defined) {
|
|
|
512
520
|
return this.split_indents()
|
|
513
521
|
.map(line => ' '.repeat(line.indent * 2) + line.text);
|
|
514
522
|
},
|
|
523
|
+
sum() {
|
|
524
|
+
return this.length
|
|
525
|
+
? this.reduce((acc, x) => acc + x)
|
|
526
|
+
: undefined;
|
|
527
|
+
},
|
|
528
|
+
max(selector = ident) {
|
|
529
|
+
if (!this.length)
|
|
530
|
+
return undefined;
|
|
531
|
+
if (is_key_type(selector))
|
|
532
|
+
selector = build_selector(selector);
|
|
533
|
+
let max = selector(this[0]);
|
|
534
|
+
let imax = 0;
|
|
535
|
+
for (let i = 0; i < this.length; i++) {
|
|
536
|
+
const value = selector(this[i]);
|
|
537
|
+
if (value > max) {
|
|
538
|
+
max = value;
|
|
539
|
+
imax = i;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return this[imax];
|
|
543
|
+
},
|
|
544
|
+
min(selector = ident) {
|
|
545
|
+
if (!this.length)
|
|
546
|
+
return undefined;
|
|
547
|
+
if (is_key_type(selector))
|
|
548
|
+
selector = build_selector(selector);
|
|
549
|
+
let min = selector(this[0]);
|
|
550
|
+
let imin = 0;
|
|
551
|
+
for (let i = 0; i < this.length; i++) {
|
|
552
|
+
const value = selector(this[i]);
|
|
553
|
+
if (value < min) {
|
|
554
|
+
min = value;
|
|
555
|
+
imin = i;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return this[imin];
|
|
559
|
+
},
|
|
560
|
+
unique(selector) {
|
|
561
|
+
if (!selector)
|
|
562
|
+
return [...new Set(this)];
|
|
563
|
+
if (is_key_type(selector))
|
|
564
|
+
selector = build_selector(selector);
|
|
565
|
+
let map = new Map();
|
|
566
|
+
for (const x of this)
|
|
567
|
+
map.set(selector(x), x);
|
|
568
|
+
return [...map.values()];
|
|
569
|
+
},
|
|
515
570
|
join_lines(append = true) {
|
|
516
571
|
return `${this.join('\n')}${append ? '\n' : ''}`;
|
|
517
572
|
}
|
package/utils.browser.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
/** value 不为 null 或 undefined */
|
|
3
|
-
export declare const not_empty: (value: any) => boolean;
|
|
1
|
+
import { type KeySelector } from './prototype.browser.ts';
|
|
4
2
|
export declare function assert(assertion: any, message?: string): never | void;
|
|
5
3
|
/** 做参数校验,逻辑检查 */
|
|
6
4
|
export declare function check(condition: any, message?: string): never | void;
|
|
@@ -11,8 +9,8 @@ export declare function check(condition: any, message?: string): never | void;
|
|
|
11
9
|
export declare function log<TObj>(obj: TObj): TObj;
|
|
12
10
|
export declare function log<TObj>(label: string, obj: TObj): TObj;
|
|
13
11
|
/** 数组或 iterable 去重(可按 selector 去重),重复值保留最后出现的那个
|
|
14
|
-
- selector?: 可以是 key (string) 或 (obj: any) => any */
|
|
15
|
-
export declare function unique<TObj>(iterable: TObj[] | Iterable<TObj>, selector?:
|
|
12
|
+
- selector?: 可以是 key (string, number, symbol) 或 (obj: any) => any */
|
|
13
|
+
export declare function unique<TObj>(iterable: TObj[] | Iterable<TObj>, selector?: keyof TObj | KeySelector<TObj>): TObj[];
|
|
16
14
|
/** 生成 0, 1, ..., n - 1 (不包括 n) 的数组,支持传入 generator 函数,通过 index 生成各个元素
|
|
17
15
|
@example seq(10, i => `item-${i}`) */
|
|
18
16
|
export declare function seq<T = number>(n: number, generator?: (index: number) => T): T[];
|
package/utils.browser.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
+
import { is_key_type, build_selector, not_empty } from "./prototype.browser.js";
|
|
1
2
|
import { t } from "./i18n/instance.js";
|
|
2
|
-
export const noop = () => { };
|
|
3
|
-
/** value 不为 null 或 undefined */
|
|
4
|
-
export const not_empty = (value) => value !== null && value !== undefined;
|
|
5
3
|
export function assert(assertion, message) {
|
|
6
4
|
if (!assertion) {
|
|
7
5
|
debugger;
|
|
@@ -28,14 +26,15 @@ export function log(...args) {
|
|
|
28
26
|
}
|
|
29
27
|
}
|
|
30
28
|
/** 数组或 iterable 去重(可按 selector 去重),重复值保留最后出现的那个
|
|
31
|
-
- selector?: 可以是 key (string) 或 (obj: any) => any */
|
|
29
|
+
- selector?: 可以是 key (string, number, symbol) 或 (obj: any) => any */
|
|
32
30
|
export function unique(iterable, selector) {
|
|
33
31
|
if (!selector)
|
|
34
32
|
return [...new Set(iterable)];
|
|
33
|
+
if (is_key_type(selector))
|
|
34
|
+
selector = build_selector(selector);
|
|
35
35
|
let map = new Map();
|
|
36
|
-
const is_str_selector = typeof selector === 'string';
|
|
37
36
|
for (const x of iterable)
|
|
38
|
-
map.set(
|
|
37
|
+
map.set(selector(x), x);
|
|
39
38
|
return [...map.values()];
|
|
40
39
|
}
|
|
41
40
|
/** 生成 0, 1, ..., n - 1 (不包括 n) 的数组,支持传入 generator 函数,通过 index 生成各个元素
|
package/utils.d.ts
CHANGED
|
@@ -2,10 +2,7 @@ import { Writable, Transform, type Readable, type Duplex, type TransformCallback
|
|
|
2
2
|
import util from 'util';
|
|
3
3
|
import type { TimerOptions } from 'timers';
|
|
4
4
|
import type Vinyl from 'vinyl';
|
|
5
|
-
import './prototype.ts';
|
|
6
|
-
export declare const noop: () => void;
|
|
7
|
-
/** value 不为 null 或 undefined */
|
|
8
|
-
export declare const not_empty: (value: any) => boolean;
|
|
5
|
+
import { type KeySelector } from './prototype.ts';
|
|
9
6
|
/** `230` term 字符宽度 (实际上有 240) */
|
|
10
7
|
export declare const output_width = 230;
|
|
11
8
|
export declare function set_inspect_options(colors?: boolean): void;
|
|
@@ -18,13 +15,12 @@ export declare function check(condition: any, message?: string): never | void;
|
|
|
18
15
|
log(obj) */
|
|
19
16
|
export declare function log<TObj>(obj: TObj): TObj;
|
|
20
17
|
export declare function log<TObj>(label: string, obj: TObj): TObj;
|
|
18
|
+
/** 数组或 iterable 去重(可按 selector 去重),重复值保留最后出现的那个
|
|
19
|
+
- selector?: 可以是 key (string, number, symbol) 或 (obj: any) => any */
|
|
20
|
+
export declare function unique<TObj>(iterable: TObj[] | Iterable<TObj>, selector?: keyof TObj | KeySelector<TObj>): TObj[];
|
|
21
21
|
/** 生成 0, 1, ..., n - 1 (不包括 n) 的数组,支持传入 generator 函数,通过 index 生成各个元素
|
|
22
22
|
@example seq(10, i => `item-${i}`) */
|
|
23
23
|
export declare function seq<T = number>(n: number, generator?: (index: number) => T): T[];
|
|
24
|
-
/** 数组或 iterable 去重(可按 selector 去重)
|
|
25
|
-
- selector?: 可以是 key (string) 或 (obj: any) => any
|
|
26
|
-
*/
|
|
27
|
-
export declare function unique<T>(iterable: T[] | Iterable<T>, selector?: string | ((obj: T) => any)): any[];
|
|
28
24
|
/** 排序对象中 keys 的顺序,返回新的对象 */
|
|
29
25
|
export declare function sort_keys<TObj>(obj: TObj): TObj;
|
|
30
26
|
/** 将 keys, values 数组按对应的顺序组合成一个对象 */
|
package/utils.js
CHANGED
|
@@ -2,10 +2,7 @@ import { Stream, Writable, Transform } from 'stream';
|
|
|
2
2
|
import util from 'util';
|
|
3
3
|
import timers from 'timers/promises';
|
|
4
4
|
import { t } from "./i18n/instance.js";
|
|
5
|
-
import "./prototype.js";
|
|
6
|
-
export const noop = () => { };
|
|
7
|
-
/** value 不为 null 或 undefined */
|
|
8
|
-
export const not_empty = (value) => value !== null && value !== undefined;
|
|
5
|
+
import { build_selector, not_empty, is_key_type, noop } from "./prototype.js";
|
|
9
6
|
/** `230` term 字符宽度 (实际上有 240) */
|
|
10
7
|
export const output_width = 230;
|
|
11
8
|
export function set_inspect_options(colors = true) {
|
|
@@ -49,6 +46,18 @@ export function log(...args) {
|
|
|
49
46
|
return obj;
|
|
50
47
|
}
|
|
51
48
|
}
|
|
49
|
+
/** 数组或 iterable 去重(可按 selector 去重),重复值保留最后出现的那个
|
|
50
|
+
- selector?: 可以是 key (string, number, symbol) 或 (obj: any) => any */
|
|
51
|
+
export function unique(iterable, selector) {
|
|
52
|
+
if (!selector)
|
|
53
|
+
return [...new Set(iterable)];
|
|
54
|
+
if (is_key_type(selector))
|
|
55
|
+
selector = build_selector(selector);
|
|
56
|
+
let map = new Map();
|
|
57
|
+
for (const x of iterable)
|
|
58
|
+
map.set(selector(x), x);
|
|
59
|
+
return [...map.values()];
|
|
60
|
+
}
|
|
52
61
|
/** 生成 0, 1, ..., n - 1 (不包括 n) 的数组,支持传入 generator 函数,通过 index 生成各个元素
|
|
53
62
|
@example seq(10, i => `item-${i}`) */
|
|
54
63
|
export function seq(n, generator) {
|
|
@@ -57,18 +66,6 @@ export function seq(n, generator) {
|
|
|
57
66
|
a[i] = generator ? generator(i) : i;
|
|
58
67
|
return a;
|
|
59
68
|
}
|
|
60
|
-
/** 数组或 iterable 去重(可按 selector 去重)
|
|
61
|
-
- selector?: 可以是 key (string) 或 (obj: any) => any
|
|
62
|
-
*/
|
|
63
|
-
export function unique(iterable, selector) {
|
|
64
|
-
if (!selector)
|
|
65
|
-
return [...new Set(iterable)];
|
|
66
|
-
let map = new Map();
|
|
67
|
-
const is_str_selector = typeof selector === 'string';
|
|
68
|
-
for (const x of iterable)
|
|
69
|
-
map.set(is_str_selector ? x[selector] : selector(x), x);
|
|
70
|
-
return [...map.values()];
|
|
71
|
-
}
|
|
72
69
|
/** 排序对象中 keys 的顺序,返回新的对象 */
|
|
73
70
|
export function sort_keys(obj) {
|
|
74
71
|
return Object.fromEntries(Object.entries(obj)
|