xshell 1.2.57 → 1.2.59

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.
@@ -0,0 +1,583 @@
1
+ import EmojiRegex from 'emoji-regex';
2
+ import { t } from "./i18n/instance.js";
3
+ export const emoji_regex = EmojiRegex();
4
+ export const noop = () => { };
5
+ export const ident = (x) => x;
6
+ export const select = (key) => (obj) => obj[key];
7
+ /** value 不为 null 或 undefined */
8
+ export const not_empty = (value) => value !== null && value !== undefined;
9
+ export const empty = (value) => value === undefined || value === null;
10
+ const key_types = ['string', 'number', 'symbol'];
11
+ export const is_key_type = ((key) => key_types.includes(typeof key));
12
+ export function rethrow(error) {
13
+ throw error;
14
+ }
15
+ export function to_snake_case(str) {
16
+ return str.replace(/([A-Z])/g, '_$1')
17
+ .toLowerCase()
18
+ .replace('-', '_')
19
+ .strip_if_start('_');
20
+ }
21
+ export function to_method_property_descriptors(methods) {
22
+ return Object.fromEntries(Object.entries(methods)
23
+ .map(([name, value]) => ([name, {
24
+ configurable: true,
25
+ writable: true,
26
+ enumerable: false,
27
+ value,
28
+ }])));
29
+ }
30
+ export function to_getter_property_descriptors(getters) {
31
+ return Object.fromEntries(Object.entries(getters)
32
+ .map(([name, get]) => ([name, {
33
+ configurable: true,
34
+ enumerable: false,
35
+ get,
36
+ }])));
37
+ }
38
+ export const cjk = '([\u2e80-\u9fff\uf900-\ufaff])';
39
+ export const quotes = {
40
+ single: "'",
41
+ double: '"',
42
+ backtick: '`',
43
+ };
44
+ export const brackets = {
45
+ round: ['(', ')'],
46
+ square: ['[', ']'],
47
+ curly: ['{', '}'],
48
+ pointy: ['<', '>'],
49
+ corner: ['「', '」'],
50
+ fat: ['【', '】'],
51
+ tortoise_shell: ['〔', '〕'],
52
+ };
53
+ if (!globalThis.my_prototype_defined) {
54
+ // ------------------------------------ String.prototype
55
+ Object.defineProperties(String.prototype, {
56
+ // ------------ 文本处理工具方法
57
+ ...to_method_property_descriptors({
58
+ pad(width, { character = ' ', position = 'right' } = {}) {
59
+ const _width = this.width;
60
+ if (_width >= width)
61
+ return this;
62
+ if (position === 'right')
63
+ return this + character.repeat((width - _width) / character.width);
64
+ return character.repeat(width - _width) + this;
65
+ },
66
+ limit(width, { character = ' ', position = 'right' } = {}) {
67
+ return this.pad(width, { character, position }).truncate(width);
68
+ },
69
+ to_regexp(preservations, flags = '') {
70
+ const preserved_chars = new Set(preservations);
71
+ const replace_chars = Array.prototype.filter.call('|\\{}()[]^$+*?.-', (c) => !preserved_chars.has(c))
72
+ .map((c) => c === ']' ? '\\]' : c).join('');
73
+ return new RegExp(this.replace(new RegExp(`[${replace_chars}]`, 'g'), '\\$&'), flags);
74
+ },
75
+ to_snake_case() {
76
+ return to_snake_case(this);
77
+ },
78
+ refmt(pattern, pattern_, preservations = '', flags = '', transformer = (name, value) => value || '', pattern_placeholder = /\{.*?\}/g) {
79
+ // --- 转换 pattern 为 pattern_regx
80
+ let last_end = 0;
81
+ // placeholder matched group indexes
82
+ let $placeholders = {};
83
+ let regx_parts = [];
84
+ function add_part(left, right) {
85
+ const part = pattern.slice(left, right);
86
+ if (part)
87
+ regx_parts.push(part.to_regexp(preservations).source.bracket());
88
+ }
89
+ pattern.replace(pattern_placeholder, ($0, offset) => {
90
+ add_part(last_end, offset);
91
+ last_end = offset + $0.length;
92
+ const placeholder = $0.slice(1, -1);
93
+ let [placeholder_name, placeholder_pattern] = placeholder.split(':').map(s => s.trim());
94
+ let optional = false;
95
+ if (placeholder_name.endsWith('?')) {
96
+ placeholder_name = placeholder_name.slice(0, -1);
97
+ optional = true;
98
+ }
99
+ $placeholders[placeholder_name] = regx_parts.push(placeholder_pattern ?
100
+ `${placeholder_pattern.bracket()}${optional ? '?' : ''}`
101
+ :
102
+ '(.*?)');
103
+ return '';
104
+ });
105
+ add_part(last_end);
106
+ // 最后一个 (.*?) 改为贪心匹配,满足 .{suffix} 的需要
107
+ regx_parts = regx_parts.filter(part => part);
108
+ if (regx_parts[regx_parts.length - 1] === '(.*?)')
109
+ regx_parts[regx_parts.length - 1] = '(.*)';
110
+ const pattern_regx = new RegExp(regx_parts.join(''), flags);
111
+ // --- 根据 pattern_regx 去匹配原有字符串,获取匹配结果,生成 placeholders 词典
112
+ const matches = pattern_regx.exec(this);
113
+ if (!matches)
114
+ return this;
115
+ const placeholders = Object.fromEntries(Object.entries($placeholders)
116
+ .map(([name, $i]) => [
117
+ [name, matches[$i]],
118
+ [`${name}.before`, matches[$i - 1] || ''],
119
+ [`${name}.after`, matches[$i + 1] || ''],
120
+ ])
121
+ .flat());
122
+ // --- 转换 pattern_ 为 replacement_str,如果有 transformer 则在遇到 placeholder 时应用
123
+ last_end = 0;
124
+ let replacement_parts = [];
125
+ pattern_.replace(pattern_placeholder, ($0, offset) => {
126
+ replacement_parts.push(pattern_.slice(last_end, offset));
127
+ last_end = offset + $0.length;
128
+ const placeholder_name = $0.slice(1, -1);
129
+ replacement_parts.push(transformer(placeholder_name, placeholders[placeholder_name], placeholders));
130
+ return '';
131
+ });
132
+ replacement_parts.push(pattern_.slice(last_end));
133
+ return this.replace(pattern_regx, replacement_parts.join(''));
134
+ },
135
+ find(pattern, preservations = '', flags = '', pattern_placeholder = /\{.*?\}/g) {
136
+ // --- 转换 pattern 为 pattern_regx
137
+ let last_end = 0;
138
+ // placeholder matched group index
139
+ let $placeholders = {};
140
+ let regx_parts = [];
141
+ function add_part(left, right) {
142
+ const part = pattern.slice(left, right);
143
+ if (part)
144
+ regx_parts.push(part.to_regexp(preservations).source.bracket());
145
+ }
146
+ pattern.replace(pattern_placeholder, ($0, offset) => {
147
+ add_part(last_end, offset);
148
+ last_end = offset + $0.length;
149
+ const placeholder = $0.slice(1, -1);
150
+ let [placeholder_name, placeholder_pattern] = placeholder.split(':').map(s => s.trim());
151
+ let optional = false;
152
+ if (placeholder_name.endsWith('?')) {
153
+ placeholder_name = placeholder_name.slice(0, -1);
154
+ optional = true;
155
+ }
156
+ $placeholders[placeholder_name] = regx_parts.push(placeholder_pattern ?
157
+ `${placeholder_pattern.bracket()}${optional ? '?' : ''}`
158
+ :
159
+ '(.*?)');
160
+ return '';
161
+ });
162
+ add_part(last_end);
163
+ // 最后一个 (.*?) 改为贪心匹配,满足 .{suffix} 的需要
164
+ regx_parts = regx_parts.filter(part => part);
165
+ if (regx_parts[regx_parts.length - 1] === '(.*?)')
166
+ regx_parts[regx_parts.length - 1] = '(.*)';
167
+ const pattern_regx = new RegExp(regx_parts.join(''), flags);
168
+ // --- 根据 pattern_regx 去匹配原有字符串,获取匹配结果,生成 placeholders 词典
169
+ const matches = pattern_regx.exec(this);
170
+ if (!matches)
171
+ return {};
172
+ return Object.fromEntries(Object.entries($placeholders)
173
+ .map(([name, $i]) => [name, matches[$i] || '']));
174
+ },
175
+ /** 查找子串或字符出现的次数 */
176
+ count(search) {
177
+ if (!search)
178
+ throw new Error('count 的 search 不能为空');
179
+ let count = 0;
180
+ for (let i = 0; (i = this.indexOf(search, i)) !== -1; i += search.length)
181
+ count++;
182
+ return count;
183
+ },
184
+ quote(type = 'single') {
185
+ if (type === 'psh')
186
+ return `& ${this.quote()}`;
187
+ return this.surround(quotes[type]);
188
+ },
189
+ bracket(shape = 'round') {
190
+ return this.surround(...brackets[shape]);
191
+ },
192
+ surround(left, right) {
193
+ return left + this + (right || left);
194
+ },
195
+ surround_tag(tag_name) {
196
+ return '<' + tag_name + '>' + this + '</' + tag_name + '>';
197
+ },
198
+ to_lf() {
199
+ return this.replace(/\r\n/g, '\n');
200
+ },
201
+ rm(pattern, flags = 'g') {
202
+ if (typeof pattern === 'string')
203
+ pattern = new RegExp(pattern, flags);
204
+ return this.replace(pattern, '');
205
+ },
206
+ split_lines(delimiter = /\r?\n/) {
207
+ let lines = this.split(delimiter);
208
+ if (lines[lines.length - 1] === '')
209
+ lines.pop();
210
+ return lines;
211
+ },
212
+ split_indent() {
213
+ let i = 0;
214
+ let indent = 0;
215
+ for (; i < this.length; i++)
216
+ if (this[i] === ' ')
217
+ indent++;
218
+ else if (this[i] === '\t')
219
+ indent += 4;
220
+ else
221
+ break;
222
+ return {
223
+ indent,
224
+ text: this.slice(i)
225
+ };
226
+ },
227
+ split2(splitter, { last = false, optional = false } = {}) {
228
+ const isplitter = last ? this.lastIndexOf(splitter) : this.indexOf(splitter);
229
+ if (isplitter === -1)
230
+ if (optional)
231
+ return [this];
232
+ else
233
+ throw new Error(`字符串: ${this} 必须包含 splitter: ${splitter}`);
234
+ return [this.slice(0, isplitter), this.slice(isplitter + splitter.length)];
235
+ },
236
+ strip_start(prefix, validate) {
237
+ if (validate && !this.startsWith(prefix))
238
+ throw new Error(`字符串没有以前缀 ${prefix} 开头: ${this}`);
239
+ return this.slice(prefix.length);
240
+ },
241
+ strip_if_start(prefix) {
242
+ return this.startsWith(prefix) ? this.slice(prefix.length) : this;
243
+ },
244
+ strip_end(suffix, validate) {
245
+ if (validate && !this.endsWith(suffix))
246
+ throw new Error(`字符串没有以后缀 ${suffix} 结尾: ${this}`);
247
+ return this.slice(0, -suffix.length);
248
+ },
249
+ strip_if_end(suffix) {
250
+ return this.endsWith(suffix) ? this.slice(0, -suffix.length) : this;
251
+ },
252
+ ensure_start(prefix) {
253
+ return this.startsWith(prefix) ? this : prefix + this;
254
+ },
255
+ ensure_end(suffix = '\n') {
256
+ return this.endsWith(suffix) ? this : this + suffix;
257
+ },
258
+ slice_from(search, { include = false, last = false, optional = false } = {}) {
259
+ const i = last ? this.lastIndexOf(search) : this.indexOf(search);
260
+ if (i === -1)
261
+ if (optional)
262
+ return this;
263
+ else
264
+ throw new Error(`slice_from 在字符串 ${this} 中找不到 search: ${search}`);
265
+ else
266
+ return this.slice(include ? i : i + search.length);
267
+ },
268
+ slice_to(search, { include = false, last = false, optional = false } = {}) {
269
+ const i = last ? this.lastIndexOf(search) : this.indexOf(search);
270
+ if (i === -1)
271
+ if (optional)
272
+ return this;
273
+ else
274
+ throw new Error(`slice_to 在字符串 ${this} 中找不到 search: ${search}`);
275
+ else
276
+ return this.slice(0, include ? i + search.length : i);
277
+ },
278
+ }),
279
+ // ------------ 文件路径操作
280
+ ...to_getter_property_descriptors({
281
+ isdir() {
282
+ return this.endsWith('/');
283
+ },
284
+ fp() {
285
+ if (!this)
286
+ return this;
287
+ const fp = this.replaceAll('\\', '/');
288
+ // 转换小写盘符开头的路径
289
+ return fp[1] === ':' && 'a' <= fp[0] && fp[0] <= 'z'
290
+ ? fp[0].toUpperCase() + fp.slice(1)
291
+ : fp;
292
+ },
293
+ fpd() {
294
+ const { fp } = this;
295
+ return fp.endsWith('/') ? fp : `${fp}/`;
296
+ },
297
+ fdir() {
298
+ return this.fp.strip_end(this.fname);
299
+ },
300
+ fname() {
301
+ const { fp } = this;
302
+ const ilast = fp.lastIndexOf('/');
303
+ if (ilast === -1)
304
+ return fp; // 没有斜杠时返回整个字符串
305
+ // 以斜杠结尾的情况
306
+ if (ilast === fp.length - 1) {
307
+ const iprev = fp.lastIndexOf('/', ilast - 1);
308
+ return iprev === -1
309
+ ? fp // 只有一个斜杠且在末尾
310
+ : fp.slice(iprev + 1);
311
+ }
312
+ // 返回最后一个斜杠后的内容
313
+ return fp.slice(ilast + 1);
314
+ },
315
+ fext() {
316
+ const { fname } = this;
317
+ const index = fname.lastIndexOf('.');
318
+ return index <= 0
319
+ ? ''
320
+ : fname.slice(index + 1);
321
+ }
322
+ })
323
+ });
324
+ // ------------------------------------ Date.prototype
325
+ Object.defineProperties(Date.prototype, to_method_property_descriptors({
326
+ to_str(ms) {
327
+ return `${this.to_date_str()} ${this.to_time_str(ms)}`;
328
+ },
329
+ to_date_str() {
330
+ // 2024.01.01
331
+ return this.getFullYear() + '.' +
332
+ String(this.getMonth() + 1).padStart(2, '0') + '.' +
333
+ String(this.getDate()).padStart(2, '0');
334
+ },
335
+ to_time_str(ms) {
336
+ // 早上 09:00:00
337
+ const [ampm, hour] = get_twelve_hour_clock(this);
338
+ return `${ampm} ${get_time_str(this, hour, ms, ':')}`;
339
+ },
340
+ to_dot_time_str(ms) {
341
+ // 17.03.02
342
+ return get_time_str(this, this.getHours(), ms, '.');
343
+ },
344
+ to_dot_str(ms) {
345
+ return `${this.to_date_str()} ${this.to_dot_time_str(ms)}`;
346
+ },
347
+ to_formal_time_str(ms) {
348
+ // 17:03:02
349
+ return get_time_str(this, this.getHours(), ms, ':');
350
+ },
351
+ to_formal_str(ms) {
352
+ return `${this.to_date_str()} ${this.to_formal_time_str(ms)}`;
353
+ }
354
+ }));
355
+ function get_twelve_hour_clock(date) {
356
+ let hour = date.getHours();
357
+ if (hour <= 6)
358
+ return [t('凌晨'), hour];
359
+ if (hour <= 8)
360
+ return [t('清晨'), hour];
361
+ if (hour <= 9)
362
+ return [t('早上'), hour];
363
+ if (hour <= 10)
364
+ return [t('上午'), hour];
365
+ if (hour <= 12)
366
+ return [t('中午'), hour];
367
+ hour -= 12;
368
+ if (hour <= 5)
369
+ return [t('下午'), hour];
370
+ if (hour <= 10)
371
+ return [t('晚上'), hour];
372
+ return [t('深夜'), hour];
373
+ }
374
+ function get_time_str(date, hour, ms, splitter) {
375
+ return String(hour).padStart(2, '0') + splitter +
376
+ String(date.getMinutes()).padStart(2, '0') + splitter +
377
+ String(date.getSeconds()).padStart(2, '0') +
378
+ (ms
379
+ ? '.' + String(date.getMilliseconds()).padStart(3, '0')
380
+ : '');
381
+ }
382
+ // ------------------------------------ Number.prototype
383
+ Object.defineProperties(Number.prototype, to_method_property_descriptors({
384
+ to_fsize_str() {
385
+ return byte_size(this);
386
+ },
387
+ to_bin_str() {
388
+ return `0b${this.toString(2)}`;
389
+ },
390
+ to_hex_str(length) {
391
+ const s = Math.abs(this).toString(16);
392
+ // 长度自动对齐到 4 的倍数
393
+ if (length === undefined)
394
+ length = Math.ceil(s.length / 4) * 4;
395
+ return `${this < 0 ? '-' : ''}0x${'0'.repeat(length - s.length)}${s}`;
396
+ },
397
+ to_oct_str() {
398
+ return `0o${this.toString(8)}`;
399
+ },
400
+ }));
401
+ // ------------------------------------ Array.prototype
402
+ Object.defineProperties(Array.prototype, {
403
+ ...to_getter_property_descriptors({
404
+ last() {
405
+ return this.at(-1);
406
+ }
407
+ }),
408
+ // --- 文本处理工具方法
409
+ ...to_method_property_descriptors({
410
+ trim_lines({ trim_line = true, rm_empty_lines = true, rm_last_empty_lines = false } = {}) {
411
+ if (!this.length)
412
+ return this;
413
+ let lines = this;
414
+ if (trim_line)
415
+ lines = lines.map(line => line.trim());
416
+ if (rm_empty_lines)
417
+ return lines.filter(Boolean);
418
+ if (rm_last_empty_lines) {
419
+ lines.reverse();
420
+ const i_not_empty = lines.findIndex(Boolean);
421
+ if (i_not_empty !== -1)
422
+ lines = lines.slice(i_not_empty);
423
+ lines.reverse();
424
+ return lines;
425
+ }
426
+ return lines;
427
+ },
428
+ indent(width = 4, character = ' ') {
429
+ const indent = character.repeat(width);
430
+ return this.map(line => indent + line);
431
+ },
432
+ sum(zero, mapper) {
433
+ if (!this.length)
434
+ return undefined;
435
+ // 快捷路径
436
+ const first = this[0];
437
+ if ((typeof first === 'number' || typeof first === 'bigint') && !mapper)
438
+ return this.reduce((acc, x) => acc + x, zero);
439
+ if (is_key_type(mapper))
440
+ mapper = select(mapper);
441
+ mapper ??= ident;
442
+ return this.reduce((acc, x) => acc + mapper(x), zero);
443
+ },
444
+ max(mapper = ident) {
445
+ if (!this.length)
446
+ return undefined;
447
+ if (is_key_type(mapper))
448
+ mapper = select(mapper);
449
+ let max = mapper(this[0]);
450
+ let imax = 0;
451
+ for (let i = 0; i < this.length; i++) {
452
+ const value = mapper(this[i]);
453
+ if (value > max) {
454
+ max = value;
455
+ imax = i;
456
+ }
457
+ }
458
+ return this[imax];
459
+ },
460
+ min(mapper = ident) {
461
+ if (!this.length)
462
+ return undefined;
463
+ if (is_key_type(mapper))
464
+ mapper = select(mapper);
465
+ let min = mapper(this[0]);
466
+ let imin = 0;
467
+ for (let i = 0; i < this.length; i++) {
468
+ const value = mapper(this[i]);
469
+ if (value < min) {
470
+ min = value;
471
+ imin = i;
472
+ }
473
+ }
474
+ return this[imin];
475
+ },
476
+ unique(mapper) {
477
+ if (!mapper)
478
+ return [...new Set(this)];
479
+ if (is_key_type(mapper))
480
+ mapper = select(mapper);
481
+ let map = new Map();
482
+ for (const x of this)
483
+ map.set(mapper(x), x);
484
+ return [...map.values()];
485
+ },
486
+ join_lines(append = Boolean(this.length)) {
487
+ return `${this.join('\n')}${append ? '\n' : ''}`;
488
+ }
489
+ })
490
+ });
491
+ Object.defineProperties(BigInt.prototype, to_method_property_descriptors({
492
+ to_fsize_str() {
493
+ return byte_size(this);
494
+ },
495
+ toJSON() {
496
+ return this.toString();
497
+ }
498
+ }));
499
+ Object.defineProperties(Error.prototype, to_method_property_descriptors({
500
+ toJSON() {
501
+ return Object.fromEntries(Object.getOwnPropertyNames(this)
502
+ .map(name => [name, this[name]]));
503
+ }
504
+ }));
505
+ Object.defineProperties(Set.prototype, to_method_property_descriptors({
506
+ map(mapfn) {
507
+ return Array.from(this, mapfn);
508
+ }
509
+ }));
510
+ Object.defineProperties(Uint8Array.prototype, to_getter_property_descriptors({
511
+ dataview() {
512
+ return new DataView(this.buffer, this.byteOffset, this.byteLength);
513
+ }
514
+ }));
515
+ }
516
+ export function to_json(obj, replacer) {
517
+ return JSON.stringify(obj, replacer, 4) + '\n';
518
+ }
519
+ export function to_json_safely(obj, replacer) {
520
+ return to_json(obj, replacer)
521
+ .replace(/\u2028/g, '\\u2028')
522
+ .replace(/\u2029/g, '\\u2029')
523
+ .replace(/<\/script>/g, '<\\/script>');
524
+ }
525
+ const units = ['b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb'];
526
+ const bytes_table = units.map((unit, i) => ({
527
+ start: i === 0 ? 0 : 2 ** (i * 10),
528
+ end: 2 ** ((i + 1) * 10),
529
+ unit
530
+ }));
531
+ export function byte_size(bytes) {
532
+ bytes = Number(bytes);
533
+ const sign = bytes < 0 ? '-' : '';
534
+ bytes = Math.abs(bytes);
535
+ const { unit, start } = bytes_table.find(range => bytes >= range.start && bytes < range.end);
536
+ return `${sign}${start === 0 ? bytes : (bytes / start).toFixed()} ${unit}`;
537
+ }
538
+ export function is_codepoint_fullwidth(codepoint) {
539
+ // code points are derived from:
540
+ // http://www.unix.org/Public/UNIDATA/EastAsianWidth.txt
541
+ return (!Number.isNaN(codepoint) &&
542
+ codepoint >= 0x1100 &&
543
+ (codepoint <= 0x115f || // hangul jamo
544
+ codepoint === 0x201c || codepoint === 0x201d || //
545
+ codepoint === 0x2026 || // …
546
+ codepoint === 0x203b || // ※
547
+ // arrows
548
+ (0x2190 <= codepoint && codepoint <= 0x21FF) ||
549
+ codepoint === 0x2329 || // left-pointing angle bracket
550
+ codepoint === 0x232a || // right-pointing angle bracket
551
+ // ①
552
+ (0x2460 <= codepoint && codepoint <= 0x24ff) ||
553
+ // box drawing
554
+ (0x2500 <= codepoint && codepoint <= 0x257f) ||
555
+ // shapes, symbols, …
556
+ (0x2580 <= codepoint && codepoint <= 0x2bef) ||
557
+ // cjk radicals supplement .. enclosed cjk letters and months
558
+ (0x2e80 <= codepoint && codepoint <= 0x3247 && codepoint !== 0x303f) ||
559
+ // enclosed cjk letters and months .. cjk unified ideographs extension a
560
+ (0x3250 <= codepoint && codepoint <= 0x4dbf) ||
561
+ // cjk unified ideographs .. yi radicals
562
+ (0x4E00 <= codepoint && codepoint <= 0xA4C6) ||
563
+ // hangul jamo extended-a
564
+ (0xa960 <= codepoint && codepoint <= 0xa97c) ||
565
+ // hangul syllables
566
+ (0xac00 <= codepoint && codepoint <= 0xd7a3) ||
567
+ // cjk compatibility ideographs
568
+ (0xf900 <= codepoint && codepoint <= 0xfaff) ||
569
+ // vertical forms
570
+ (0xfe10 <= codepoint && codepoint <= 0xfe19) ||
571
+ // cjk compatibility forms .. small form variants
572
+ (0xfe30 <= codepoint && codepoint <= 0xfe6b) ||
573
+ // halfwidth and fullwidth forms
574
+ (0xff01 <= codepoint && codepoint <= 0xff60) ||
575
+ (0xffe0 <= codepoint && codepoint <= 0xffe6) ||
576
+ // kana supplement
577
+ (0x1b000 <= codepoint && codepoint <= 0x1b001) ||
578
+ // enclosed ideographic supplement
579
+ (0x1f200 <= codepoint && codepoint <= 0x1f251) ||
580
+ // cjk unified ideographs extension b .. tertiary ideographic plane
581
+ (0x20000 <= codepoint && codepoint <= 0x3fffd)));
582
+ }
583
+ //# sourceMappingURL=prototype.common.js.map