xshell 0.0.69 → 0.0.71

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/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
- // ------------------------------------ String.prototype
44
- Object.defineProperties(String.prototype, {
45
- ...to_getter_property_descriptors({
46
- width() {
47
- const s = strip_ansi(this.replace(emoji_regex, ' '));
48
- let width = 0;
49
- for (let i = 0; i < s.length; i++) {
50
- const code = s.codePointAt(i);
51
- if ((code <= 0x1f || (code >= 0x7f && code <= 0x9f)) || // ignore control characters
52
- code >= 0x300 && code <= 0x36f // ignore combining characters
53
- )
54
- continue;
55
- // surrogates
56
- if (code > 0xffff)
57
- i++;
58
- width += is_codepoint_fullwidth(code) ? 2 : 1;
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
- return this;
100
- },
101
- pad(width, { character = ' ', position = 'right' } = {}) {
102
- const _width = this.width;
103
- if (_width >= width)
104
- return this;
105
- if (position === 'right')
106
- return this + character.repeat((width - _width) / character.width);
107
- return character.repeat(width - _width) + this;
108
- },
109
- limit(width, { character = ' ', position = 'right' } = {}) {
110
- return this.pad(width, { character, position }).truncate(width);
111
- },
112
- to_regexp(preservations, flags = '') {
113
- const preserved_chars = new Set(preservations);
114
- const replace_chars = Array.prototype.filter.call('|\\{}()[]^$+*?.-', (c) => !preserved_chars.has(c))
115
- .map((c) => c === ']' ? '\\]' : c).join('');
116
- return new RegExp(this.replace(new RegExp(`[${replace_chars}]`, 'g'), '\\$&'), flags);
117
- },
118
- to_bool() {
119
- return this.length && this !== '0' && this.toLowerCase() !== 'false';
120
- },
121
- refmt(pattern, pattern_, preservations = '', flags = '', transformer = (name, value) => value || '', pattern_placeholder = /\{.*?\}/g) {
122
- // --- 转换 pattern 为 pattern_regx
123
- let last_end = 0;
124
- // placeholder matched group indexes
125
- let $placeholders = {};
126
- let regx_parts = [];
127
- function add_part(left, right) {
128
- const part = pattern.slice(left, right);
129
- if (part)
130
- regx_parts.push(part.to_regexp(preservations).source.bracket());
131
- }
132
- pattern.replace(pattern_placeholder, ($0, offset) => {
133
- add_part(last_end, offset);
134
- last_end = offset + $0.length;
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
- const placeholders = Object.fromEntries(Object.entries($placeholders)
159
- .map(([name, $i]) => [
160
- [name, matches[$i]],
161
- [`${name}.before`, matches[$i - 1] || ''],
162
- [`${name}.after`, matches[$i + 1] || ''],
163
- ])
164
- .flat());
165
- // --- 转换 pattern_ replacement_str,如果有 transformer 则在遇到 placeholder 时应用
166
- last_end = 0;
167
- let replacement_parts = [];
168
- pattern_.replace(pattern_placeholder, ($0, offset) => {
169
- replacement_parts.push(pattern_.slice(last_end, offset));
170
- last_end = offset + $0.length;
171
- const placeholder_name = $0.slice(1, -1);
172
- replacement_parts.push(transformer(placeholder_name, placeholders[placeholder_name], placeholders));
173
- return '';
174
- });
175
- replacement_parts.push(pattern_.slice(last_end));
176
- return this.replace(pattern_regx, replacement_parts.join(''));
177
- },
178
- find(pattern, preservations = '', flags = '', pattern_placeholder = /\{.*?\}/g) {
179
- // --- 转换 pattern pattern_regx
180
- let last_end = 0;
181
- // placeholder matched group index
182
- let $placeholders = {};
183
- let regx_parts = [];
184
- function add_part(left, right) {
185
- const part = pattern.slice(left, right);
186
- if (part)
187
- regx_parts.push(part.to_regexp(preservations).source.bracket());
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
- pattern.replace(pattern_placeholder, ($0, offset) => {
190
- add_part(last_end, offset);
191
- last_end = offset + $0.length;
192
- const placeholder = $0.slice(1, -1);
193
- let [placeholder_name, placeholder_pattern] = placeholder.split(':').map(s => s.trim());
194
- let optional = false;
195
- if (placeholder_name.endsWith('?')) {
196
- placeholder_name = placeholder_name.slice(0, -1);
197
- optional = true;
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
- $placeholders[placeholder_name] = regx_parts.push(placeholder_pattern ?
200
- `${placeholder_pattern.bracket()}${optional ? '?' : ''}`
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
- surround_tag(tag_name) {
230
- return '<' + tag_name + '>' + this + '</' + tag_name + '>';
377
+ to_date_str() {
378
+ return this.to_str().split(' ')[0];
231
379
  },
232
- to_lf() {
233
- return this.replace(/\r\n/g, '\n');
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
- trim_doc_comment() {
265
- return `/** ${this.slice(3, -2).replace(/\s*\*\s*/g, ' ').replace(/@(param|params|return) \{.*?\}\s*/g, '').trim()} */`;
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
- to_base64() {
268
- return Buffer.from(this).toString('base64');
391
+ to_bin_str() {
392
+ return `0b${this.toString(2)}`;
269
393
  },
270
- decode_base64(buffer = false) {
271
- const buf = Buffer.from(this, 'base64');
272
- if (buffer)
273
- return buf;
274
- return buf.toString();
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
- strip_ansi() {
277
- return strip_ansi(this);
401
+ to_oct_str() {
402
+ return `0o${this.toString(8)}`;
278
403
  },
279
- space() {
280
- if (!this)
281
- return this;
282
- let text_;
283
- text_ = this
284
- .replace(new RegExp(cjk + `(['"])`, 'g'), '$1 $2')
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
- ...to_getter_property_descriptors({
315
- fdir() {
316
- const dir = path.dirname(this);
317
- return dir.endsWith('/') ? dir : `${dir}/`;
318
- },
319
- fname() {
320
- return path.basename(this);
321
- },
322
- fext() {
323
- return path.extname(this);
324
- },
325
- }),
326
- ...to_method_property_descriptors({
327
- to_slash() {
328
- if (!this)
329
- return this;
330
- return path.normalizeSafe(this);
331
- },
332
- to_backslash() {
333
- return this.replaceAll('/', '\\');
334
- },
335
- })
336
- });
337
- // ------------------------------------ Date.prototype
338
- Object.defineProperties(Date.prototype, to_method_property_descriptors({
339
- to_str(ms) {
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
- return lines;
439
- },
440
- trim_license() {
441
- const i = this.indexOf('/*');
442
- const j = this.indexOf('*/');
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
- Object.defineProperties(BigInt.prototype, to_method_property_descriptors({
464
- toJSON() {
465
- return this.toString();
466
- }
467
- }));
468
- Object.defineProperties(Error.prototype, to_method_property_descriptors({
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
  }