xshell 0.0.68 → 0.0.70
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/net.d.ts +4 -1
- package/net.js +1 -1
- package/net.js.map +1 -1
- package/package.json +9 -9
- package/prototype.d.ts +1 -0
- package/prototype.js +415 -413
- package/prototype.js.map +1 -1
package/prototype.js
CHANGED
|
@@ -40,437 +40,439 @@ export const brackets = {
|
|
|
40
40
|
tortoise_shell: ['〔', '〕'],
|
|
41
41
|
};
|
|
42
42
|
const color_map = Object.fromEntries(['red_', 'green_', 'yellow_', 'blue_', 'magenta_', 'cyan_'].map(color => [color, `${color.slice(0, -1)}Bright`]));
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
code >=
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return width;
|
|
61
|
-
}
|
|
62
|
-
}),
|
|
63
|
-
// ------------ 文本处理工具方法
|
|
64
|
-
...to_method_property_descriptors({
|
|
65
|
-
/** 截取字符串不超过 width 显示宽度的部分,并保留颜色
|
|
66
|
-
找到并记录能容纳 字符串 + … 的最后一个字符的位置 i_fitted
|
|
67
|
-
- 若完整的字符串长度超过 width,返回 slice(0, i_fitted + 1) + …
|
|
68
|
-
- 否则 返回 this
|
|
69
|
-
*/
|
|
70
|
-
truncate(width) {
|
|
71
|
-
const color_bak = this.startsWith('\u001b') ? this.slice(0, 5) : '';
|
|
72
|
-
const s = strip_ansi(this);
|
|
73
|
-
if (width <= 2)
|
|
74
|
-
return this.slice(0, width);
|
|
75
|
-
let i_fitted = 0;
|
|
76
|
-
let fitted_width = 0;
|
|
77
|
-
let cur_width = 0;
|
|
78
|
-
for (let i = 0; i < s.length; i++) {
|
|
79
|
-
const code = s.codePointAt(i);
|
|
80
|
-
if ((code <= 0x1F || (code >= 0x7F && code <= 0x9F)) || // Ignore control characters
|
|
81
|
-
code >= 0x300 && code <= 0x36F // Ignore combining characters
|
|
82
|
-
)
|
|
83
|
-
continue;
|
|
84
|
-
// surrogates (codepoint 需要用两个 utf-16 编码单位表示,因此这里跳过第二个编码单位,防止重复计算显示宽度)
|
|
85
|
-
if (code > 0xFFFF)
|
|
86
|
-
i++;
|
|
87
|
-
const w = is_codepoint_fullwidth(code) ? 2 : 1;
|
|
88
|
-
if (cur_width + w + 2 <= width) {
|
|
89
|
-
i_fitted = i;
|
|
90
|
-
fitted_width += w;
|
|
91
|
-
}
|
|
92
|
-
cur_width += w;
|
|
93
|
-
if (cur_width > width) {
|
|
94
|
-
const i_fitted_next = i_fitted + 1;
|
|
95
|
-
const t = s.slice(0, i_fitted_next) + ' '.repeat(width - 2 - fitted_width) + '…';
|
|
96
|
-
return color_bak ? color_bak + t + '\u001b[39m' : t;
|
|
43
|
+
if (!global.my_prototype_defined) {
|
|
44
|
+
// ------------------------------------ String.prototype
|
|
45
|
+
Object.defineProperties(String.prototype, {
|
|
46
|
+
...to_getter_property_descriptors({
|
|
47
|
+
width() {
|
|
48
|
+
const s = strip_ansi(this.replace(emoji_regex, ' '));
|
|
49
|
+
let width = 0;
|
|
50
|
+
for (let i = 0; i < s.length; i++) {
|
|
51
|
+
const code = s.codePointAt(i);
|
|
52
|
+
if ((code <= 0x1f || (code >= 0x7f && code <= 0x9f)) || // ignore control characters
|
|
53
|
+
code >= 0x300 && code <= 0x36f // ignore combining characters
|
|
54
|
+
)
|
|
55
|
+
continue;
|
|
56
|
+
// surrogates
|
|
57
|
+
if (code > 0xffff)
|
|
58
|
+
i++;
|
|
59
|
+
width += is_codepoint_fullwidth(code) ? 2 : 1;
|
|
97
60
|
}
|
|
61
|
+
return width;
|
|
98
62
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const placeholder = $0.slice(1, -1);
|
|
136
|
-
let [placeholder_name, placeholder_pattern] = placeholder.split(':').map(s => s.trim());
|
|
137
|
-
let optional = false;
|
|
138
|
-
if (placeholder_name.endsWith('?')) {
|
|
139
|
-
placeholder_name = placeholder_name.slice(0, -1);
|
|
140
|
-
optional = true;
|
|
63
|
+
}),
|
|
64
|
+
// ------------ 文本处理工具方法
|
|
65
|
+
...to_method_property_descriptors({
|
|
66
|
+
/** 截取字符串不超过 width 显示宽度的部分,并保留颜色
|
|
67
|
+
找到并记录能容纳 字符串 + … 的最后一个字符的位置 i_fitted
|
|
68
|
+
- 若完整的字符串长度超过 width,返回 slice(0, i_fitted + 1) + …
|
|
69
|
+
- 否则 返回 this
|
|
70
|
+
*/
|
|
71
|
+
truncate(width) {
|
|
72
|
+
const color_bak = this.startsWith('\u001b') ? this.slice(0, 5) : '';
|
|
73
|
+
const s = strip_ansi(this);
|
|
74
|
+
if (width <= 2)
|
|
75
|
+
return this.slice(0, width);
|
|
76
|
+
let i_fitted = 0;
|
|
77
|
+
let fitted_width = 0;
|
|
78
|
+
let cur_width = 0;
|
|
79
|
+
for (let i = 0; i < s.length; i++) {
|
|
80
|
+
const code = s.codePointAt(i);
|
|
81
|
+
if ((code <= 0x1F || (code >= 0x7F && code <= 0x9F)) || // Ignore control characters
|
|
82
|
+
code >= 0x300 && code <= 0x36F // Ignore combining characters
|
|
83
|
+
)
|
|
84
|
+
continue;
|
|
85
|
+
// surrogates (codepoint 需要用两个 utf-16 编码单位表示,因此这里跳过第二个编码单位,防止重复计算显示宽度)
|
|
86
|
+
if (code > 0xFFFF)
|
|
87
|
+
i++;
|
|
88
|
+
const w = is_codepoint_fullwidth(code) ? 2 : 1;
|
|
89
|
+
if (cur_width + w + 2 <= width) {
|
|
90
|
+
i_fitted = i;
|
|
91
|
+
fitted_width += w;
|
|
92
|
+
}
|
|
93
|
+
cur_width += w;
|
|
94
|
+
if (cur_width > width) {
|
|
95
|
+
const i_fitted_next = i_fitted + 1;
|
|
96
|
+
const t = s.slice(0, i_fitted_next) + ' '.repeat(width - 2 - fitted_width) + '…';
|
|
97
|
+
return color_bak ? color_bak + t + '\u001b[39m' : t;
|
|
98
|
+
}
|
|
141
99
|
}
|
|
142
|
-
$placeholders[placeholder_name] = regx_parts.push(placeholder_pattern ?
|
|
143
|
-
`${placeholder_pattern.bracket()}${optional ? '?' : ''}`
|
|
144
|
-
:
|
|
145
|
-
'(.*?)');
|
|
146
|
-
return '';
|
|
147
|
-
});
|
|
148
|
-
add_part(last_end);
|
|
149
|
-
// 最后一个 (.*?) 改为贪心匹配,满足 .{suffix} 的需要
|
|
150
|
-
regx_parts = regx_parts.filter(part => part);
|
|
151
|
-
if (regx_parts.last === '(.*?)')
|
|
152
|
-
regx_parts[regx_parts.length - 1] = '(.*)';
|
|
153
|
-
const pattern_regx = new RegExp(regx_parts.join(''), flags);
|
|
154
|
-
// --- 根据 pattern_regx 去匹配原有字符串,获取匹配结果,生成 placeholders 词典
|
|
155
|
-
const matches = pattern_regx.exec(this);
|
|
156
|
-
if (!matches)
|
|
157
100
|
return this;
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
101
|
+
},
|
|
102
|
+
pad(width, { character = ' ', position = 'right' } = {}) {
|
|
103
|
+
const _width = this.width;
|
|
104
|
+
if (_width >= width)
|
|
105
|
+
return this;
|
|
106
|
+
if (position === 'right')
|
|
107
|
+
return this + character.repeat((width - _width) / character.width);
|
|
108
|
+
return character.repeat(width - _width) + this;
|
|
109
|
+
},
|
|
110
|
+
limit(width, { character = ' ', position = 'right' } = {}) {
|
|
111
|
+
return this.pad(width, { character, position }).truncate(width);
|
|
112
|
+
},
|
|
113
|
+
to_regexp(preservations, flags = '') {
|
|
114
|
+
const preserved_chars = new Set(preservations);
|
|
115
|
+
const replace_chars = Array.prototype.filter.call('|\\{}()[]^$+*?.-', (c) => !preserved_chars.has(c))
|
|
116
|
+
.map((c) => c === ']' ? '\\]' : c).join('');
|
|
117
|
+
return new RegExp(this.replace(new RegExp(`[${replace_chars}]`, 'g'), '\\$&'), flags);
|
|
118
|
+
},
|
|
119
|
+
to_bool() {
|
|
120
|
+
return this.length && this !== '0' && this.toLowerCase() !== 'false';
|
|
121
|
+
},
|
|
122
|
+
refmt(pattern, pattern_, preservations = '', flags = '', transformer = (name, value) => value || '', pattern_placeholder = /\{.*?\}/g) {
|
|
123
|
+
// --- 转换 pattern 为 pattern_regx
|
|
124
|
+
let last_end = 0;
|
|
125
|
+
// placeholder matched group indexes
|
|
126
|
+
let $placeholders = {};
|
|
127
|
+
let regx_parts = [];
|
|
128
|
+
function add_part(left, right) {
|
|
129
|
+
const part = pattern.slice(left, right);
|
|
130
|
+
if (part)
|
|
131
|
+
regx_parts.push(part.to_regexp(preservations).source.bracket());
|
|
132
|
+
}
|
|
133
|
+
pattern.replace(pattern_placeholder, ($0, offset) => {
|
|
134
|
+
add_part(last_end, offset);
|
|
135
|
+
last_end = offset + $0.length;
|
|
136
|
+
const placeholder = $0.slice(1, -1);
|
|
137
|
+
let [placeholder_name, placeholder_pattern] = placeholder.split(':').map(s => s.trim());
|
|
138
|
+
let optional = false;
|
|
139
|
+
if (placeholder_name.endsWith('?')) {
|
|
140
|
+
placeholder_name = placeholder_name.slice(0, -1);
|
|
141
|
+
optional = true;
|
|
142
|
+
}
|
|
143
|
+
$placeholders[placeholder_name] = regx_parts.push(placeholder_pattern ?
|
|
144
|
+
`${placeholder_pattern.bracket()}${optional ? '?' : ''}`
|
|
145
|
+
:
|
|
146
|
+
'(.*?)');
|
|
147
|
+
return '';
|
|
148
|
+
});
|
|
149
|
+
add_part(last_end);
|
|
150
|
+
// 最后一个 (.*?) 改为贪心匹配,满足 .{suffix} 的需要
|
|
151
|
+
regx_parts = regx_parts.filter(part => part);
|
|
152
|
+
if (regx_parts.last === '(.*?)')
|
|
153
|
+
regx_parts[regx_parts.length - 1] = '(.*)';
|
|
154
|
+
const pattern_regx = new RegExp(regx_parts.join(''), flags);
|
|
155
|
+
// --- 根据 pattern_regx 去匹配原有字符串,获取匹配结果,生成 placeholders 词典
|
|
156
|
+
const matches = pattern_regx.exec(this);
|
|
157
|
+
if (!matches)
|
|
158
|
+
return this;
|
|
159
|
+
const placeholders = Object.fromEntries(Object.entries($placeholders)
|
|
160
|
+
.map(([name, $i]) => [
|
|
161
|
+
[name, matches[$i]],
|
|
162
|
+
[`${name}.before`, matches[$i - 1] || ''],
|
|
163
|
+
[`${name}.after`, matches[$i + 1] || ''],
|
|
164
|
+
])
|
|
165
|
+
.flat());
|
|
166
|
+
// --- 转换 pattern_ 为 replacement_str,如果有 transformer 则在遇到 placeholder 时应用
|
|
167
|
+
last_end = 0;
|
|
168
|
+
let replacement_parts = [];
|
|
169
|
+
pattern_.replace(pattern_placeholder, ($0, offset) => {
|
|
170
|
+
replacement_parts.push(pattern_.slice(last_end, offset));
|
|
171
|
+
last_end = offset + $0.length;
|
|
172
|
+
const placeholder_name = $0.slice(1, -1);
|
|
173
|
+
replacement_parts.push(transformer(placeholder_name, placeholders[placeholder_name], placeholders));
|
|
174
|
+
return '';
|
|
175
|
+
});
|
|
176
|
+
replacement_parts.push(pattern_.slice(last_end));
|
|
177
|
+
return this.replace(pattern_regx, replacement_parts.join(''));
|
|
178
|
+
},
|
|
179
|
+
find(pattern, preservations = '', flags = '', pattern_placeholder = /\{.*?\}/g) {
|
|
180
|
+
// --- 转换 pattern 为 pattern_regx
|
|
181
|
+
let last_end = 0;
|
|
182
|
+
// placeholder matched group index
|
|
183
|
+
let $placeholders = {};
|
|
184
|
+
let regx_parts = [];
|
|
185
|
+
function add_part(left, right) {
|
|
186
|
+
const part = pattern.slice(left, right);
|
|
187
|
+
if (part)
|
|
188
|
+
regx_parts.push(part.to_regexp(preservations).source.bracket());
|
|
189
|
+
}
|
|
190
|
+
pattern.replace(pattern_placeholder, ($0, offset) => {
|
|
191
|
+
add_part(last_end, offset);
|
|
192
|
+
last_end = offset + $0.length;
|
|
193
|
+
const placeholder = $0.slice(1, -1);
|
|
194
|
+
let [placeholder_name, placeholder_pattern] = placeholder.split(':').map(s => s.trim());
|
|
195
|
+
let optional = false;
|
|
196
|
+
if (placeholder_name.endsWith('?')) {
|
|
197
|
+
placeholder_name = placeholder_name.slice(0, -1);
|
|
198
|
+
optional = true;
|
|
199
|
+
}
|
|
200
|
+
$placeholders[placeholder_name] = regx_parts.push(placeholder_pattern ?
|
|
201
|
+
`${placeholder_pattern.bracket()}${optional ? '?' : ''}`
|
|
202
|
+
:
|
|
203
|
+
'(.*?)');
|
|
204
|
+
return '';
|
|
205
|
+
});
|
|
206
|
+
add_part(last_end);
|
|
207
|
+
// 最后一个 (.*?) 改为贪心匹配,满足 .{suffix} 的需要
|
|
208
|
+
regx_parts = regx_parts.filter(part => part);
|
|
209
|
+
if (regx_parts[regx_parts.length - 1] === '(.*?)')
|
|
210
|
+
regx_parts[regx_parts.length - 1] = '(.*)';
|
|
211
|
+
const pattern_regx = new RegExp(regx_parts.join(''), flags);
|
|
212
|
+
// --- 根据 pattern_regx 去匹配原有字符串,获取匹配结果,生成 placeholders 词典
|
|
213
|
+
const matches = pattern_regx.exec(this);
|
|
214
|
+
if (!matches)
|
|
215
|
+
return {};
|
|
216
|
+
return Object.fromEntries(Object.entries($placeholders)
|
|
217
|
+
.map(([name, $i]) => [name, matches[$i] || '']));
|
|
218
|
+
},
|
|
219
|
+
quote(type = 'single') {
|
|
220
|
+
if (type === 'psh')
|
|
221
|
+
return `& ${this.quote()}`;
|
|
222
|
+
return this.surround(quotes[type]);
|
|
223
|
+
},
|
|
224
|
+
bracket(shape = 'round') {
|
|
225
|
+
return this.surround(...brackets[shape]);
|
|
226
|
+
},
|
|
227
|
+
surround(left, right) {
|
|
228
|
+
return left + this + (right || left);
|
|
229
|
+
},
|
|
230
|
+
surround_tag(tag_name) {
|
|
231
|
+
return '<' + tag_name + '>' + this + '</' + tag_name + '>';
|
|
232
|
+
},
|
|
233
|
+
to_lf() {
|
|
234
|
+
return this.replace(/\r\n/g, '\n');
|
|
235
|
+
},
|
|
236
|
+
to_crlf() {
|
|
237
|
+
return this.replace(/\n/g, '\r\n');
|
|
238
|
+
},
|
|
239
|
+
rm(pattern, flags = 'g') {
|
|
240
|
+
if (typeof pattern === 'string')
|
|
241
|
+
pattern = new RegExp(pattern, flags);
|
|
242
|
+
return this.replace(pattern, '');
|
|
243
|
+
},
|
|
244
|
+
split_lines(delimiter = /\r?\n/) {
|
|
245
|
+
let lines = this.split(delimiter);
|
|
246
|
+
if (lines.last === '')
|
|
247
|
+
lines.pop();
|
|
248
|
+
return lines;
|
|
249
|
+
},
|
|
250
|
+
split_indent() {
|
|
251
|
+
let i = 0;
|
|
252
|
+
let indent = 0;
|
|
253
|
+
for (; i < this.length; i++)
|
|
254
|
+
if (this[i] === ' ')
|
|
255
|
+
indent += 1;
|
|
256
|
+
else if (this[i] === '\t')
|
|
257
|
+
indent += 4;
|
|
258
|
+
else
|
|
259
|
+
break;
|
|
260
|
+
return {
|
|
261
|
+
indent,
|
|
262
|
+
text: this.slice(i)
|
|
263
|
+
};
|
|
264
|
+
},
|
|
265
|
+
trim_doc_comment() {
|
|
266
|
+
return `/** ${this.slice(3, -2).replace(/\s*\*\s*/g, ' ').replace(/@(param|params|return) \{.*?\}\s*/g, '').trim()} */`;
|
|
267
|
+
},
|
|
268
|
+
to_base64() {
|
|
269
|
+
return Buffer.from(this).toString('base64');
|
|
270
|
+
},
|
|
271
|
+
decode_base64(buffer = false) {
|
|
272
|
+
const buf = Buffer.from(this, 'base64');
|
|
273
|
+
if (buffer)
|
|
274
|
+
return buf;
|
|
275
|
+
return buf.toString();
|
|
276
|
+
},
|
|
277
|
+
strip_ansi() {
|
|
278
|
+
return strip_ansi(this);
|
|
279
|
+
},
|
|
280
|
+
space() {
|
|
281
|
+
if (!this)
|
|
282
|
+
return this;
|
|
283
|
+
let text_;
|
|
284
|
+
text_ = this
|
|
285
|
+
.replace(new RegExp(cjk + `(['"])`, 'g'), '$1 $2')
|
|
286
|
+
.replace(new RegExp(`(['"])` + cjk, 'g'), '$1 $2')
|
|
287
|
+
.replace(/(["']+)\s*(.+?)\s*(["']+)/g, '$1$2$3')
|
|
288
|
+
.replace(new RegExp(cjk + '([\\+\\-\\*\\/=&\\\\\\|<>])([A-Za-z0-9])', 'g'), '$1 $2 $3')
|
|
289
|
+
.replace(new RegExp('([A-Za-z0-9])([\\+\\-\\*\\/=&\\\\\\|<>])' + cjk, 'g'), '$1 $2 $3');
|
|
290
|
+
const text_bak = text_;
|
|
291
|
+
text_ = text_.replace(new RegExp(cjk + '([\\(\\[\\{<\u201c]+(.*?)[\\)\\]\\}>\u201d]+)' + cjk, 'g'), '$1 $2 $4');
|
|
292
|
+
if (text_ === text_bak)
|
|
293
|
+
text_ = text_
|
|
294
|
+
.replace(new RegExp(cjk + '([\\(\\[\\{<\u201c>])', 'g'), '$1 $2')
|
|
295
|
+
.replace(new RegExp('([\\)\\]\\}>\u201d<])' + cjk, 'g'), '$1 $2');
|
|
296
|
+
return text_
|
|
297
|
+
.replace(/([\(\[\{<\u201c]+)(\s*)(.+?)(\s*)([\)\]\}>\u201d]+)/g, '$1$3$5')
|
|
298
|
+
.replace(new RegExp(cjk + '([~!;:,\\.\\?\u2026])([A-Za-z0-9])', 'g'), '$1$2 $3')
|
|
299
|
+
.replace(new RegExp(cjk + '([A-Za-z0-9`\\$%\\^&\\*\\-=\\+\\\\\\|\\/@\u00a1-\u00ff\u2022\u2027\u2150-\u218f])', 'g'), '$1 $2')
|
|
300
|
+
.replace(new RegExp('([A-Za-z0-9`\\$%\\^&\\*\\-=\\+\\\\\\|\\/@\u00a1-\u00ff\u2022\u2027\u2150-\u218f])' + cjk, 'g'), '$1 $2');
|
|
188
301
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
302
|
+
}),
|
|
303
|
+
// ------------ chalk colors
|
|
304
|
+
...Object.fromEntries([
|
|
305
|
+
'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'grey',
|
|
306
|
+
'red_', 'green_', 'yellow_', 'blue_', 'magenta_', 'cyan_',
|
|
307
|
+
'underline',
|
|
308
|
+
].map(color => ([color, {
|
|
309
|
+
configurable: true,
|
|
310
|
+
get() {
|
|
311
|
+
return chalk[color_map[color] || color](this);
|
|
198
312
|
}
|
|
199
|
-
|
|
200
|
-
|
|
313
|
+
}]))),
|
|
314
|
+
// ------------ 文件路径操作
|
|
315
|
+
...to_getter_property_descriptors({
|
|
316
|
+
fdir() {
|
|
317
|
+
const dir = path.dirname(this);
|
|
318
|
+
return dir.endsWith('/') ? dir : `${dir}/`;
|
|
319
|
+
},
|
|
320
|
+
fname() {
|
|
321
|
+
return path.basename(this);
|
|
322
|
+
},
|
|
323
|
+
fext() {
|
|
324
|
+
return path.extname(this);
|
|
325
|
+
},
|
|
326
|
+
}),
|
|
327
|
+
...to_method_property_descriptors({
|
|
328
|
+
to_slash() {
|
|
329
|
+
if (!this)
|
|
330
|
+
return this;
|
|
331
|
+
return path.normalizeSafe(this);
|
|
332
|
+
},
|
|
333
|
+
to_backslash() {
|
|
334
|
+
return this.replaceAll('/', '\\');
|
|
335
|
+
},
|
|
336
|
+
})
|
|
337
|
+
});
|
|
338
|
+
// ------------------------------------ Date.prototype
|
|
339
|
+
Object.defineProperties(Date.prototype, to_method_property_descriptors({
|
|
340
|
+
to_str(ms) {
|
|
341
|
+
const [ampm, hour] = (() => {
|
|
342
|
+
let hour = this.getHours();
|
|
343
|
+
if (hour <= 6)
|
|
344
|
+
return [t('凌晨'), hour];
|
|
345
|
+
if (hour <= 8)
|
|
346
|
+
return [t('清晨'), hour];
|
|
347
|
+
if (hour <= 9)
|
|
348
|
+
return [t('早上'), hour];
|
|
349
|
+
if (hour <= 10)
|
|
350
|
+
return [t('上午'), hour];
|
|
351
|
+
if (hour <= 12)
|
|
352
|
+
return [t('中午'), hour];
|
|
353
|
+
hour -= 12;
|
|
354
|
+
if (hour <= 5)
|
|
355
|
+
return [t('下午'), hour];
|
|
356
|
+
if (hour <= 10)
|
|
357
|
+
return [t('晚上'), hour];
|
|
358
|
+
return [t('深夜'), hour];
|
|
359
|
+
})();
|
|
360
|
+
const zero_padding = { character: '0', position: 'left' };
|
|
361
|
+
return '' +
|
|
362
|
+
// year.month.date
|
|
363
|
+
this.getFullYear() + '.' +
|
|
364
|
+
String(this.getMonth() + 1).pad(2, zero_padding) + '.' +
|
|
365
|
+
String(this.getDate()).pad(2, zero_padding) + ' ' +
|
|
366
|
+
// 上午
|
|
367
|
+
ampm + ' ' +
|
|
368
|
+
// 10:03:02
|
|
369
|
+
String(hour).pad(2, zero_padding) + ':' +
|
|
370
|
+
String(this.getMinutes()).pad(2, zero_padding) + ':' +
|
|
371
|
+
String(this.getSeconds()).pad(2, zero_padding) +
|
|
372
|
+
(ms ?
|
|
373
|
+
'.' + String(this.getMilliseconds()).pad(3, zero_padding)
|
|
201
374
|
:
|
|
202
|
-
'
|
|
203
|
-
return '';
|
|
204
|
-
});
|
|
205
|
-
add_part(last_end);
|
|
206
|
-
// 最后一个 (.*?) 改为贪心匹配,满足 .{suffix} 的需要
|
|
207
|
-
regx_parts = regx_parts.filter(part => part);
|
|
208
|
-
if (regx_parts[regx_parts.length - 1] === '(.*?)')
|
|
209
|
-
regx_parts[regx_parts.length - 1] = '(.*)';
|
|
210
|
-
const pattern_regx = new RegExp(regx_parts.join(''), flags);
|
|
211
|
-
// --- 根据 pattern_regx 去匹配原有字符串,获取匹配结果,生成 placeholders 词典
|
|
212
|
-
const matches = pattern_regx.exec(this);
|
|
213
|
-
if (!matches)
|
|
214
|
-
return {};
|
|
215
|
-
return Object.fromEntries(Object.entries($placeholders)
|
|
216
|
-
.map(([name, $i]) => [name, matches[$i] || '']));
|
|
217
|
-
},
|
|
218
|
-
quote(type = 'single') {
|
|
219
|
-
if (type === 'psh')
|
|
220
|
-
return `& ${this.quote()}`;
|
|
221
|
-
return this.surround(quotes[type]);
|
|
222
|
-
},
|
|
223
|
-
bracket(shape = 'round') {
|
|
224
|
-
return this.surround(...brackets[shape]);
|
|
225
|
-
},
|
|
226
|
-
surround(left, right) {
|
|
227
|
-
return left + this + (right || left);
|
|
375
|
+
'');
|
|
228
376
|
},
|
|
229
|
-
|
|
230
|
-
return
|
|
377
|
+
to_date_str() {
|
|
378
|
+
return this.to_str().split(' ')[0];
|
|
231
379
|
},
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
to_crlf() {
|
|
236
|
-
return this.replace(/\n/g, '\r\n');
|
|
237
|
-
},
|
|
238
|
-
rm(pattern, flags = 'g') {
|
|
239
|
-
if (typeof pattern === 'string')
|
|
240
|
-
pattern = new RegExp(pattern, flags);
|
|
241
|
-
return this.replace(pattern, '');
|
|
242
|
-
},
|
|
243
|
-
split_lines(delimiter = /\r?\n/) {
|
|
244
|
-
let lines = this.split(delimiter);
|
|
245
|
-
if (lines.last === '')
|
|
246
|
-
lines.pop();
|
|
247
|
-
return lines;
|
|
248
|
-
},
|
|
249
|
-
split_indent() {
|
|
250
|
-
let i = 0;
|
|
251
|
-
let indent = 0;
|
|
252
|
-
for (; i < this.length; i++)
|
|
253
|
-
if (this[i] === ' ')
|
|
254
|
-
indent += 1;
|
|
255
|
-
else if (this[i] === '\t')
|
|
256
|
-
indent += 4;
|
|
257
|
-
else
|
|
258
|
-
break;
|
|
259
|
-
return {
|
|
260
|
-
indent,
|
|
261
|
-
text: this.slice(i)
|
|
262
|
-
};
|
|
380
|
+
to_time_str(ms) {
|
|
381
|
+
const [, ampm, time] = this.to_str(ms).split(' ');
|
|
382
|
+
return `${ampm} ${time}`;
|
|
263
383
|
},
|
|
264
|
-
|
|
265
|
-
|
|
384
|
+
}));
|
|
385
|
+
// ------------------------------------ Number.prototype
|
|
386
|
+
Object.defineProperties(Number.prototype, to_method_property_descriptors({
|
|
387
|
+
to_fsize_str(units = 'iec') {
|
|
388
|
+
const { value, unit } = byte_size(this, { units });
|
|
389
|
+
return `${value} ${unit.replace('i', '')}`;
|
|
266
390
|
},
|
|
267
|
-
|
|
268
|
-
return
|
|
391
|
+
to_bin_str() {
|
|
392
|
+
return `0b${this.toString(2)}`;
|
|
269
393
|
},
|
|
270
|
-
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
394
|
+
to_hex_str(length) {
|
|
395
|
+
const s = this.toString(16);
|
|
396
|
+
// 长度自动对齐到 4 的倍数
|
|
397
|
+
if (!length)
|
|
398
|
+
length = Math.ceil(s.length / 4) * 4;
|
|
399
|
+
return `0x${'0'.repeat(length - s.length)}${s}`;
|
|
275
400
|
},
|
|
276
|
-
|
|
277
|
-
return
|
|
401
|
+
to_oct_str() {
|
|
402
|
+
return `0o${this.toString(8)}`;
|
|
278
403
|
},
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
.replace(new RegExp(`(['"])` + cjk, 'g'), '$1 $2')
|
|
286
|
-
.replace(/(["']+)\s*(.+?)\s*(["']+)/g, '$1$2$3')
|
|
287
|
-
.replace(new RegExp(cjk + '([\\+\\-\\*\\/=&\\\\\\|<>])([A-Za-z0-9])', 'g'), '$1 $2 $3')
|
|
288
|
-
.replace(new RegExp('([A-Za-z0-9])([\\+\\-\\*\\/=&\\\\\\|<>])' + cjk, 'g'), '$1 $2 $3');
|
|
289
|
-
const text_bak = text_;
|
|
290
|
-
text_ = text_.replace(new RegExp(cjk + '([\\(\\[\\{<\u201c]+(.*?)[\\)\\]\\}>\u201d]+)' + cjk, 'g'), '$1 $2 $4');
|
|
291
|
-
if (text_ === text_bak)
|
|
292
|
-
text_ = text_
|
|
293
|
-
.replace(new RegExp(cjk + '([\\(\\[\\{<\u201c>])', 'g'), '$1 $2')
|
|
294
|
-
.replace(new RegExp('([\\)\\]\\}>\u201d<])' + cjk, 'g'), '$1 $2');
|
|
295
|
-
return text_
|
|
296
|
-
.replace(/([\(\[\{<\u201c]+)(\s*)(.+?)(\s*)([\)\]\}>\u201d]+)/g, '$1$3$5')
|
|
297
|
-
.replace(new RegExp(cjk + '([~!;:,\\.\\?\u2026])([A-Za-z0-9])', 'g'), '$1$2 $3')
|
|
298
|
-
.replace(new RegExp(cjk + '([A-Za-z0-9`\\$%\\^&\\*\\-=\\+\\\\\\|\\/@\u00a1-\u00ff\u2022\u2027\u2150-\u218f])', 'g'), '$1 $2')
|
|
299
|
-
.replace(new RegExp('([A-Za-z0-9`\\$%\\^&\\*\\-=\\+\\\\\\|\\/@\u00a1-\u00ff\u2022\u2027\u2150-\u218f])' + cjk, 'g'), '$1 $2');
|
|
300
|
-
}
|
|
301
|
-
}),
|
|
302
|
-
// ------------ chalk colors
|
|
303
|
-
...Object.fromEntries([
|
|
304
|
-
'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'grey',
|
|
305
|
-
'red_', 'green_', 'yellow_', 'blue_', 'magenta_', 'cyan_',
|
|
306
|
-
'underline',
|
|
307
|
-
].map(color => ([color, {
|
|
308
|
-
configurable: true,
|
|
309
|
-
get() {
|
|
310
|
-
return chalk[color_map[color] || color](this);
|
|
404
|
+
}));
|
|
405
|
+
// ------------------------------------ Array.prototype
|
|
406
|
+
Object.defineProperties(Array.prototype, {
|
|
407
|
+
...to_getter_property_descriptors({
|
|
408
|
+
last() {
|
|
409
|
+
return this[this.length - 1];
|
|
311
410
|
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
const [ampm, hour] = (() => {
|
|
341
|
-
let hour = this.getHours();
|
|
342
|
-
if (hour <= 6)
|
|
343
|
-
return [t('凌晨'), hour];
|
|
344
|
-
if (hour <= 8)
|
|
345
|
-
return [t('清晨'), hour];
|
|
346
|
-
if (hour <= 9)
|
|
347
|
-
return [t('早上'), hour];
|
|
348
|
-
if (hour <= 10)
|
|
349
|
-
return [t('上午'), hour];
|
|
350
|
-
if (hour <= 12)
|
|
351
|
-
return [t('中午'), hour];
|
|
352
|
-
hour -= 12;
|
|
353
|
-
if (hour <= 5)
|
|
354
|
-
return [t('下午'), hour];
|
|
355
|
-
if (hour <= 10)
|
|
356
|
-
return [t('晚上'), hour];
|
|
357
|
-
return [t('深夜'), hour];
|
|
358
|
-
})();
|
|
359
|
-
const zero_padding = { character: '0', position: 'left' };
|
|
360
|
-
return '' +
|
|
361
|
-
// year.month.date
|
|
362
|
-
this.getFullYear() + '.' +
|
|
363
|
-
String(this.getMonth() + 1).pad(2, zero_padding) + '.' +
|
|
364
|
-
String(this.getDate()).pad(2, zero_padding) + ' ' +
|
|
365
|
-
// 上午
|
|
366
|
-
ampm + ' ' +
|
|
367
|
-
// 10:03:02
|
|
368
|
-
String(hour).pad(2, zero_padding) + ':' +
|
|
369
|
-
String(this.getMinutes()).pad(2, zero_padding) + ':' +
|
|
370
|
-
String(this.getSeconds()).pad(2, zero_padding) +
|
|
371
|
-
(ms ?
|
|
372
|
-
'.' + String(this.getMilliseconds()).pad(3, zero_padding)
|
|
373
|
-
:
|
|
374
|
-
'');
|
|
375
|
-
},
|
|
376
|
-
to_date_str() {
|
|
377
|
-
return this.to_str().split(' ')[0];
|
|
378
|
-
},
|
|
379
|
-
to_time_str(ms) {
|
|
380
|
-
const [, ampm, time] = this.to_str(ms).split(' ');
|
|
381
|
-
return `${ampm} ${time}`;
|
|
382
|
-
},
|
|
383
|
-
}));
|
|
384
|
-
// ------------------------------------ Number.prototype
|
|
385
|
-
Object.defineProperties(Number.prototype, to_method_property_descriptors({
|
|
386
|
-
to_fsize_str(units = 'iec') {
|
|
387
|
-
const { value, unit } = byte_size(this, { units });
|
|
388
|
-
return `${value} ${unit.replace('i', '')}`;
|
|
389
|
-
},
|
|
390
|
-
to_bin_str() {
|
|
391
|
-
return `0b${this.toString(2)}`;
|
|
392
|
-
},
|
|
393
|
-
to_hex_str(length) {
|
|
394
|
-
const s = this.toString(16);
|
|
395
|
-
// 长度自动对齐到 4 的倍数
|
|
396
|
-
if (!length)
|
|
397
|
-
length = Math.ceil(s.length / 4) * 4;
|
|
398
|
-
return `0x${'0'.repeat(length - s.length)}${s}`;
|
|
399
|
-
},
|
|
400
|
-
to_oct_str() {
|
|
401
|
-
return `0o${this.toString(8)}`;
|
|
402
|
-
},
|
|
403
|
-
}));
|
|
404
|
-
// ------------------------------------ Array.prototype
|
|
405
|
-
Object.defineProperties(Array.prototype, {
|
|
406
|
-
...to_getter_property_descriptors({
|
|
407
|
-
last() {
|
|
408
|
-
return this[this.length - 1];
|
|
409
|
-
}
|
|
410
|
-
}),
|
|
411
|
-
// --- 文本处理工具方法
|
|
412
|
-
...to_method_property_descriptors({
|
|
413
|
-
log(limit = 10000) {
|
|
414
|
-
const text = this.join('\n') + '\n';
|
|
415
|
-
if (limit === -1 || this.length <= limit)
|
|
416
|
-
console.log(text);
|
|
417
|
-
else if (limit > 0)
|
|
418
|
-
console.log(text.slice(0, limit) + '\n...'.blue);
|
|
419
|
-
else
|
|
420
|
-
console.log('...\n'.blue + text.slice(limit));
|
|
421
|
-
},
|
|
422
|
-
trim_lines({ trim_line = true, rm_empty_lines = true, rm_last_empty_lines = false } = {}) {
|
|
423
|
-
if (!this.length)
|
|
424
|
-
return this;
|
|
425
|
-
let lines = this;
|
|
426
|
-
if (trim_line)
|
|
427
|
-
lines = lines.map(line => line.trim());
|
|
428
|
-
if (rm_empty_lines)
|
|
429
|
-
return lines.filter(line => line);
|
|
430
|
-
if (rm_last_empty_lines) {
|
|
431
|
-
lines.reverse();
|
|
432
|
-
const i_not_empty = lines.findIndex(line => line);
|
|
433
|
-
if (i_not_empty !== -1)
|
|
434
|
-
lines = lines.slice(i_not_empty);
|
|
435
|
-
lines.reverse();
|
|
411
|
+
}),
|
|
412
|
+
// --- 文本处理工具方法
|
|
413
|
+
...to_method_property_descriptors({
|
|
414
|
+
log(limit = 10000) {
|
|
415
|
+
const text = this.join('\n') + '\n';
|
|
416
|
+
if (limit === -1 || this.length <= limit)
|
|
417
|
+
console.log(text);
|
|
418
|
+
else if (limit > 0)
|
|
419
|
+
console.log(text.slice(0, limit) + '\n...'.blue);
|
|
420
|
+
else
|
|
421
|
+
console.log('...\n'.blue + text.slice(limit));
|
|
422
|
+
},
|
|
423
|
+
trim_lines({ trim_line = true, rm_empty_lines = true, rm_last_empty_lines = false } = {}) {
|
|
424
|
+
if (!this.length)
|
|
425
|
+
return this;
|
|
426
|
+
let lines = this;
|
|
427
|
+
if (trim_line)
|
|
428
|
+
lines = lines.map(line => line.trim());
|
|
429
|
+
if (rm_empty_lines)
|
|
430
|
+
return lines.filter(line => line);
|
|
431
|
+
if (rm_last_empty_lines) {
|
|
432
|
+
lines.reverse();
|
|
433
|
+
const i_not_empty = lines.findIndex(line => line);
|
|
434
|
+
if (i_not_empty !== -1)
|
|
435
|
+
lines = lines.slice(i_not_empty);
|
|
436
|
+
lines.reverse();
|
|
437
|
+
return lines;
|
|
438
|
+
}
|
|
436
439
|
return lines;
|
|
440
|
+
},
|
|
441
|
+
trim_license() {
|
|
442
|
+
const i = this.indexOf('/*');
|
|
443
|
+
const j = this.indexOf('*/');
|
|
444
|
+
if (i === 0 && this[i + 1].includes('License'))
|
|
445
|
+
return this.slice(j + 1);
|
|
446
|
+
else
|
|
447
|
+
return this;
|
|
448
|
+
},
|
|
449
|
+
split_indents() {
|
|
450
|
+
return this.map(line => line.split_indent());
|
|
451
|
+
},
|
|
452
|
+
indent(width, character = ' ') {
|
|
453
|
+
return this.map(line => character.repeat(width) + line);
|
|
454
|
+
},
|
|
455
|
+
indent2to4() {
|
|
456
|
+
return this.split_indents()
|
|
457
|
+
.map(line => ' '.repeat(Math.floor(line.indent / 2) * 4) + line.text);
|
|
458
|
+
},
|
|
459
|
+
join_lines(append = true) {
|
|
460
|
+
return `${this.join('\n')}${append ? '\n' : ''}`;
|
|
437
461
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
if (i === 0 && this[i + 1].includes('License'))
|
|
444
|
-
return this.slice(j + 1);
|
|
445
|
-
else
|
|
446
|
-
return this;
|
|
447
|
-
},
|
|
448
|
-
split_indents() {
|
|
449
|
-
return this.map(line => line.split_indent());
|
|
450
|
-
},
|
|
451
|
-
indent(width, character = ' ') {
|
|
452
|
-
return this.map(line => character.repeat(width) + line);
|
|
453
|
-
},
|
|
454
|
-
indent2to4() {
|
|
455
|
-
return this.split_indents()
|
|
456
|
-
.map(line => ' '.repeat(Math.floor(line.indent / 2) * 4) + line.text);
|
|
457
|
-
},
|
|
458
|
-
join_lines(append = true) {
|
|
459
|
-
return `${this.join('\n')}${append ? '\n' : ''}`;
|
|
462
|
+
})
|
|
463
|
+
});
|
|
464
|
+
Object.defineProperties(BigInt.prototype, to_method_property_descriptors({
|
|
465
|
+
toJSON() {
|
|
466
|
+
return this.toString();
|
|
460
467
|
}
|
|
461
|
-
})
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}));
|
|
468
|
-
|
|
469
|
-
toJSON() {
|
|
470
|
-
return Object.fromEntries(Object.getOwnPropertyNames(this)
|
|
471
|
-
.map(name => [name, this[name]]));
|
|
472
|
-
}
|
|
473
|
-
}));
|
|
468
|
+
}));
|
|
469
|
+
Object.defineProperties(Error.prototype, to_method_property_descriptors({
|
|
470
|
+
toJSON() {
|
|
471
|
+
return Object.fromEntries(Object.getOwnPropertyNames(this)
|
|
472
|
+
.map(name => [name, this[name]]));
|
|
473
|
+
}
|
|
474
|
+
}));
|
|
475
|
+
}
|
|
474
476
|
export function to_json(obj, replacer) {
|
|
475
477
|
return JSON.stringify(obj, replacer, 4) + '\n';
|
|
476
478
|
}
|