xshell 1.1.8 → 1.1.10
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/antd.sass +43 -0
- package/file.js +7 -2
- package/i18n/dict.json +3 -0
- package/package.json +8 -11
- 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 +35 -23
- package/prototype.browser.js +89 -57
- package/prototype.d.ts +35 -24
- package/prototype.js +99 -54
- package/server.d.ts +14 -15
- package/server.js +17 -15
- 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/patches/@types__byte-size@8.1.2.patch +0 -14
package/prototype.browser.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/** 在浏览器端修改 prototype,需要更加小心 */
|
|
2
|
-
import byte_size from 'byte-size';
|
|
3
2
|
import EmojiRegex from 'emoji-regex';
|
|
4
3
|
import { t } from "./i18n/instance.js";
|
|
5
4
|
export const emoji_regex = EmojiRegex();
|
|
6
5
|
export const noop = () => { };
|
|
7
6
|
export const ident = (x) => x;
|
|
8
|
-
export const
|
|
7
|
+
export const build_mapper = (key) => (obj) => obj[key];
|
|
9
8
|
/** value 不为 null 或 undefined */
|
|
10
9
|
export const not_empty = (value) => value !== null && value !== undefined;
|
|
11
10
|
export const empty = (value) => value === undefined || value === null;
|
|
@@ -43,16 +42,6 @@ export const brackets = {
|
|
|
43
42
|
fat: ['【', '】'],
|
|
44
43
|
tortoise_shell: ['〔', '〕'],
|
|
45
44
|
};
|
|
46
|
-
function to_fp(str) {
|
|
47
|
-
if (!str)
|
|
48
|
-
return str;
|
|
49
|
-
const fp = str.replaceAll('\\', '/');
|
|
50
|
-
// 转换小写盘符开头的路径
|
|
51
|
-
return fp[1] === ':' && 'a' <= fp[0] && fp[0] <= 'z' ?
|
|
52
|
-
fp[0].toUpperCase() + fp.slice(1)
|
|
53
|
-
:
|
|
54
|
-
fp;
|
|
55
|
-
}
|
|
56
45
|
// ------------------------------------ String.prototype
|
|
57
46
|
Object.defineProperties(String.prototype, {
|
|
58
47
|
...to_getter_property_descriptors({
|
|
@@ -224,6 +213,15 @@ Object.defineProperties(String.prototype, {
|
|
|
224
213
|
return Object.fromEntries(Object.entries($placeholders)
|
|
225
214
|
.map(([name, $i]) => [name, matches[$i] || '']));
|
|
226
215
|
},
|
|
216
|
+
/** 查找子串或字符出现的次数 */
|
|
217
|
+
count(search) {
|
|
218
|
+
if (!search)
|
|
219
|
+
throw new Error('count 的 search 不能为空');
|
|
220
|
+
let count = 0;
|
|
221
|
+
for (let i = 0; (i = this.indexOf(search, i)) !== -1; i += search.length)
|
|
222
|
+
count++;
|
|
223
|
+
return count;
|
|
224
|
+
},
|
|
227
225
|
quote(type = 'single') {
|
|
228
226
|
if (type === 'psh')
|
|
229
227
|
return `& ${this.quote()}`;
|
|
@@ -313,9 +311,9 @@ Object.defineProperties(String.prototype, {
|
|
|
313
311
|
.replace(/(["']+)\s*(.+?)\s*(["']+)/g, '$1$2$3')
|
|
314
312
|
.replace(new RegExp(cjk + '([\\+\\-\\*\\/=&\\\\\\|<>])([A-Za-z0-9])', 'g'), '$1 $2 $3')
|
|
315
313
|
.replace(new RegExp('([A-Za-z0-9])([\\+\\-\\*\\/=&\\\\\\|<>])' + cjk, 'g'), '$1 $2 $3');
|
|
316
|
-
const
|
|
314
|
+
const text_bak = text_;
|
|
317
315
|
text_ = text_.replace(new RegExp(cjk + '([\\(\\[\\{<\u201c]+(.*?)[\\)\\]\\}>\u201d]+)' + cjk, 'g'), '$1 $2 $4');
|
|
318
|
-
if (text_ ===
|
|
316
|
+
if (text_ === text_bak)
|
|
319
317
|
text_ = text_
|
|
320
318
|
.replace(new RegExp(cjk + '([\\(\\[\\{<\u201c>])', 'g'), '$1 $2')
|
|
321
319
|
.replace(new RegExp('([\\)\\]\\}>\u201d<])' + cjk, 'g'), '$1 $2');
|
|
@@ -324,7 +322,7 @@ Object.defineProperties(String.prototype, {
|
|
|
324
322
|
.replace(new RegExp(cjk + '([~!;:,\\.\\?\u2026])([A-Za-z0-9])', 'g'), '$1$2 $3')
|
|
325
323
|
.replace(new RegExp(cjk + '([A-Za-z0-9`\\$%\\^&\\*\\-=\\+\\\\\\|\\/@\u00a1-\u00ff\u2022\u2027\u2150-\u218f])', 'g'), '$1 $2')
|
|
326
324
|
.replace(new RegExp('([A-Za-z0-9`\\$%\\^&\\*\\-=\\+\\\\\\|\\/@\u00a1-\u00ff\u2022\u2027\u2150-\u218f])' + cjk, 'g'), '$1 $2');
|
|
327
|
-
}
|
|
325
|
+
}
|
|
328
326
|
}),
|
|
329
327
|
// ------------ 文件路径操作
|
|
330
328
|
...to_getter_property_descriptors({
|
|
@@ -332,30 +330,43 @@ Object.defineProperties(String.prototype, {
|
|
|
332
330
|
return this.endsWith('/');
|
|
333
331
|
},
|
|
334
332
|
fp() {
|
|
335
|
-
return to_fp(this);
|
|
336
|
-
},
|
|
337
|
-
fpd() {
|
|
338
333
|
if (!this)
|
|
339
334
|
return this;
|
|
340
|
-
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;
|
|
341
343
|
return fp.endsWith('/') ? fp : `${fp}/`;
|
|
342
344
|
},
|
|
343
345
|
fdir() {
|
|
344
|
-
|
|
345
|
-
return this.slice(0, this.length - (fname.length + (this.endsWith('/') ? 1 : 0)));
|
|
346
|
+
return this.strip_end(this.fname);
|
|
346
347
|
},
|
|
347
348
|
fname() {
|
|
348
|
-
const
|
|
349
|
-
if (
|
|
350
|
-
return
|
|
351
|
-
|
|
352
|
-
|
|
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);
|
|
353
361
|
},
|
|
354
362
|
fext() {
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
363
|
+
const { fname } = this;
|
|
364
|
+
const index = fname.lastIndexOf('.');
|
|
365
|
+
return index <= 0
|
|
366
|
+
? ''
|
|
367
|
+
: fname.slice(index + 1);
|
|
368
|
+
}
|
|
369
|
+
})
|
|
359
370
|
});
|
|
360
371
|
// ------------------------------------ Date.prototype
|
|
361
372
|
Object.defineProperties(Date.prototype, to_method_property_descriptors({
|
|
@@ -411,16 +422,14 @@ function get_time_str(date, hour, ms, splitter) {
|
|
|
411
422
|
return String(hour).padStart(2, '0') + splitter +
|
|
412
423
|
String(date.getMinutes()).padStart(2, '0') + splitter +
|
|
413
424
|
String(date.getSeconds()).padStart(2, '0') +
|
|
414
|
-
(ms
|
|
415
|
-
'.' + String(date.getMilliseconds()).padStart(3, '0')
|
|
416
|
-
:
|
|
417
|
-
'');
|
|
425
|
+
(ms
|
|
426
|
+
? '.' + String(date.getMilliseconds()).padStart(3, '0')
|
|
427
|
+
: '');
|
|
418
428
|
}
|
|
419
429
|
// ------------------------------------ Number.prototype
|
|
420
430
|
Object.defineProperties(Number.prototype, to_method_property_descriptors({
|
|
421
|
-
to_fsize_str(
|
|
422
|
-
|
|
423
|
-
return `${value} ${unit.replace('i', '')}`;
|
|
431
|
+
to_fsize_str() {
|
|
432
|
+
return byte_size(this);
|
|
424
433
|
},
|
|
425
434
|
to_bin_str() {
|
|
426
435
|
return `0b${this.toString(2)}`;
|
|
@@ -467,20 +476,27 @@ Object.defineProperties(Array.prototype, {
|
|
|
467
476
|
const indent = character.repeat(width);
|
|
468
477
|
return this.map(line => indent + line);
|
|
469
478
|
},
|
|
470
|
-
sum() {
|
|
471
|
-
return this.length
|
|
472
|
-
? this.reduce((acc, x) => acc + x)
|
|
473
|
-
: undefined;
|
|
474
|
-
},
|
|
475
|
-
max(selector = ident) {
|
|
479
|
+
sum(mapper) {
|
|
476
480
|
if (!this.length)
|
|
477
481
|
return undefined;
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
482
|
+
// 快捷路径
|
|
483
|
+
const first = this[0];
|
|
484
|
+
if ((typeof first === 'number' || typeof first === 'bigint') && !mapper)
|
|
485
|
+
return this.reduce((acc, x) => acc + x, first);
|
|
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));
|
|
490
|
+
},
|
|
491
|
+
max(mapper = ident) {
|
|
492
|
+
if (!this.length)
|
|
493
|
+
return undefined;
|
|
494
|
+
if (is_key_type(mapper))
|
|
495
|
+
mapper = build_mapper(mapper);
|
|
496
|
+
let max = mapper(this[0]);
|
|
481
497
|
let imax = 0;
|
|
482
498
|
for (let i = 0; i < this.length; i++) {
|
|
483
|
-
const value =
|
|
499
|
+
const value = mapper(this[i]);
|
|
484
500
|
if (value > max) {
|
|
485
501
|
max = value;
|
|
486
502
|
imax = i;
|
|
@@ -488,15 +504,15 @@ Object.defineProperties(Array.prototype, {
|
|
|
488
504
|
}
|
|
489
505
|
return this[imax];
|
|
490
506
|
},
|
|
491
|
-
min(
|
|
507
|
+
min(mapper = ident) {
|
|
492
508
|
if (!this.length)
|
|
493
509
|
return undefined;
|
|
494
|
-
if (
|
|
495
|
-
|
|
496
|
-
let min =
|
|
510
|
+
if (is_key_type(mapper))
|
|
511
|
+
mapper = build_mapper(mapper);
|
|
512
|
+
let min = mapper(this[0]);
|
|
497
513
|
let imin = 0;
|
|
498
514
|
for (let i = 0; i < this.length; i++) {
|
|
499
|
-
const value =
|
|
515
|
+
const value = mapper(this[i]);
|
|
500
516
|
if (value < min) {
|
|
501
517
|
min = value;
|
|
502
518
|
imin = i;
|
|
@@ -504,14 +520,14 @@ Object.defineProperties(Array.prototype, {
|
|
|
504
520
|
}
|
|
505
521
|
return this[imin];
|
|
506
522
|
},
|
|
507
|
-
unique(
|
|
508
|
-
if (!
|
|
523
|
+
unique(mapper) {
|
|
524
|
+
if (!mapper)
|
|
509
525
|
return [...new Set(this)];
|
|
510
|
-
if (is_key_type(
|
|
511
|
-
|
|
526
|
+
if (is_key_type(mapper))
|
|
527
|
+
mapper = build_mapper(mapper);
|
|
512
528
|
let map = new Map();
|
|
513
529
|
for (const x of this)
|
|
514
|
-
map.set(
|
|
530
|
+
map.set(mapper(x), x);
|
|
515
531
|
return [...map.values()];
|
|
516
532
|
},
|
|
517
533
|
join_lines(append = true) {
|
|
@@ -520,6 +536,9 @@ Object.defineProperties(Array.prototype, {
|
|
|
520
536
|
})
|
|
521
537
|
});
|
|
522
538
|
Object.defineProperties(BigInt.prototype, to_method_property_descriptors({
|
|
539
|
+
to_fsize_str() {
|
|
540
|
+
return byte_size(this);
|
|
541
|
+
},
|
|
523
542
|
toJSON() {
|
|
524
543
|
return this.toString();
|
|
525
544
|
}
|
|
@@ -583,4 +602,17 @@ export function is_codepoint_fullwidth(codepoint) {
|
|
|
583
602
|
// cjk unified ideographs extension b .. tertiary ideographic plane
|
|
584
603
|
(0x20000 <= codepoint && codepoint <= 0x3fffd)));
|
|
585
604
|
}
|
|
605
|
+
const units = ['b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb'];
|
|
606
|
+
const bytes_table = units.map((unit, i) => ({
|
|
607
|
+
start: i === 0 ? 0 : 2 ** (i * 10),
|
|
608
|
+
end: 2 ** ((i + 1) * 10),
|
|
609
|
+
unit
|
|
610
|
+
}));
|
|
611
|
+
export function byte_size(bytes) {
|
|
612
|
+
bytes = Number(bytes);
|
|
613
|
+
const sign = bytes < 0 ? '-' : '';
|
|
614
|
+
bytes = Math.abs(bytes);
|
|
615
|
+
const { unit, start } = bytes_table.find(range => bytes >= range.start && bytes < range.end);
|
|
616
|
+
return `${sign}${start === 0 ? bytes : (bytes / start).toFixed()} ${unit}`;
|
|
617
|
+
}
|
|
586
618
|
//# sourceMappingURL=prototype.browser.js.map
|
package/prototype.d.ts
CHANGED
|
@@ -59,6 +59,8 @@ declare global {
|
|
|
59
59
|
- flags?: `''` 正则匹配选项
|
|
60
60
|
- pattern_placeholder?: `/\{.*?\}/g` */
|
|
61
61
|
find(this: string, pattern: string, preservations?: string, flags?: string, pattern_placeholder?: RegExp): Record<string, string>;
|
|
62
|
+
/** 查找子串或字符出现的次数 */
|
|
63
|
+
count(this: string, search: string): number;
|
|
62
64
|
/** - type?: `'single'` 引号类型 */
|
|
63
65
|
quote(this: string, type?: keyof typeof quotes | 'psh'): string;
|
|
64
66
|
/** - type?: `'single'` 引号类型 */
|
|
@@ -69,8 +71,7 @@ declare global {
|
|
|
69
71
|
surround_tag(this: string, tag_name: string): string;
|
|
70
72
|
to_lf(this: string): string;
|
|
71
73
|
/** 'xxx'.replace(/pattern/g, '')
|
|
72
|
-
如果 pattern 是 string 则在创建 RegExp 时自动加上 flags (默认 'g'), 否则忽略 flags
|
|
73
|
-
*/
|
|
74
|
+
如果 pattern 是 string 则在创建 RegExp 时自动加上 flags (默认 'g'), 否则忽略 flags */
|
|
74
75
|
rm(this: string, pattern: string | RegExp, flags?: string): string;
|
|
75
76
|
readonly red: string;
|
|
76
77
|
readonly red_: string;
|
|
@@ -125,17 +126,25 @@ declare global {
|
|
|
125
126
|
slice_to(this: string, search: string, options?: SliceOptions): string;
|
|
126
127
|
/** 等价于 .endsWith('/') */
|
|
127
128
|
isdir: boolean;
|
|
128
|
-
/**
|
|
129
|
+
/** 转换为以 `/` 分割的路径,可能以 / 结尾 */
|
|
129
130
|
fp: string;
|
|
130
|
-
/**
|
|
131
|
+
/** 转换为以 `/` 分割的文件夹路径,一定以 / 结尾 */
|
|
131
132
|
fpd: string;
|
|
132
|
-
/**
|
|
133
|
+
/** 父文件夹路径,一定以 `/` 结尾,或为空
|
|
134
|
+
特殊情况:
|
|
135
|
+
- '/'.fdir === ''
|
|
136
|
+
- 'D:/'.fdir === '' */
|
|
133
137
|
fdir: string;
|
|
134
|
-
/**
|
|
138
|
+
/** 文件或文件夹名, 保留结尾的 /
|
|
139
|
+
常规情况:
|
|
135
140
|
- D:/0/aaa.txt -> aaa.txt
|
|
136
|
-
- D:/aaa/ -> aaa/
|
|
141
|
+
- D:/aaa/ -> aaa/
|
|
142
|
+
特殊情况:
|
|
143
|
+
- '/'.fname === '/'
|
|
144
|
+
- 'D:/'.fname === 'D:/' */
|
|
137
145
|
fname: string;
|
|
138
|
-
/**
|
|
146
|
+
/** 文件后缀名,不带点,如: txt, zip,没有后缀时返回空字符串
|
|
147
|
+
特殊情况: .aaa 的 fext 为 '' */
|
|
139
148
|
fext: string;
|
|
140
149
|
to_backslash(this: string): string;
|
|
141
150
|
}
|
|
@@ -157,8 +166,8 @@ declare global {
|
|
|
157
166
|
to_formal_str(this: Date, ms?: boolean): string;
|
|
158
167
|
}
|
|
159
168
|
interface Number {
|
|
160
|
-
/** 12.4
|
|
161
|
-
to_fsize_str(this: number
|
|
169
|
+
/** 12.4 kb (1 kb = 1024 b) */
|
|
170
|
+
to_fsize_str(this: number): string;
|
|
162
171
|
to_bin_str(this: number): string;
|
|
163
172
|
/** 转换为 0x???? 这样的十六进制形式
|
|
164
173
|
- length?: 位数自动对齐到 4 的倍数 */
|
|
@@ -171,15 +180,15 @@ declare global {
|
|
|
171
180
|
log(this: string[], limit?: number): void;
|
|
172
181
|
indent(this: string[], width?: number, c?: string): string[];
|
|
173
182
|
indent2to4(this: string[]): string[];
|
|
174
|
-
/** 对数组中所有元素求和 (+),
|
|
175
|
-
sum(this: T[]):
|
|
176
|
-
/** 查找数组中最大的元素,可传入
|
|
177
|
-
max(this: T[],
|
|
178
|
-
/** 查找数组中最小的元素,可传入
|
|
179
|
-
min(this: T[],
|
|
180
|
-
/** 去除重复元素(可按
|
|
181
|
-
-
|
|
182
|
-
unique(this: T[],
|
|
183
|
+
/** 对数组中所有元素求和 (+), 返回结果,可传入 mapper 计算出某个值,用作求和 */
|
|
184
|
+
sum<TReturn = T>(this: T[], mapper?: keyof T | Mapper<T>): TReturn;
|
|
185
|
+
/** 查找数组中最大的元素,可传入 mapper 计算出某个值,用作大小比较 */
|
|
186
|
+
max(this: T[], mapper?: keyof T | Mapper<T>): T;
|
|
187
|
+
/** 查找数组中最小的元素,可传入 mapper 计算出某个值,用作大小比较 */
|
|
188
|
+
min(this: T[], mapper?: keyof T | Mapper<T>): T;
|
|
189
|
+
/** 去除重复元素(可按 mapper 选择或计算某个值来去重),重复值保留最后出现的那个
|
|
190
|
+
- mapper?: 可以是 key (string, number, symbol) 或 (obj: any) => any */
|
|
191
|
+
unique(this: T[], mapper?: keyof T | Mapper<T>): T[];
|
|
183
192
|
/**
|
|
184
193
|
- trim_line?: `true`
|
|
185
194
|
- rm_empty_lines?: `true`
|
|
@@ -199,26 +208,26 @@ declare global {
|
|
|
199
208
|
join_lines(append?: boolean): string;
|
|
200
209
|
}
|
|
201
210
|
interface BigInt {
|
|
211
|
+
/** 12.4 kb (1 kb = 1024 b) */
|
|
212
|
+
to_fsize_str(this: bigint): string;
|
|
202
213
|
toJSON(this: bigint): string;
|
|
203
214
|
}
|
|
204
215
|
interface Error {
|
|
205
216
|
toJSON(this: Error): string;
|
|
206
217
|
}
|
|
207
218
|
interface Set<T> {
|
|
208
|
-
map<TResult>(
|
|
219
|
+
map<TResult>(mapper: (value: T, index: number) => TResult): TResult[];
|
|
209
220
|
}
|
|
210
221
|
}
|
|
211
222
|
interface SliceOptions {
|
|
212
223
|
include?: boolean;
|
|
213
224
|
last?: boolean;
|
|
214
225
|
}
|
|
215
|
-
import chalk from 'chalk';
|
|
216
226
|
export declare const emoji_regex: RegExp;
|
|
217
|
-
export { chalk };
|
|
218
227
|
export declare const noop: () => void;
|
|
219
228
|
export declare const ident: <T>(x: T) => T;
|
|
220
|
-
export declare const
|
|
221
|
-
export type
|
|
229
|
+
export declare const build_mapper: <TObj>(key: keyof TObj) => (obj: TObj) => TObj[keyof TObj];
|
|
230
|
+
export type Mapper<TObj = any, TKey extends keyof TObj = keyof TObj> = (obj: TObj) => TObj[TKey];
|
|
222
231
|
/** value 不为 null 或 undefined */
|
|
223
232
|
export declare const not_empty: (value: any) => boolean;
|
|
224
233
|
export declare const empty: (value: any) => boolean;
|
|
@@ -248,3 +257,5 @@ export declare const brackets: {
|
|
|
248
257
|
export declare function to_json(obj: any, replacer?: any): string;
|
|
249
258
|
export declare function to_json_safely(obj: any, replacer?: any): string;
|
|
250
259
|
export declare function is_codepoint_fullwidth(codepoint: number): boolean;
|
|
260
|
+
export declare function byte_size(bytes: number | bigint): string;
|
|
261
|
+
export {};
|
package/prototype.js
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import util from 'util';
|
|
2
2
|
import EmojiRegex from 'emoji-regex';
|
|
3
|
+
export const emoji_regex = EmojiRegex();
|
|
3
4
|
import strip_ansi from 'strip-ansi';
|
|
4
|
-
import chalk from 'chalk';
|
|
5
|
-
import { to_fp, dirname, basename, extname } from "./path.js";
|
|
6
5
|
import { t } from "./i18n/instance.js";
|
|
7
|
-
chalk.level = 2;
|
|
8
|
-
export const emoji_regex = EmojiRegex();
|
|
9
|
-
export { chalk };
|
|
10
6
|
export const noop = () => { };
|
|
11
7
|
export const ident = (x) => x;
|
|
12
|
-
export const
|
|
8
|
+
export const build_mapper = (key) => (obj) => obj[key];
|
|
13
9
|
/** value 不为 null 或 undefined */
|
|
14
10
|
export const not_empty = (value) => value !== null && value !== undefined;
|
|
15
11
|
export const empty = (value) => value === undefined || value === null;
|
|
@@ -47,7 +43,6 @@ export const brackets = {
|
|
|
47
43
|
fat: ['【', '】'],
|
|
48
44
|
tortoise_shell: ['〔', '〕'],
|
|
49
45
|
};
|
|
50
|
-
const color_map = Object.fromEntries(['red_', 'green_', 'yellow_', 'blue_', 'magenta_', 'cyan_'].map(color => [color, `${color.slice(0, -1)}Bright`]));
|
|
51
46
|
if (!globalThis.my_prototype_defined) {
|
|
52
47
|
// ------------------------------------ String.prototype
|
|
53
48
|
Object.defineProperties(String.prototype, {
|
|
@@ -222,6 +217,15 @@ if (!globalThis.my_prototype_defined) {
|
|
|
222
217
|
return Object.fromEntries(Object.entries($placeholders)
|
|
223
218
|
.map(([name, $i]) => [name, matches[$i] || '']));
|
|
224
219
|
},
|
|
220
|
+
/** 查找子串或字符出现的次数 */
|
|
221
|
+
count(search) {
|
|
222
|
+
if (!search)
|
|
223
|
+
throw new Error('count 的 search 不能为空');
|
|
224
|
+
let count = 0;
|
|
225
|
+
for (let i = 0; (i = this.indexOf(search, i)) !== -1; i += search.length)
|
|
226
|
+
count++;
|
|
227
|
+
return count;
|
|
228
|
+
},
|
|
225
229
|
quote(type = 'single') {
|
|
226
230
|
if (type === 'psh')
|
|
227
231
|
return `& ${this.quote()}`;
|
|
@@ -242,9 +246,6 @@ if (!globalThis.my_prototype_defined) {
|
|
|
242
246
|
to_lf() {
|
|
243
247
|
return this.replace(/\r\n/g, '\n');
|
|
244
248
|
},
|
|
245
|
-
to_crlf() {
|
|
246
|
-
return this.replace(/\n/g, '\r\n');
|
|
247
|
-
},
|
|
248
249
|
rm(pattern, flags = 'g') {
|
|
249
250
|
if (typeof pattern === 'string')
|
|
250
251
|
pattern = new RegExp(pattern, flags);
|
|
@@ -345,45 +346,68 @@ if (!globalThis.my_prototype_defined) {
|
|
|
345
346
|
.replace(new RegExp('([A-Za-z0-9`\\$%\\^&\\*\\-=\\+\\\\\\|\\/@\u00a1-\u00ff\u2022\u2027\u2150-\u218f])' + cjk, 'g'), '$1 $2');
|
|
346
347
|
}
|
|
347
348
|
}),
|
|
348
|
-
// ------------
|
|
349
|
+
// ------------ colors
|
|
349
350
|
...Object.fromEntries([
|
|
350
351
|
'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'grey',
|
|
351
352
|
'red_', 'green_', 'yellow_', 'blue_', 'magenta_', 'cyan_',
|
|
352
353
|
'underline',
|
|
353
|
-
].map(color =>
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
354
|
+
].map(color => {
|
|
355
|
+
const style = color.endsWith('_') ? `${color.slice(0, -1)}Bright` : color;
|
|
356
|
+
return [color, {
|
|
357
|
+
configurable: true,
|
|
358
|
+
get() {
|
|
359
|
+
// @ts-ignore
|
|
360
|
+
return util.styleText(style, this, { validateStream: false });
|
|
361
|
+
}
|
|
362
|
+
}];
|
|
363
|
+
})),
|
|
359
364
|
// ------------ 文件路径操作
|
|
360
365
|
...to_getter_property_descriptors({
|
|
361
366
|
isdir() {
|
|
362
367
|
return this.endsWith('/');
|
|
363
368
|
},
|
|
364
369
|
fp() {
|
|
365
|
-
|
|
370
|
+
if (!this)
|
|
371
|
+
return this;
|
|
372
|
+
const fp = this.replaceAll('\\', '/');
|
|
373
|
+
// 转换小写盘符开头的路径
|
|
374
|
+
return fp[1] === ':' && 'a' <= fp[0] && fp[0] <= 'z'
|
|
375
|
+
? fp[0].toUpperCase() + fp.slice(1)
|
|
376
|
+
: fp;
|
|
366
377
|
},
|
|
367
378
|
fpd() {
|
|
368
|
-
const fp =
|
|
379
|
+
const { fp } = this;
|
|
369
380
|
return fp.endsWith('/') ? fp : `${fp}/`;
|
|
370
381
|
},
|
|
371
382
|
fdir() {
|
|
372
|
-
|
|
373
|
-
// 有可能 fpd 是 '/'
|
|
374
|
-
return fpd.endsWith('/') ? fpd : `${fpd}/`;
|
|
383
|
+
return this.strip_end(this.fname);
|
|
375
384
|
},
|
|
376
385
|
fname() {
|
|
377
|
-
|
|
386
|
+
const ilast = this.lastIndexOf('/');
|
|
387
|
+
if (ilast === -1)
|
|
388
|
+
return this; // 没有斜杠时返回整个字符串
|
|
389
|
+
// 以斜杠结尾的情况
|
|
390
|
+
if (ilast === this.length - 1) {
|
|
391
|
+
const iprev = this.lastIndexOf('/', ilast - 1);
|
|
392
|
+
return iprev === -1
|
|
393
|
+
? this // 只有一个斜杠且在末尾
|
|
394
|
+
: this.slice(iprev + 1);
|
|
395
|
+
}
|
|
396
|
+
// 返回最后一个斜杠后的内容
|
|
397
|
+
return this.slice(ilast + 1);
|
|
378
398
|
},
|
|
379
399
|
fext() {
|
|
380
|
-
|
|
381
|
-
|
|
400
|
+
const { fname } = this;
|
|
401
|
+
const index = fname.lastIndexOf('.');
|
|
402
|
+
return index <= 0
|
|
403
|
+
? ''
|
|
404
|
+
: fname.slice(index + 1);
|
|
405
|
+
}
|
|
382
406
|
}),
|
|
383
407
|
...to_method_property_descriptors({
|
|
384
408
|
to_backslash() {
|
|
385
409
|
return this.replaceAll('/', '\\');
|
|
386
|
-
}
|
|
410
|
+
}
|
|
387
411
|
})
|
|
388
412
|
});
|
|
389
413
|
// ------------------------------------ Date.prototype
|
|
@@ -440,16 +464,14 @@ if (!globalThis.my_prototype_defined) {
|
|
|
440
464
|
return String(hour).padStart(2, '0') + splitter +
|
|
441
465
|
String(date.getMinutes()).padStart(2, '0') + splitter +
|
|
442
466
|
String(date.getSeconds()).padStart(2, '0') +
|
|
443
|
-
(ms
|
|
444
|
-
'.' + String(date.getMilliseconds()).padStart(3, '0')
|
|
445
|
-
:
|
|
446
|
-
'');
|
|
467
|
+
(ms
|
|
468
|
+
? '.' + String(date.getMilliseconds()).padStart(3, '0')
|
|
469
|
+
: '');
|
|
447
470
|
}
|
|
448
471
|
// ------------------------------------ Number.prototype
|
|
449
472
|
Object.defineProperties(Number.prototype, to_method_property_descriptors({
|
|
450
|
-
to_fsize_str(
|
|
451
|
-
|
|
452
|
-
return `${value} ${unit.replace('i', '')}`;
|
|
473
|
+
to_fsize_str() {
|
|
474
|
+
return byte_size(this);
|
|
453
475
|
},
|
|
454
476
|
to_bin_str() {
|
|
455
477
|
return `0b${this.toString(2)}`;
|
|
@@ -520,20 +542,27 @@ if (!globalThis.my_prototype_defined) {
|
|
|
520
542
|
return this.split_indents()
|
|
521
543
|
.map(line => ' '.repeat(line.indent * 2) + line.text);
|
|
522
544
|
},
|
|
523
|
-
sum() {
|
|
524
|
-
return this.length
|
|
525
|
-
? this.reduce((acc, x) => acc + x)
|
|
526
|
-
: undefined;
|
|
527
|
-
},
|
|
528
|
-
max(selector = ident) {
|
|
545
|
+
sum(mapper) {
|
|
529
546
|
if (!this.length)
|
|
530
547
|
return undefined;
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
548
|
+
// 快捷路径
|
|
549
|
+
const first = this[0];
|
|
550
|
+
if ((typeof first === 'number' || typeof first === 'bigint') && !mapper)
|
|
551
|
+
return this.reduce((acc, x) => acc + x, first);
|
|
552
|
+
if (is_key_type(mapper))
|
|
553
|
+
mapper = build_mapper(mapper);
|
|
554
|
+
mapper ??= ident;
|
|
555
|
+
return this.reduce((acc, x) => acc + mapper(x), mapper(first));
|
|
556
|
+
},
|
|
557
|
+
max(mapper = ident) {
|
|
558
|
+
if (!this.length)
|
|
559
|
+
return undefined;
|
|
560
|
+
if (is_key_type(mapper))
|
|
561
|
+
mapper = build_mapper(mapper);
|
|
562
|
+
let max = mapper(this[0]);
|
|
534
563
|
let imax = 0;
|
|
535
564
|
for (let i = 0; i < this.length; i++) {
|
|
536
|
-
const value =
|
|
565
|
+
const value = mapper(this[i]);
|
|
537
566
|
if (value > max) {
|
|
538
567
|
max = value;
|
|
539
568
|
imax = i;
|
|
@@ -541,15 +570,15 @@ if (!globalThis.my_prototype_defined) {
|
|
|
541
570
|
}
|
|
542
571
|
return this[imax];
|
|
543
572
|
},
|
|
544
|
-
min(
|
|
573
|
+
min(mapper = ident) {
|
|
545
574
|
if (!this.length)
|
|
546
575
|
return undefined;
|
|
547
|
-
if (is_key_type(
|
|
548
|
-
|
|
549
|
-
let min =
|
|
576
|
+
if (is_key_type(mapper))
|
|
577
|
+
mapper = build_mapper(mapper);
|
|
578
|
+
let min = mapper(this[0]);
|
|
550
579
|
let imin = 0;
|
|
551
580
|
for (let i = 0; i < this.length; i++) {
|
|
552
|
-
const value =
|
|
581
|
+
const value = mapper(this[i]);
|
|
553
582
|
if (value < min) {
|
|
554
583
|
min = value;
|
|
555
584
|
imin = i;
|
|
@@ -557,14 +586,14 @@ if (!globalThis.my_prototype_defined) {
|
|
|
557
586
|
}
|
|
558
587
|
return this[imin];
|
|
559
588
|
},
|
|
560
|
-
unique(
|
|
561
|
-
if (!
|
|
589
|
+
unique(mapper) {
|
|
590
|
+
if (!mapper)
|
|
562
591
|
return [...new Set(this)];
|
|
563
|
-
if (is_key_type(
|
|
564
|
-
|
|
592
|
+
if (is_key_type(mapper))
|
|
593
|
+
mapper = build_mapper(mapper);
|
|
565
594
|
let map = new Map();
|
|
566
595
|
for (const x of this)
|
|
567
|
-
map.set(
|
|
596
|
+
map.set(mapper(x), x);
|
|
568
597
|
return [...map.values()];
|
|
569
598
|
},
|
|
570
599
|
join_lines(append = true) {
|
|
@@ -573,6 +602,9 @@ if (!globalThis.my_prototype_defined) {
|
|
|
573
602
|
})
|
|
574
603
|
});
|
|
575
604
|
Object.defineProperties(BigInt.prototype, to_method_property_descriptors({
|
|
605
|
+
to_fsize_str() {
|
|
606
|
+
return byte_size(this);
|
|
607
|
+
},
|
|
576
608
|
toJSON() {
|
|
577
609
|
return this.toString();
|
|
578
610
|
}
|
|
@@ -643,4 +675,17 @@ export function is_codepoint_fullwidth(codepoint) {
|
|
|
643
675
|
// cjk unified ideographs extension b .. tertiary ideographic plane
|
|
644
676
|
(0x20000 <= codepoint && codepoint <= 0x3fffd)));
|
|
645
677
|
}
|
|
678
|
+
const units = ['b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb'];
|
|
679
|
+
const bytes_table = units.map((unit, i) => ({
|
|
680
|
+
start: i === 0 ? 0 : 2 ** (i * 10),
|
|
681
|
+
end: 2 ** ((i + 1) * 10),
|
|
682
|
+
unit
|
|
683
|
+
}));
|
|
684
|
+
export function byte_size(bytes) {
|
|
685
|
+
bytes = Number(bytes);
|
|
686
|
+
const sign = bytes < 0 ? '-' : '';
|
|
687
|
+
bytes = Math.abs(bytes);
|
|
688
|
+
const { unit, start } = bytes_table.find(range => bytes >= range.start && bytes < range.end);
|
|
689
|
+
return `${sign}${start === 0 ? bytes : (bytes / start).toFixed()} ${unit}`;
|
|
690
|
+
}
|
|
646
691
|
//# sourceMappingURL=prototype.js.map
|