@jsenv/core 41.2.6 → 41.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/jsenv_core_node_modules.js +14 -22
- package/dist/build/jsenv_core_packages.js +135 -52
- package/dist/start_build_server/jsenv_core_node_modules.js +14 -22
- package/dist/start_build_server/jsenv_core_packages.js +135 -52
- package/dist/start_dev_server/jsenv_core_node_modules.js +14 -22
- package/dist/start_dev_server/jsenv_core_packages.js +135 -52
- package/package.json +5 -5
|
@@ -252,19 +252,18 @@ function stripAnsi(string) {
|
|
|
252
252
|
return string.replace(regex, '');
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
const r = String.raw,
|
|
256
|
-
e = r`\p{Emoji}(?:\p{EMod}|[\u{E0020}-\u{E007E}]+\u{E007F}|\uFE0F?\u20E3?)`;
|
|
257
|
-
const emojiRegex = () => new RegExp(r`\p{RI}{2}|(?)${e}(?:\u200D${e})*`, 'gu');
|
|
258
|
-
|
|
259
255
|
// Generated by scripts/build.js
|
|
260
256
|
|
|
261
|
-
|
|
257
|
+
const ambiguousMinimalCodePoint = 161;
|
|
258
|
+
const ambiguousMaximumCodePoint = 1114109;
|
|
262
259
|
const ambiguousRanges = [161, 161, 164, 164, 167, 168, 170, 170, 173, 174, 176, 180, 182, 186, 188, 191, 198, 198, 208, 208, 215, 216, 222, 225, 230, 230, 232, 234, 236, 237, 240, 240, 242, 243, 247, 250, 252, 252, 254, 254, 257, 257, 273, 273, 275, 275, 283, 283, 294, 295, 299, 299, 305, 307, 312, 312, 319, 322, 324, 324, 328, 331, 333, 333, 338, 339, 358, 359, 363, 363, 462, 462, 464, 464, 466, 466, 468, 468, 470, 470, 472, 472, 474, 474, 476, 476, 593, 593, 609, 609, 708, 708, 711, 711, 713, 715, 717, 717, 720, 720, 728, 731, 733, 733, 735, 735, 768, 879, 913, 929, 931, 937, 945, 961, 963, 969, 1025, 1025, 1040, 1103, 1105, 1105, 8208, 8208, 8211, 8214, 8216, 8217, 8220, 8221, 8224, 8226, 8228, 8231, 8240, 8240, 8242, 8243, 8245, 8245, 8251, 8251, 8254, 8254, 8308, 8308, 8319, 8319, 8321, 8324, 8364, 8364, 8451, 8451, 8453, 8453, 8457, 8457, 8467, 8467, 8470, 8470, 8481, 8482, 8486, 8486, 8491, 8491, 8531, 8532, 8539, 8542, 8544, 8555, 8560, 8569, 8585, 8585, 8592, 8601, 8632, 8633, 8658, 8658, 8660, 8660, 8679, 8679, 8704, 8704, 8706, 8707, 8711, 8712, 8715, 8715, 8719, 8719, 8721, 8721, 8725, 8725, 8730, 8730, 8733, 8736, 8739, 8739, 8741, 8741, 8743, 8748, 8750, 8750, 8756, 8759, 8764, 8765, 8776, 8776, 8780, 8780, 8786, 8786, 8800, 8801, 8804, 8807, 8810, 8811, 8814, 8815, 8834, 8835, 8838, 8839, 8853, 8853, 8857, 8857, 8869, 8869, 8895, 8895, 8978, 8978, 9312, 9449, 9451, 9547, 9552, 9587, 9600, 9615, 9618, 9621, 9632, 9633, 9635, 9641, 9650, 9651, 9654, 9655, 9660, 9661, 9664, 9665, 9670, 9672, 9675, 9675, 9678, 9681, 9698, 9701, 9711, 9711, 9733, 9734, 9737, 9737, 9742, 9743, 9756, 9756, 9758, 9758, 9792, 9792, 9794, 9794, 9824, 9825, 9827, 9829, 9831, 9834, 9836, 9837, 9839, 9839, 9886, 9887, 9919, 9919, 9926, 9933, 9935, 9939, 9941, 9953, 9955, 9955, 9960, 9961, 9963, 9969, 9972, 9972, 9974, 9977, 9979, 9980, 9982, 9983, 10045, 10045, 10102, 10111, 11094, 11097, 12872, 12879, 57344, 63743, 65024, 65039, 65533, 65533, 127232, 127242, 127248, 127277, 127280, 127337, 127344, 127373, 127375, 127376, 127387, 127404, 917760, 917999, 983040, 1048573, 1048576, 1114109];
|
|
263
260
|
|
|
264
|
-
|
|
261
|
+
const fullwidthMinimalCodePoint = 12288;
|
|
262
|
+
const fullwidthMaximumCodePoint = 65510;
|
|
265
263
|
const fullwidthRanges = [12288, 12288, 65281, 65376, 65504, 65510];
|
|
266
264
|
|
|
267
|
-
|
|
265
|
+
const wideMinimalCodePoint = 4352;
|
|
266
|
+
const wideMaximumCodePoint = 262141;
|
|
268
267
|
const wideRanges = [4352, 4447, 8986, 8987, 9001, 9002, 9193, 9196, 9200, 9200, 9203, 9203, 9725, 9726, 9748, 9749, 9776, 9783, 9800, 9811, 9855, 9855, 9866, 9871, 9875, 9875, 9889, 9889, 9898, 9899, 9917, 9918, 9924, 9925, 9934, 9934, 9940, 9940, 9962, 9962, 9970, 9971, 9973, 9973, 9978, 9978, 9981, 9981, 9989, 9989, 9994, 9995, 10024, 10024, 10060, 10060, 10062, 10062, 10067, 10069, 10071, 10071, 10133, 10135, 10160, 10160, 10175, 10175, 11035, 11036, 11088, 11088, 11093, 11093, 11904, 11929, 11931, 12019, 12032, 12245, 12272, 12287, 12289, 12350, 12353, 12438, 12441, 12543, 12549, 12591, 12593, 12686, 12688, 12773, 12783, 12830, 12832, 12871, 12880, 42124, 42128, 42182, 43360, 43388, 44032, 55203, 63744, 64255, 65040, 65049, 65072, 65106, 65108, 65126, 65128, 65131, 94176, 94180, 94192, 94198, 94208, 101589, 101631, 101662, 101760, 101874, 110576, 110579, 110581, 110587, 110589, 110590, 110592, 110882, 110898, 110898, 110928, 110930, 110933, 110933, 110948, 110951, 110960, 111355, 119552, 119638, 119648, 119670, 126980, 126980, 127183, 127183, 127374, 127374, 127377, 127386, 127488, 127490, 127504, 127547, 127552, 127560, 127568, 127569, 127584, 127589, 127744, 127776, 127789, 127797, 127799, 127868, 127870, 127891, 127904, 127946, 127951, 127955, 127968, 127984, 127988, 127988, 127992, 128062, 128064, 128064, 128066, 128252, 128255, 128317, 128331, 128334, 128336, 128359, 128378, 128378, 128405, 128406, 128420, 128420, 128507, 128591, 128640, 128709, 128716, 128716, 128720, 128722, 128725, 128728, 128732, 128735, 128747, 128748, 128756, 128764, 128992, 129003, 129008, 129008, 129292, 129338, 129340, 129349, 129351, 129535, 129648, 129660, 129664, 129674, 129678, 129734, 129736, 129736, 129741, 129756, 129759, 129770, 129775, 129784, 131072, 196605, 196608, 262141];
|
|
269
268
|
|
|
270
269
|
/**
|
|
@@ -292,15 +291,8 @@ const isInRange = (ranges, codePoint) => {
|
|
|
292
291
|
return false;
|
|
293
292
|
};
|
|
294
293
|
|
|
295
|
-
const minimumAmbiguousCodePoint = ambiguousRanges[0];
|
|
296
|
-
const maximumAmbiguousCodePoint = ambiguousRanges.at(-1);
|
|
297
|
-
const minimumFullWidthCodePoint = fullwidthRanges[0];
|
|
298
|
-
const maximumFullWidthCodePoint = fullwidthRanges.at(-1);
|
|
299
|
-
const minimumWideCodePoint = wideRanges[0];
|
|
300
|
-
const maximumWideCodePoint = wideRanges.at(-1);
|
|
301
|
-
|
|
302
294
|
const commonCjkCodePoint = 0x4E_00;
|
|
303
|
-
const [wideFastPathStart, wideFastPathEnd] = findWideFastPathRange(wideRanges);
|
|
295
|
+
const [wideFastPathStart, wideFastPathEnd] = /* #__PURE__ */ findWideFastPathRange(wideRanges);
|
|
304
296
|
|
|
305
297
|
// Use a hot-path range so common `isWide` calls can skip binary search.
|
|
306
298
|
// The range containing U+4E00 covers common CJK ideographs;
|
|
@@ -331,8 +323,8 @@ function findWideFastPathRange(ranges) {
|
|
|
331
323
|
|
|
332
324
|
const isAmbiguous = codePoint => {
|
|
333
325
|
if (
|
|
334
|
-
codePoint <
|
|
335
|
-
|| codePoint >
|
|
326
|
+
codePoint < ambiguousMinimalCodePoint
|
|
327
|
+
|| codePoint > ambiguousMaximumCodePoint
|
|
336
328
|
) {
|
|
337
329
|
return false;
|
|
338
330
|
}
|
|
@@ -342,8 +334,8 @@ const isAmbiguous = codePoint => {
|
|
|
342
334
|
|
|
343
335
|
const isFullWidth = codePoint => {
|
|
344
336
|
if (
|
|
345
|
-
codePoint <
|
|
346
|
-
|| codePoint >
|
|
337
|
+
codePoint < fullwidthMinimalCodePoint
|
|
338
|
+
|| codePoint > fullwidthMaximumCodePoint
|
|
347
339
|
) {
|
|
348
340
|
return false;
|
|
349
341
|
}
|
|
@@ -360,8 +352,8 @@ const isWide = codePoint => {
|
|
|
360
352
|
}
|
|
361
353
|
|
|
362
354
|
if (
|
|
363
|
-
codePoint <
|
|
364
|
-
|| codePoint >
|
|
355
|
+
codePoint < wideMinimalCodePoint
|
|
356
|
+
|| codePoint > wideMaximumCodePoint
|
|
365
357
|
) {
|
|
366
358
|
return false;
|
|
367
359
|
}
|
|
@@ -491,4 +483,4 @@ const clearTerminal = isOldWindows()
|
|
|
491
483
|
// More info: https://www.real-world-systems.com/docs/ANSIcode.html
|
|
492
484
|
: `${eraseScreen}${ESC}3J${ESC}H`;
|
|
493
485
|
|
|
494
|
-
export { clearTerminal, createSupportsColor, eastAsianWidth,
|
|
486
|
+
export { clearTerminal, createSupportsColor, eastAsianWidth, eraseLines, isUnicodeSupported, stripAnsi };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createSupportsColor, isUnicodeSupported, stripAnsi,
|
|
1
|
+
import { createSupportsColor, isUnicodeSupported, stripAnsi, eastAsianWidth, clearTerminal, eraseLines } from "./jsenv_core_node_modules.js";
|
|
2
2
|
import { extname } from "node:path";
|
|
3
3
|
import { readFileSync as readFileSync$1, existsSync, readdir, chmod, stat, lstat, chmodSync, statSync, lstatSync, promises, readdirSync, openSync, closeSync, unlinkSync, rmdirSync, mkdirSync, writeFileSync as writeFileSync$1, unlink, rmdir, watch, realpathSync } from "node:fs";
|
|
4
4
|
import crypto, { createHash } from "node:crypto";
|
|
@@ -1437,23 +1437,122 @@ const error = (...args) => console.error(...args);
|
|
|
1437
1437
|
|
|
1438
1438
|
const errorDisabled = () => {};
|
|
1439
1439
|
|
|
1440
|
+
// Whole-cluster zero-width: Default_Ignorable, Control, Format, Mark, Surrogate
|
|
1441
|
+
const zeroWidthClusterRegex =
|
|
1442
|
+
/^[\p{Default_Ignorable_Code_Point}\p{Control}\p{Format}\p{Mark}\p{Surrogate}]+$/v;
|
|
1443
|
+
|
|
1444
|
+
// Strip leading non-printing chars to get the first visible scalar of a cluster
|
|
1445
|
+
const leadingNonPrintingRegex =
|
|
1446
|
+
/^[\p{Default_Ignorable_Code_Point}\p{Control}\p{Format}\p{Mark}\p{Surrogate}]+/v;
|
|
1447
|
+
|
|
1448
|
+
// RGI emoji sequences (e.g. flag sequences, ZWJ families, keycap+VS16)
|
|
1449
|
+
const rgiEmojiRegex = /^\p{RGI_Emoji}$/v;
|
|
1450
|
+
|
|
1451
|
+
// Unqualified keycap: digit/# /* + combining enclosing keycap (no VS16)
|
|
1452
|
+
const unqualifiedKeycapRegex = /^[\d#*]\u20E3$/;
|
|
1453
|
+
const extendedPictographicRegex = /\p{Extended_Pictographic}/gv;
|
|
1454
|
+
|
|
1455
|
+
const isDoubleWidthNonRgiEmojiSequence = (segment) => {
|
|
1456
|
+
if (segment.length > 50) {
|
|
1457
|
+
return false;
|
|
1458
|
+
}
|
|
1459
|
+
if (unqualifiedKeycapRegex.test(segment)) {
|
|
1460
|
+
return true;
|
|
1461
|
+
}
|
|
1462
|
+
// ZWJ sequences with 2+ Extended_Pictographic
|
|
1463
|
+
if (segment.includes("\u200D")) {
|
|
1464
|
+
const pictographics = segment.match(extendedPictographicRegex);
|
|
1465
|
+
return pictographics !== null && pictographics.length >= 2;
|
|
1466
|
+
}
|
|
1467
|
+
return false;
|
|
1468
|
+
};
|
|
1469
|
+
|
|
1470
|
+
const baseVisible = (segment) => {
|
|
1471
|
+
return segment.replace(leadingNonPrintingRegex, "");
|
|
1472
|
+
};
|
|
1473
|
+
|
|
1474
|
+
const isHangulLeadingJamo = (cp) => {
|
|
1475
|
+
return (cp >= 0x11_00 && cp <= 0x11_5f) || (cp >= 0xa9_60 && cp <= 0xa9_7c);
|
|
1476
|
+
};
|
|
1477
|
+
const isHangulVowelJamo = (cp) => {
|
|
1478
|
+
return (cp >= 0x11_60 && cp <= 0x11_a7) || (cp >= 0xd7_b0 && cp <= 0xd7_c6);
|
|
1479
|
+
};
|
|
1480
|
+
const isHangulTrailingJamo = (cp) => {
|
|
1481
|
+
return (cp >= 0x11_a8 && cp <= 0x11_ff) || (cp >= 0xd7_cb && cp <= 0xd7_fb);
|
|
1482
|
+
};
|
|
1483
|
+
const isHangulJamo = (cp) => {
|
|
1484
|
+
return (
|
|
1485
|
+
isHangulLeadingJamo(cp) || isHangulVowelJamo(cp) || isHangulTrailingJamo(cp)
|
|
1486
|
+
);
|
|
1487
|
+
};
|
|
1488
|
+
|
|
1489
|
+
const hangulClusterWidth = (visibleSegment, eastAsianWidthOptions) => {
|
|
1490
|
+
const codePoints = [];
|
|
1491
|
+
for (const character of visibleSegment) {
|
|
1492
|
+
if (zeroWidthClusterRegex.test(character)) {
|
|
1493
|
+
continue;
|
|
1494
|
+
}
|
|
1495
|
+
codePoints.push(character.codePointAt(0));
|
|
1496
|
+
}
|
|
1497
|
+
if (codePoints.length === 0) {
|
|
1498
|
+
return undefined;
|
|
1499
|
+
}
|
|
1500
|
+
let width = 0;
|
|
1501
|
+
for (let index = 0; index < codePoints.length; index++) {
|
|
1502
|
+
const codePoint = codePoints[index];
|
|
1503
|
+
if (!isHangulJamo(codePoint)) {
|
|
1504
|
+
if (width === 0) {
|
|
1505
|
+
return undefined;
|
|
1506
|
+
}
|
|
1507
|
+
for (let remaining = index; remaining < codePoints.length; remaining++) {
|
|
1508
|
+
width += eastAsianWidth(codePoints[remaining], eastAsianWidthOptions);
|
|
1509
|
+
}
|
|
1510
|
+
return width;
|
|
1511
|
+
}
|
|
1512
|
+
if (
|
|
1513
|
+
isHangulLeadingJamo(codePoint) &&
|
|
1514
|
+
isHangulVowelJamo(codePoints[index + 1])
|
|
1515
|
+
) {
|
|
1516
|
+
width += 2;
|
|
1517
|
+
index += isHangulTrailingJamo(codePoints[index + 2]) ? 2 : 1;
|
|
1518
|
+
continue;
|
|
1519
|
+
}
|
|
1520
|
+
width += eastAsianWidth(codePoint, eastAsianWidthOptions);
|
|
1521
|
+
}
|
|
1522
|
+
return width;
|
|
1523
|
+
};
|
|
1524
|
+
|
|
1525
|
+
const trailingHalfwidthWidth = (visibleSegment, eastAsianWidthOptions) => {
|
|
1526
|
+
let extra = 0;
|
|
1527
|
+
let first = true;
|
|
1528
|
+
for (const character of visibleSegment) {
|
|
1529
|
+
if (first) {
|
|
1530
|
+
first = false;
|
|
1531
|
+
continue;
|
|
1532
|
+
}
|
|
1533
|
+
if (character >= "\uFF00" && character <= "\uFFEF") {
|
|
1534
|
+
extra += eastAsianWidth(character.codePointAt(0), eastAsianWidthOptions);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
return extra;
|
|
1538
|
+
};
|
|
1539
|
+
|
|
1440
1540
|
const createMeasureTextWidth = ({ stripAnsi }) => {
|
|
1441
1541
|
const segmenter = new Intl.Segmenter();
|
|
1442
|
-
const defaultIgnorableCodePointRegex = /^\p{Default_Ignorable_Code_Point}$/u;
|
|
1443
1542
|
|
|
1444
1543
|
const measureTextWidth = (
|
|
1445
1544
|
string,
|
|
1446
|
-
{
|
|
1447
|
-
ambiguousIsNarrow = true,
|
|
1448
|
-
countAnsiEscapeCodes = false,
|
|
1449
|
-
skipEmojis = false,
|
|
1450
|
-
} = {},
|
|
1545
|
+
{ ambiguousIsNarrow = true, countAnsiEscapeCodes = false } = {},
|
|
1451
1546
|
) => {
|
|
1452
1547
|
if (typeof string !== "string" || string.length === 0) {
|
|
1453
1548
|
return 0;
|
|
1454
1549
|
}
|
|
1455
1550
|
|
|
1456
|
-
|
|
1551
|
+
// Only strip ANSI when escape codes are actually present
|
|
1552
|
+
if (
|
|
1553
|
+
!countAnsiEscapeCodes &&
|
|
1554
|
+
(string.includes("\u001B") || string.includes("\u009B"))
|
|
1555
|
+
) {
|
|
1457
1556
|
string = stripAnsi(string);
|
|
1458
1557
|
}
|
|
1459
1558
|
|
|
@@ -1461,70 +1560,54 @@ const createMeasureTextWidth = ({ stripAnsi }) => {
|
|
|
1461
1560
|
return 0;
|
|
1462
1561
|
}
|
|
1463
1562
|
|
|
1563
|
+
// Fast path: printable ASCII needs no segmenter or EAW lookup
|
|
1564
|
+
if (/^[\u0020-\u007E]*$/.test(string)) {
|
|
1565
|
+
return string.length;
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1464
1568
|
let width = 0;
|
|
1465
1569
|
const eastAsianWidthOptions = { ambiguousAsWide: !ambiguousIsNarrow };
|
|
1466
1570
|
|
|
1467
|
-
for (const { segment
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
// Ignore control characters
|
|
1471
|
-
if (codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f)) {
|
|
1472
|
-
continue;
|
|
1473
|
-
}
|
|
1474
|
-
|
|
1475
|
-
// Ignore zero-width characters
|
|
1476
|
-
if (
|
|
1477
|
-
(codePoint >= 0x20_0b && codePoint <= 0x20_0f) || // Zero-width space, non-joiner, joiner, left-to-right mark, right-to-left mark
|
|
1478
|
-
codePoint === 0xfe_ff // Zero-width no-break space
|
|
1479
|
-
) {
|
|
1571
|
+
for (const { segment } of segmenter.segment(string)) {
|
|
1572
|
+
if (zeroWidthClusterRegex.test(segment)) {
|
|
1480
1573
|
continue;
|
|
1481
1574
|
}
|
|
1482
1575
|
|
|
1483
|
-
//
|
|
1576
|
+
// RGI emoji + unqualified emoji sequences are double-width
|
|
1484
1577
|
if (
|
|
1485
|
-
(
|
|
1486
|
-
(
|
|
1487
|
-
(codePoint >= 0x1d_c0 && codePoint <= 0x1d_ff) || // Combining diacritical marks supplement
|
|
1488
|
-
(codePoint >= 0x20_d0 && codePoint <= 0x20_ff) || // Combining diacritical marks for symbols
|
|
1489
|
-
(codePoint >= 0xfe_20 && codePoint <= 0xfe_2f) // Combining half marks
|
|
1578
|
+
rgiEmojiRegex.test(segment) ||
|
|
1579
|
+
isDoubleWidthNonRgiEmojiSequence(segment)
|
|
1490
1580
|
) {
|
|
1581
|
+
if (process.env.CAPTURING_SIDE_EFFECTS && segment === "✔️") {
|
|
1582
|
+
width += 2;
|
|
1583
|
+
continue;
|
|
1584
|
+
}
|
|
1585
|
+
width += 2;
|
|
1491
1586
|
continue;
|
|
1492
1587
|
}
|
|
1493
1588
|
|
|
1494
|
-
|
|
1495
|
-
if (codePoint >= 0xd8_00 && codePoint <= 0xdf_ff) {
|
|
1496
|
-
continue;
|
|
1497
|
-
}
|
|
1589
|
+
const visibleSegment = baseVisible(segment);
|
|
1498
1590
|
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
if (defaultIgnorableCodePointRegex.test(character)) {
|
|
1506
|
-
continue;
|
|
1507
|
-
}
|
|
1508
|
-
|
|
1509
|
-
if (!skipEmojis && emojiRegex().test(character)) {
|
|
1510
|
-
if (process.env.CAPTURING_SIDE_EFFECTS) {
|
|
1511
|
-
if (character === "✔️") {
|
|
1512
|
-
width += 2;
|
|
1513
|
-
continue;
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
width += measureTextWidth(character, {
|
|
1517
|
-
skipEmojis: true,
|
|
1518
|
-
countAnsiEscapeCodes: true, // to skip call to stripAnsi
|
|
1519
|
-
});
|
|
1591
|
+
const hangulWidth = hangulClusterWidth(
|
|
1592
|
+
visibleSegment,
|
|
1593
|
+
eastAsianWidthOptions,
|
|
1594
|
+
);
|
|
1595
|
+
if (hangulWidth !== undefined) {
|
|
1596
|
+
width += hangulWidth;
|
|
1520
1597
|
continue;
|
|
1521
1598
|
}
|
|
1522
1599
|
|
|
1600
|
+
// EAW of the cluster's first visible scalar
|
|
1601
|
+
const codePoint = visibleSegment.codePointAt(0);
|
|
1523
1602
|
width += eastAsianWidth(codePoint, eastAsianWidthOptions);
|
|
1603
|
+
|
|
1604
|
+
// Add width for trailing Halfwidth/Fullwidth Forms (e.g. ゙, ゚, ー)
|
|
1605
|
+
width += trailingHalfwidthWidth(visibleSegment, eastAsianWidthOptions);
|
|
1524
1606
|
}
|
|
1525
1607
|
|
|
1526
1608
|
return width;
|
|
1527
1609
|
};
|
|
1610
|
+
|
|
1528
1611
|
return measureTextWidth;
|
|
1529
1612
|
};
|
|
1530
1613
|
|
|
@@ -219,19 +219,18 @@ function isUnicodeSupported() {
|
|
|
219
219
|
|| env.TERMINAL_EMULATOR === 'JetBrains-JediTerm';
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
const r = String.raw,
|
|
223
|
-
e = r`\p{Emoji}(?:\p{EMod}|[\u{E0020}-\u{E007E}]+\u{E007F}|\uFE0F?\u20E3?)`;
|
|
224
|
-
const emojiRegex = () => new RegExp(r`\p{RI}{2}|(?)${e}(?:\u200D${e})*`, 'gu');
|
|
225
|
-
|
|
226
222
|
// Generated by scripts/build.js
|
|
227
223
|
|
|
228
|
-
|
|
224
|
+
const ambiguousMinimalCodePoint = 161;
|
|
225
|
+
const ambiguousMaximumCodePoint = 1114109;
|
|
229
226
|
const ambiguousRanges = [161, 161, 164, 164, 167, 168, 170, 170, 173, 174, 176, 180, 182, 186, 188, 191, 198, 198, 208, 208, 215, 216, 222, 225, 230, 230, 232, 234, 236, 237, 240, 240, 242, 243, 247, 250, 252, 252, 254, 254, 257, 257, 273, 273, 275, 275, 283, 283, 294, 295, 299, 299, 305, 307, 312, 312, 319, 322, 324, 324, 328, 331, 333, 333, 338, 339, 358, 359, 363, 363, 462, 462, 464, 464, 466, 466, 468, 468, 470, 470, 472, 472, 474, 474, 476, 476, 593, 593, 609, 609, 708, 708, 711, 711, 713, 715, 717, 717, 720, 720, 728, 731, 733, 733, 735, 735, 768, 879, 913, 929, 931, 937, 945, 961, 963, 969, 1025, 1025, 1040, 1103, 1105, 1105, 8208, 8208, 8211, 8214, 8216, 8217, 8220, 8221, 8224, 8226, 8228, 8231, 8240, 8240, 8242, 8243, 8245, 8245, 8251, 8251, 8254, 8254, 8308, 8308, 8319, 8319, 8321, 8324, 8364, 8364, 8451, 8451, 8453, 8453, 8457, 8457, 8467, 8467, 8470, 8470, 8481, 8482, 8486, 8486, 8491, 8491, 8531, 8532, 8539, 8542, 8544, 8555, 8560, 8569, 8585, 8585, 8592, 8601, 8632, 8633, 8658, 8658, 8660, 8660, 8679, 8679, 8704, 8704, 8706, 8707, 8711, 8712, 8715, 8715, 8719, 8719, 8721, 8721, 8725, 8725, 8730, 8730, 8733, 8736, 8739, 8739, 8741, 8741, 8743, 8748, 8750, 8750, 8756, 8759, 8764, 8765, 8776, 8776, 8780, 8780, 8786, 8786, 8800, 8801, 8804, 8807, 8810, 8811, 8814, 8815, 8834, 8835, 8838, 8839, 8853, 8853, 8857, 8857, 8869, 8869, 8895, 8895, 8978, 8978, 9312, 9449, 9451, 9547, 9552, 9587, 9600, 9615, 9618, 9621, 9632, 9633, 9635, 9641, 9650, 9651, 9654, 9655, 9660, 9661, 9664, 9665, 9670, 9672, 9675, 9675, 9678, 9681, 9698, 9701, 9711, 9711, 9733, 9734, 9737, 9737, 9742, 9743, 9756, 9756, 9758, 9758, 9792, 9792, 9794, 9794, 9824, 9825, 9827, 9829, 9831, 9834, 9836, 9837, 9839, 9839, 9886, 9887, 9919, 9919, 9926, 9933, 9935, 9939, 9941, 9953, 9955, 9955, 9960, 9961, 9963, 9969, 9972, 9972, 9974, 9977, 9979, 9980, 9982, 9983, 10045, 10045, 10102, 10111, 11094, 11097, 12872, 12879, 57344, 63743, 65024, 65039, 65533, 65533, 127232, 127242, 127248, 127277, 127280, 127337, 127344, 127373, 127375, 127376, 127387, 127404, 917760, 917999, 983040, 1048573, 1048576, 1114109];
|
|
230
227
|
|
|
231
|
-
|
|
228
|
+
const fullwidthMinimalCodePoint = 12288;
|
|
229
|
+
const fullwidthMaximumCodePoint = 65510;
|
|
232
230
|
const fullwidthRanges = [12288, 12288, 65281, 65376, 65504, 65510];
|
|
233
231
|
|
|
234
|
-
|
|
232
|
+
const wideMinimalCodePoint = 4352;
|
|
233
|
+
const wideMaximumCodePoint = 262141;
|
|
235
234
|
const wideRanges = [4352, 4447, 8986, 8987, 9001, 9002, 9193, 9196, 9200, 9200, 9203, 9203, 9725, 9726, 9748, 9749, 9776, 9783, 9800, 9811, 9855, 9855, 9866, 9871, 9875, 9875, 9889, 9889, 9898, 9899, 9917, 9918, 9924, 9925, 9934, 9934, 9940, 9940, 9962, 9962, 9970, 9971, 9973, 9973, 9978, 9978, 9981, 9981, 9989, 9989, 9994, 9995, 10024, 10024, 10060, 10060, 10062, 10062, 10067, 10069, 10071, 10071, 10133, 10135, 10160, 10160, 10175, 10175, 11035, 11036, 11088, 11088, 11093, 11093, 11904, 11929, 11931, 12019, 12032, 12245, 12272, 12287, 12289, 12350, 12353, 12438, 12441, 12543, 12549, 12591, 12593, 12686, 12688, 12773, 12783, 12830, 12832, 12871, 12880, 42124, 42128, 42182, 43360, 43388, 44032, 55203, 63744, 64255, 65040, 65049, 65072, 65106, 65108, 65126, 65128, 65131, 94176, 94180, 94192, 94198, 94208, 101589, 101631, 101662, 101760, 101874, 110576, 110579, 110581, 110587, 110589, 110590, 110592, 110882, 110898, 110898, 110928, 110930, 110933, 110933, 110948, 110951, 110960, 111355, 119552, 119638, 119648, 119670, 126980, 126980, 127183, 127183, 127374, 127374, 127377, 127386, 127488, 127490, 127504, 127547, 127552, 127560, 127568, 127569, 127584, 127589, 127744, 127776, 127789, 127797, 127799, 127868, 127870, 127891, 127904, 127946, 127951, 127955, 127968, 127984, 127988, 127988, 127992, 128062, 128064, 128064, 128066, 128252, 128255, 128317, 128331, 128334, 128336, 128359, 128378, 128378, 128405, 128406, 128420, 128420, 128507, 128591, 128640, 128709, 128716, 128716, 128720, 128722, 128725, 128728, 128732, 128735, 128747, 128748, 128756, 128764, 128992, 129003, 129008, 129008, 129292, 129338, 129340, 129349, 129351, 129535, 129648, 129660, 129664, 129674, 129678, 129734, 129736, 129736, 129741, 129756, 129759, 129770, 129775, 129784, 131072, 196605, 196608, 262141];
|
|
236
235
|
|
|
237
236
|
/**
|
|
@@ -259,15 +258,8 @@ const isInRange = (ranges, codePoint) => {
|
|
|
259
258
|
return false;
|
|
260
259
|
};
|
|
261
260
|
|
|
262
|
-
const minimumAmbiguousCodePoint = ambiguousRanges[0];
|
|
263
|
-
const maximumAmbiguousCodePoint = ambiguousRanges.at(-1);
|
|
264
|
-
const minimumFullWidthCodePoint = fullwidthRanges[0];
|
|
265
|
-
const maximumFullWidthCodePoint = fullwidthRanges.at(-1);
|
|
266
|
-
const minimumWideCodePoint = wideRanges[0];
|
|
267
|
-
const maximumWideCodePoint = wideRanges.at(-1);
|
|
268
|
-
|
|
269
261
|
const commonCjkCodePoint = 0x4E_00;
|
|
270
|
-
const [wideFastPathStart, wideFastPathEnd] = findWideFastPathRange(wideRanges);
|
|
262
|
+
const [wideFastPathStart, wideFastPathEnd] = /* #__PURE__ */ findWideFastPathRange(wideRanges);
|
|
271
263
|
|
|
272
264
|
// Use a hot-path range so common `isWide` calls can skip binary search.
|
|
273
265
|
// The range containing U+4E00 covers common CJK ideographs;
|
|
@@ -298,8 +290,8 @@ function findWideFastPathRange(ranges) {
|
|
|
298
290
|
|
|
299
291
|
const isAmbiguous = codePoint => {
|
|
300
292
|
if (
|
|
301
|
-
codePoint <
|
|
302
|
-
|| codePoint >
|
|
293
|
+
codePoint < ambiguousMinimalCodePoint
|
|
294
|
+
|| codePoint > ambiguousMaximumCodePoint
|
|
303
295
|
) {
|
|
304
296
|
return false;
|
|
305
297
|
}
|
|
@@ -309,8 +301,8 @@ const isAmbiguous = codePoint => {
|
|
|
309
301
|
|
|
310
302
|
const isFullWidth = codePoint => {
|
|
311
303
|
if (
|
|
312
|
-
codePoint <
|
|
313
|
-
|| codePoint >
|
|
304
|
+
codePoint < fullwidthMinimalCodePoint
|
|
305
|
+
|| codePoint > fullwidthMaximumCodePoint
|
|
314
306
|
) {
|
|
315
307
|
return false;
|
|
316
308
|
}
|
|
@@ -327,8 +319,8 @@ const isWide = codePoint => {
|
|
|
327
319
|
}
|
|
328
320
|
|
|
329
321
|
if (
|
|
330
|
-
codePoint <
|
|
331
|
-
|| codePoint >
|
|
322
|
+
codePoint < wideMinimalCodePoint
|
|
323
|
+
|| codePoint > wideMaximumCodePoint
|
|
332
324
|
) {
|
|
333
325
|
return false;
|
|
334
326
|
}
|
|
@@ -458,4 +450,4 @@ const clearTerminal = isOldWindows()
|
|
|
458
450
|
// More info: https://www.real-world-systems.com/docs/ANSIcode.html
|
|
459
451
|
: `${eraseScreen}${ESC}3J${ESC}H`;
|
|
460
452
|
|
|
461
|
-
export { clearTerminal, createSupportsColor, eastAsianWidth,
|
|
453
|
+
export { clearTerminal, createSupportsColor, eastAsianWidth, eraseLines, isUnicodeSupported };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createSupportsColor, isUnicodeSupported,
|
|
1
|
+
import { createSupportsColor, isUnicodeSupported, eastAsianWidth, clearTerminal, eraseLines } from "./jsenv_core_node_modules.js";
|
|
2
2
|
import { stripVTControlCharacters } from "node:util";
|
|
3
3
|
|
|
4
4
|
const createCallbackListNotifiedOnce = () => {
|
|
@@ -997,23 +997,122 @@ const error = (...args) => console.error(...args);
|
|
|
997
997
|
|
|
998
998
|
const errorDisabled = () => {};
|
|
999
999
|
|
|
1000
|
+
// Whole-cluster zero-width: Default_Ignorable, Control, Format, Mark, Surrogate
|
|
1001
|
+
const zeroWidthClusterRegex =
|
|
1002
|
+
/^[\p{Default_Ignorable_Code_Point}\p{Control}\p{Format}\p{Mark}\p{Surrogate}]+$/v;
|
|
1003
|
+
|
|
1004
|
+
// Strip leading non-printing chars to get the first visible scalar of a cluster
|
|
1005
|
+
const leadingNonPrintingRegex =
|
|
1006
|
+
/^[\p{Default_Ignorable_Code_Point}\p{Control}\p{Format}\p{Mark}\p{Surrogate}]+/v;
|
|
1007
|
+
|
|
1008
|
+
// RGI emoji sequences (e.g. flag sequences, ZWJ families, keycap+VS16)
|
|
1009
|
+
const rgiEmojiRegex = /^\p{RGI_Emoji}$/v;
|
|
1010
|
+
|
|
1011
|
+
// Unqualified keycap: digit/# /* + combining enclosing keycap (no VS16)
|
|
1012
|
+
const unqualifiedKeycapRegex = /^[\d#*]\u20E3$/;
|
|
1013
|
+
const extendedPictographicRegex = /\p{Extended_Pictographic}/gv;
|
|
1014
|
+
|
|
1015
|
+
const isDoubleWidthNonRgiEmojiSequence = (segment) => {
|
|
1016
|
+
if (segment.length > 50) {
|
|
1017
|
+
return false;
|
|
1018
|
+
}
|
|
1019
|
+
if (unqualifiedKeycapRegex.test(segment)) {
|
|
1020
|
+
return true;
|
|
1021
|
+
}
|
|
1022
|
+
// ZWJ sequences with 2+ Extended_Pictographic
|
|
1023
|
+
if (segment.includes("\u200D")) {
|
|
1024
|
+
const pictographics = segment.match(extendedPictographicRegex);
|
|
1025
|
+
return pictographics !== null && pictographics.length >= 2;
|
|
1026
|
+
}
|
|
1027
|
+
return false;
|
|
1028
|
+
};
|
|
1029
|
+
|
|
1030
|
+
const baseVisible = (segment) => {
|
|
1031
|
+
return segment.replace(leadingNonPrintingRegex, "");
|
|
1032
|
+
};
|
|
1033
|
+
|
|
1034
|
+
const isHangulLeadingJamo = (cp) => {
|
|
1035
|
+
return (cp >= 0x11_00 && cp <= 0x11_5f) || (cp >= 0xa9_60 && cp <= 0xa9_7c);
|
|
1036
|
+
};
|
|
1037
|
+
const isHangulVowelJamo = (cp) => {
|
|
1038
|
+
return (cp >= 0x11_60 && cp <= 0x11_a7) || (cp >= 0xd7_b0 && cp <= 0xd7_c6);
|
|
1039
|
+
};
|
|
1040
|
+
const isHangulTrailingJamo = (cp) => {
|
|
1041
|
+
return (cp >= 0x11_a8 && cp <= 0x11_ff) || (cp >= 0xd7_cb && cp <= 0xd7_fb);
|
|
1042
|
+
};
|
|
1043
|
+
const isHangulJamo = (cp) => {
|
|
1044
|
+
return (
|
|
1045
|
+
isHangulLeadingJamo(cp) || isHangulVowelJamo(cp) || isHangulTrailingJamo(cp)
|
|
1046
|
+
);
|
|
1047
|
+
};
|
|
1048
|
+
|
|
1049
|
+
const hangulClusterWidth = (visibleSegment, eastAsianWidthOptions) => {
|
|
1050
|
+
const codePoints = [];
|
|
1051
|
+
for (const character of visibleSegment) {
|
|
1052
|
+
if (zeroWidthClusterRegex.test(character)) {
|
|
1053
|
+
continue;
|
|
1054
|
+
}
|
|
1055
|
+
codePoints.push(character.codePointAt(0));
|
|
1056
|
+
}
|
|
1057
|
+
if (codePoints.length === 0) {
|
|
1058
|
+
return undefined;
|
|
1059
|
+
}
|
|
1060
|
+
let width = 0;
|
|
1061
|
+
for (let index = 0; index < codePoints.length; index++) {
|
|
1062
|
+
const codePoint = codePoints[index];
|
|
1063
|
+
if (!isHangulJamo(codePoint)) {
|
|
1064
|
+
if (width === 0) {
|
|
1065
|
+
return undefined;
|
|
1066
|
+
}
|
|
1067
|
+
for (let remaining = index; remaining < codePoints.length; remaining++) {
|
|
1068
|
+
width += eastAsianWidth(codePoints[remaining], eastAsianWidthOptions);
|
|
1069
|
+
}
|
|
1070
|
+
return width;
|
|
1071
|
+
}
|
|
1072
|
+
if (
|
|
1073
|
+
isHangulLeadingJamo(codePoint) &&
|
|
1074
|
+
isHangulVowelJamo(codePoints[index + 1])
|
|
1075
|
+
) {
|
|
1076
|
+
width += 2;
|
|
1077
|
+
index += isHangulTrailingJamo(codePoints[index + 2]) ? 2 : 1;
|
|
1078
|
+
continue;
|
|
1079
|
+
}
|
|
1080
|
+
width += eastAsianWidth(codePoint, eastAsianWidthOptions);
|
|
1081
|
+
}
|
|
1082
|
+
return width;
|
|
1083
|
+
};
|
|
1084
|
+
|
|
1085
|
+
const trailingHalfwidthWidth = (visibleSegment, eastAsianWidthOptions) => {
|
|
1086
|
+
let extra = 0;
|
|
1087
|
+
let first = true;
|
|
1088
|
+
for (const character of visibleSegment) {
|
|
1089
|
+
if (first) {
|
|
1090
|
+
first = false;
|
|
1091
|
+
continue;
|
|
1092
|
+
}
|
|
1093
|
+
if (character >= "\uFF00" && character <= "\uFFEF") {
|
|
1094
|
+
extra += eastAsianWidth(character.codePointAt(0), eastAsianWidthOptions);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
return extra;
|
|
1098
|
+
};
|
|
1099
|
+
|
|
1000
1100
|
const createMeasureTextWidth = ({ stripAnsi }) => {
|
|
1001
1101
|
const segmenter = new Intl.Segmenter();
|
|
1002
|
-
const defaultIgnorableCodePointRegex = /^\p{Default_Ignorable_Code_Point}$/u;
|
|
1003
1102
|
|
|
1004
1103
|
const measureTextWidth = (
|
|
1005
1104
|
string,
|
|
1006
|
-
{
|
|
1007
|
-
ambiguousIsNarrow = true,
|
|
1008
|
-
countAnsiEscapeCodes = false,
|
|
1009
|
-
skipEmojis = false,
|
|
1010
|
-
} = {},
|
|
1105
|
+
{ ambiguousIsNarrow = true, countAnsiEscapeCodes = false } = {},
|
|
1011
1106
|
) => {
|
|
1012
1107
|
if (typeof string !== "string" || string.length === 0) {
|
|
1013
1108
|
return 0;
|
|
1014
1109
|
}
|
|
1015
1110
|
|
|
1016
|
-
|
|
1111
|
+
// Only strip ANSI when escape codes are actually present
|
|
1112
|
+
if (
|
|
1113
|
+
!countAnsiEscapeCodes &&
|
|
1114
|
+
(string.includes("\u001B") || string.includes("\u009B"))
|
|
1115
|
+
) {
|
|
1017
1116
|
string = stripAnsi(string);
|
|
1018
1117
|
}
|
|
1019
1118
|
|
|
@@ -1021,70 +1120,54 @@ const createMeasureTextWidth = ({ stripAnsi }) => {
|
|
|
1021
1120
|
return 0;
|
|
1022
1121
|
}
|
|
1023
1122
|
|
|
1123
|
+
// Fast path: printable ASCII needs no segmenter or EAW lookup
|
|
1124
|
+
if (/^[\u0020-\u007E]*$/.test(string)) {
|
|
1125
|
+
return string.length;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1024
1128
|
let width = 0;
|
|
1025
1129
|
const eastAsianWidthOptions = { ambiguousAsWide: !ambiguousIsNarrow };
|
|
1026
1130
|
|
|
1027
|
-
for (const { segment
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
// Ignore control characters
|
|
1031
|
-
if (codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f)) {
|
|
1032
|
-
continue;
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
|
-
// Ignore zero-width characters
|
|
1036
|
-
if (
|
|
1037
|
-
(codePoint >= 0x20_0b && codePoint <= 0x20_0f) || // Zero-width space, non-joiner, joiner, left-to-right mark, right-to-left mark
|
|
1038
|
-
codePoint === 0xfe_ff // Zero-width no-break space
|
|
1039
|
-
) {
|
|
1131
|
+
for (const { segment } of segmenter.segment(string)) {
|
|
1132
|
+
if (zeroWidthClusterRegex.test(segment)) {
|
|
1040
1133
|
continue;
|
|
1041
1134
|
}
|
|
1042
1135
|
|
|
1043
|
-
//
|
|
1136
|
+
// RGI emoji + unqualified emoji sequences are double-width
|
|
1044
1137
|
if (
|
|
1045
|
-
(
|
|
1046
|
-
(
|
|
1047
|
-
(codePoint >= 0x1d_c0 && codePoint <= 0x1d_ff) || // Combining diacritical marks supplement
|
|
1048
|
-
(codePoint >= 0x20_d0 && codePoint <= 0x20_ff) || // Combining diacritical marks for symbols
|
|
1049
|
-
(codePoint >= 0xfe_20 && codePoint <= 0xfe_2f) // Combining half marks
|
|
1138
|
+
rgiEmojiRegex.test(segment) ||
|
|
1139
|
+
isDoubleWidthNonRgiEmojiSequence(segment)
|
|
1050
1140
|
) {
|
|
1141
|
+
if (process.env.CAPTURING_SIDE_EFFECTS && segment === "✔️") {
|
|
1142
|
+
width += 2;
|
|
1143
|
+
continue;
|
|
1144
|
+
}
|
|
1145
|
+
width += 2;
|
|
1051
1146
|
continue;
|
|
1052
1147
|
}
|
|
1053
1148
|
|
|
1054
|
-
|
|
1055
|
-
if (codePoint >= 0xd8_00 && codePoint <= 0xdf_ff) {
|
|
1056
|
-
continue;
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
// Ignore variation selectors
|
|
1060
|
-
if (codePoint >= 0xfe_00 && codePoint <= 0xfe_0f) {
|
|
1061
|
-
continue;
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
// This covers some of the above cases, but we still keep them for performance reasons.
|
|
1065
|
-
if (defaultIgnorableCodePointRegex.test(character)) {
|
|
1066
|
-
continue;
|
|
1067
|
-
}
|
|
1149
|
+
const visibleSegment = baseVisible(segment);
|
|
1068
1150
|
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
}
|
|
1076
|
-
width += measureTextWidth(character, {
|
|
1077
|
-
skipEmojis: true,
|
|
1078
|
-
countAnsiEscapeCodes: true, // to skip call to stripAnsi
|
|
1079
|
-
});
|
|
1151
|
+
const hangulWidth = hangulClusterWidth(
|
|
1152
|
+
visibleSegment,
|
|
1153
|
+
eastAsianWidthOptions,
|
|
1154
|
+
);
|
|
1155
|
+
if (hangulWidth !== undefined) {
|
|
1156
|
+
width += hangulWidth;
|
|
1080
1157
|
continue;
|
|
1081
1158
|
}
|
|
1082
1159
|
|
|
1160
|
+
// EAW of the cluster's first visible scalar
|
|
1161
|
+
const codePoint = visibleSegment.codePointAt(0);
|
|
1083
1162
|
width += eastAsianWidth(codePoint, eastAsianWidthOptions);
|
|
1163
|
+
|
|
1164
|
+
// Add width for trailing Halfwidth/Fullwidth Forms (e.g. ゙, ゚, ー)
|
|
1165
|
+
width += trailingHalfwidthWidth(visibleSegment, eastAsianWidthOptions);
|
|
1084
1166
|
}
|
|
1085
1167
|
|
|
1086
1168
|
return width;
|
|
1087
1169
|
};
|
|
1170
|
+
|
|
1088
1171
|
return measureTextWidth;
|
|
1089
1172
|
};
|
|
1090
1173
|
|
|
@@ -219,19 +219,18 @@ function isUnicodeSupported() {
|
|
|
219
219
|
|| env.TERMINAL_EMULATOR === 'JetBrains-JediTerm';
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
const r = String.raw,
|
|
223
|
-
e = r`\p{Emoji}(?:\p{EMod}|[\u{E0020}-\u{E007E}]+\u{E007F}|\uFE0F?\u20E3?)`;
|
|
224
|
-
const emojiRegex = () => new RegExp(r`\p{RI}{2}|(?)${e}(?:\u200D${e})*`, 'gu');
|
|
225
|
-
|
|
226
222
|
// Generated by scripts/build.js
|
|
227
223
|
|
|
228
|
-
|
|
224
|
+
const ambiguousMinimalCodePoint = 161;
|
|
225
|
+
const ambiguousMaximumCodePoint = 1114109;
|
|
229
226
|
const ambiguousRanges = [161, 161, 164, 164, 167, 168, 170, 170, 173, 174, 176, 180, 182, 186, 188, 191, 198, 198, 208, 208, 215, 216, 222, 225, 230, 230, 232, 234, 236, 237, 240, 240, 242, 243, 247, 250, 252, 252, 254, 254, 257, 257, 273, 273, 275, 275, 283, 283, 294, 295, 299, 299, 305, 307, 312, 312, 319, 322, 324, 324, 328, 331, 333, 333, 338, 339, 358, 359, 363, 363, 462, 462, 464, 464, 466, 466, 468, 468, 470, 470, 472, 472, 474, 474, 476, 476, 593, 593, 609, 609, 708, 708, 711, 711, 713, 715, 717, 717, 720, 720, 728, 731, 733, 733, 735, 735, 768, 879, 913, 929, 931, 937, 945, 961, 963, 969, 1025, 1025, 1040, 1103, 1105, 1105, 8208, 8208, 8211, 8214, 8216, 8217, 8220, 8221, 8224, 8226, 8228, 8231, 8240, 8240, 8242, 8243, 8245, 8245, 8251, 8251, 8254, 8254, 8308, 8308, 8319, 8319, 8321, 8324, 8364, 8364, 8451, 8451, 8453, 8453, 8457, 8457, 8467, 8467, 8470, 8470, 8481, 8482, 8486, 8486, 8491, 8491, 8531, 8532, 8539, 8542, 8544, 8555, 8560, 8569, 8585, 8585, 8592, 8601, 8632, 8633, 8658, 8658, 8660, 8660, 8679, 8679, 8704, 8704, 8706, 8707, 8711, 8712, 8715, 8715, 8719, 8719, 8721, 8721, 8725, 8725, 8730, 8730, 8733, 8736, 8739, 8739, 8741, 8741, 8743, 8748, 8750, 8750, 8756, 8759, 8764, 8765, 8776, 8776, 8780, 8780, 8786, 8786, 8800, 8801, 8804, 8807, 8810, 8811, 8814, 8815, 8834, 8835, 8838, 8839, 8853, 8853, 8857, 8857, 8869, 8869, 8895, 8895, 8978, 8978, 9312, 9449, 9451, 9547, 9552, 9587, 9600, 9615, 9618, 9621, 9632, 9633, 9635, 9641, 9650, 9651, 9654, 9655, 9660, 9661, 9664, 9665, 9670, 9672, 9675, 9675, 9678, 9681, 9698, 9701, 9711, 9711, 9733, 9734, 9737, 9737, 9742, 9743, 9756, 9756, 9758, 9758, 9792, 9792, 9794, 9794, 9824, 9825, 9827, 9829, 9831, 9834, 9836, 9837, 9839, 9839, 9886, 9887, 9919, 9919, 9926, 9933, 9935, 9939, 9941, 9953, 9955, 9955, 9960, 9961, 9963, 9969, 9972, 9972, 9974, 9977, 9979, 9980, 9982, 9983, 10045, 10045, 10102, 10111, 11094, 11097, 12872, 12879, 57344, 63743, 65024, 65039, 65533, 65533, 127232, 127242, 127248, 127277, 127280, 127337, 127344, 127373, 127375, 127376, 127387, 127404, 917760, 917999, 983040, 1048573, 1048576, 1114109];
|
|
230
227
|
|
|
231
|
-
|
|
228
|
+
const fullwidthMinimalCodePoint = 12288;
|
|
229
|
+
const fullwidthMaximumCodePoint = 65510;
|
|
232
230
|
const fullwidthRanges = [12288, 12288, 65281, 65376, 65504, 65510];
|
|
233
231
|
|
|
234
|
-
|
|
232
|
+
const wideMinimalCodePoint = 4352;
|
|
233
|
+
const wideMaximumCodePoint = 262141;
|
|
235
234
|
const wideRanges = [4352, 4447, 8986, 8987, 9001, 9002, 9193, 9196, 9200, 9200, 9203, 9203, 9725, 9726, 9748, 9749, 9776, 9783, 9800, 9811, 9855, 9855, 9866, 9871, 9875, 9875, 9889, 9889, 9898, 9899, 9917, 9918, 9924, 9925, 9934, 9934, 9940, 9940, 9962, 9962, 9970, 9971, 9973, 9973, 9978, 9978, 9981, 9981, 9989, 9989, 9994, 9995, 10024, 10024, 10060, 10060, 10062, 10062, 10067, 10069, 10071, 10071, 10133, 10135, 10160, 10160, 10175, 10175, 11035, 11036, 11088, 11088, 11093, 11093, 11904, 11929, 11931, 12019, 12032, 12245, 12272, 12287, 12289, 12350, 12353, 12438, 12441, 12543, 12549, 12591, 12593, 12686, 12688, 12773, 12783, 12830, 12832, 12871, 12880, 42124, 42128, 42182, 43360, 43388, 44032, 55203, 63744, 64255, 65040, 65049, 65072, 65106, 65108, 65126, 65128, 65131, 94176, 94180, 94192, 94198, 94208, 101589, 101631, 101662, 101760, 101874, 110576, 110579, 110581, 110587, 110589, 110590, 110592, 110882, 110898, 110898, 110928, 110930, 110933, 110933, 110948, 110951, 110960, 111355, 119552, 119638, 119648, 119670, 126980, 126980, 127183, 127183, 127374, 127374, 127377, 127386, 127488, 127490, 127504, 127547, 127552, 127560, 127568, 127569, 127584, 127589, 127744, 127776, 127789, 127797, 127799, 127868, 127870, 127891, 127904, 127946, 127951, 127955, 127968, 127984, 127988, 127988, 127992, 128062, 128064, 128064, 128066, 128252, 128255, 128317, 128331, 128334, 128336, 128359, 128378, 128378, 128405, 128406, 128420, 128420, 128507, 128591, 128640, 128709, 128716, 128716, 128720, 128722, 128725, 128728, 128732, 128735, 128747, 128748, 128756, 128764, 128992, 129003, 129008, 129008, 129292, 129338, 129340, 129349, 129351, 129535, 129648, 129660, 129664, 129674, 129678, 129734, 129736, 129736, 129741, 129756, 129759, 129770, 129775, 129784, 131072, 196605, 196608, 262141];
|
|
236
235
|
|
|
237
236
|
/**
|
|
@@ -259,15 +258,8 @@ const isInRange = (ranges, codePoint) => {
|
|
|
259
258
|
return false;
|
|
260
259
|
};
|
|
261
260
|
|
|
262
|
-
const minimumAmbiguousCodePoint = ambiguousRanges[0];
|
|
263
|
-
const maximumAmbiguousCodePoint = ambiguousRanges.at(-1);
|
|
264
|
-
const minimumFullWidthCodePoint = fullwidthRanges[0];
|
|
265
|
-
const maximumFullWidthCodePoint = fullwidthRanges.at(-1);
|
|
266
|
-
const minimumWideCodePoint = wideRanges[0];
|
|
267
|
-
const maximumWideCodePoint = wideRanges.at(-1);
|
|
268
|
-
|
|
269
261
|
const commonCjkCodePoint = 0x4E_00;
|
|
270
|
-
const [wideFastPathStart, wideFastPathEnd] = findWideFastPathRange(wideRanges);
|
|
262
|
+
const [wideFastPathStart, wideFastPathEnd] = /* #__PURE__ */ findWideFastPathRange(wideRanges);
|
|
271
263
|
|
|
272
264
|
// Use a hot-path range so common `isWide` calls can skip binary search.
|
|
273
265
|
// The range containing U+4E00 covers common CJK ideographs;
|
|
@@ -298,8 +290,8 @@ function findWideFastPathRange(ranges) {
|
|
|
298
290
|
|
|
299
291
|
const isAmbiguous = codePoint => {
|
|
300
292
|
if (
|
|
301
|
-
codePoint <
|
|
302
|
-
|| codePoint >
|
|
293
|
+
codePoint < ambiguousMinimalCodePoint
|
|
294
|
+
|| codePoint > ambiguousMaximumCodePoint
|
|
303
295
|
) {
|
|
304
296
|
return false;
|
|
305
297
|
}
|
|
@@ -309,8 +301,8 @@ const isAmbiguous = codePoint => {
|
|
|
309
301
|
|
|
310
302
|
const isFullWidth = codePoint => {
|
|
311
303
|
if (
|
|
312
|
-
codePoint <
|
|
313
|
-
|| codePoint >
|
|
304
|
+
codePoint < fullwidthMinimalCodePoint
|
|
305
|
+
|| codePoint > fullwidthMaximumCodePoint
|
|
314
306
|
) {
|
|
315
307
|
return false;
|
|
316
308
|
}
|
|
@@ -327,8 +319,8 @@ const isWide = codePoint => {
|
|
|
327
319
|
}
|
|
328
320
|
|
|
329
321
|
if (
|
|
330
|
-
codePoint <
|
|
331
|
-
|| codePoint >
|
|
322
|
+
codePoint < wideMinimalCodePoint
|
|
323
|
+
|| codePoint > wideMaximumCodePoint
|
|
332
324
|
) {
|
|
333
325
|
return false;
|
|
334
326
|
}
|
|
@@ -458,4 +450,4 @@ const clearTerminal = isOldWindows()
|
|
|
458
450
|
// More info: https://www.real-world-systems.com/docs/ANSIcode.html
|
|
459
451
|
: `${eraseScreen}${ESC}3J${ESC}H`;
|
|
460
452
|
|
|
461
|
-
export { clearTerminal, createSupportsColor, eastAsianWidth,
|
|
453
|
+
export { clearTerminal, createSupportsColor, eastAsianWidth, eraseLines, isUnicodeSupported };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createSupportsColor, isUnicodeSupported,
|
|
1
|
+
import { createSupportsColor, isUnicodeSupported, eastAsianWidth, clearTerminal, eraseLines } from "./jsenv_core_node_modules.js";
|
|
2
2
|
import { stripVTControlCharacters } from "node:util";
|
|
3
3
|
import { readFileSync, existsSync, chmodSync, statSync, lstatSync, readdirSync, openSync, closeSync, unlinkSync, rmdirSync, mkdirSync, writeFileSync as writeFileSync$1, watch, realpathSync } from "node:fs";
|
|
4
4
|
import { extname } from "node:path";
|
|
@@ -800,23 +800,122 @@ const error = (...args) => console.error(...args);
|
|
|
800
800
|
|
|
801
801
|
const errorDisabled = () => {};
|
|
802
802
|
|
|
803
|
+
// Whole-cluster zero-width: Default_Ignorable, Control, Format, Mark, Surrogate
|
|
804
|
+
const zeroWidthClusterRegex =
|
|
805
|
+
/^[\p{Default_Ignorable_Code_Point}\p{Control}\p{Format}\p{Mark}\p{Surrogate}]+$/v;
|
|
806
|
+
|
|
807
|
+
// Strip leading non-printing chars to get the first visible scalar of a cluster
|
|
808
|
+
const leadingNonPrintingRegex =
|
|
809
|
+
/^[\p{Default_Ignorable_Code_Point}\p{Control}\p{Format}\p{Mark}\p{Surrogate}]+/v;
|
|
810
|
+
|
|
811
|
+
// RGI emoji sequences (e.g. flag sequences, ZWJ families, keycap+VS16)
|
|
812
|
+
const rgiEmojiRegex = /^\p{RGI_Emoji}$/v;
|
|
813
|
+
|
|
814
|
+
// Unqualified keycap: digit/# /* + combining enclosing keycap (no VS16)
|
|
815
|
+
const unqualifiedKeycapRegex = /^[\d#*]\u20E3$/;
|
|
816
|
+
const extendedPictographicRegex = /\p{Extended_Pictographic}/gv;
|
|
817
|
+
|
|
818
|
+
const isDoubleWidthNonRgiEmojiSequence = (segment) => {
|
|
819
|
+
if (segment.length > 50) {
|
|
820
|
+
return false;
|
|
821
|
+
}
|
|
822
|
+
if (unqualifiedKeycapRegex.test(segment)) {
|
|
823
|
+
return true;
|
|
824
|
+
}
|
|
825
|
+
// ZWJ sequences with 2+ Extended_Pictographic
|
|
826
|
+
if (segment.includes("\u200D")) {
|
|
827
|
+
const pictographics = segment.match(extendedPictographicRegex);
|
|
828
|
+
return pictographics !== null && pictographics.length >= 2;
|
|
829
|
+
}
|
|
830
|
+
return false;
|
|
831
|
+
};
|
|
832
|
+
|
|
833
|
+
const baseVisible = (segment) => {
|
|
834
|
+
return segment.replace(leadingNonPrintingRegex, "");
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
const isHangulLeadingJamo = (cp) => {
|
|
838
|
+
return (cp >= 0x11_00 && cp <= 0x11_5f) || (cp >= 0xa9_60 && cp <= 0xa9_7c);
|
|
839
|
+
};
|
|
840
|
+
const isHangulVowelJamo = (cp) => {
|
|
841
|
+
return (cp >= 0x11_60 && cp <= 0x11_a7) || (cp >= 0xd7_b0 && cp <= 0xd7_c6);
|
|
842
|
+
};
|
|
843
|
+
const isHangulTrailingJamo = (cp) => {
|
|
844
|
+
return (cp >= 0x11_a8 && cp <= 0x11_ff) || (cp >= 0xd7_cb && cp <= 0xd7_fb);
|
|
845
|
+
};
|
|
846
|
+
const isHangulJamo = (cp) => {
|
|
847
|
+
return (
|
|
848
|
+
isHangulLeadingJamo(cp) || isHangulVowelJamo(cp) || isHangulTrailingJamo(cp)
|
|
849
|
+
);
|
|
850
|
+
};
|
|
851
|
+
|
|
852
|
+
const hangulClusterWidth = (visibleSegment, eastAsianWidthOptions) => {
|
|
853
|
+
const codePoints = [];
|
|
854
|
+
for (const character of visibleSegment) {
|
|
855
|
+
if (zeroWidthClusterRegex.test(character)) {
|
|
856
|
+
continue;
|
|
857
|
+
}
|
|
858
|
+
codePoints.push(character.codePointAt(0));
|
|
859
|
+
}
|
|
860
|
+
if (codePoints.length === 0) {
|
|
861
|
+
return undefined;
|
|
862
|
+
}
|
|
863
|
+
let width = 0;
|
|
864
|
+
for (let index = 0; index < codePoints.length; index++) {
|
|
865
|
+
const codePoint = codePoints[index];
|
|
866
|
+
if (!isHangulJamo(codePoint)) {
|
|
867
|
+
if (width === 0) {
|
|
868
|
+
return undefined;
|
|
869
|
+
}
|
|
870
|
+
for (let remaining = index; remaining < codePoints.length; remaining++) {
|
|
871
|
+
width += eastAsianWidth(codePoints[remaining], eastAsianWidthOptions);
|
|
872
|
+
}
|
|
873
|
+
return width;
|
|
874
|
+
}
|
|
875
|
+
if (
|
|
876
|
+
isHangulLeadingJamo(codePoint) &&
|
|
877
|
+
isHangulVowelJamo(codePoints[index + 1])
|
|
878
|
+
) {
|
|
879
|
+
width += 2;
|
|
880
|
+
index += isHangulTrailingJamo(codePoints[index + 2]) ? 2 : 1;
|
|
881
|
+
continue;
|
|
882
|
+
}
|
|
883
|
+
width += eastAsianWidth(codePoint, eastAsianWidthOptions);
|
|
884
|
+
}
|
|
885
|
+
return width;
|
|
886
|
+
};
|
|
887
|
+
|
|
888
|
+
const trailingHalfwidthWidth = (visibleSegment, eastAsianWidthOptions) => {
|
|
889
|
+
let extra = 0;
|
|
890
|
+
let first = true;
|
|
891
|
+
for (const character of visibleSegment) {
|
|
892
|
+
if (first) {
|
|
893
|
+
first = false;
|
|
894
|
+
continue;
|
|
895
|
+
}
|
|
896
|
+
if (character >= "\uFF00" && character <= "\uFFEF") {
|
|
897
|
+
extra += eastAsianWidth(character.codePointAt(0), eastAsianWidthOptions);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
return extra;
|
|
901
|
+
};
|
|
902
|
+
|
|
803
903
|
const createMeasureTextWidth = ({ stripAnsi }) => {
|
|
804
904
|
const segmenter = new Intl.Segmenter();
|
|
805
|
-
const defaultIgnorableCodePointRegex = /^\p{Default_Ignorable_Code_Point}$/u;
|
|
806
905
|
|
|
807
906
|
const measureTextWidth = (
|
|
808
907
|
string,
|
|
809
|
-
{
|
|
810
|
-
ambiguousIsNarrow = true,
|
|
811
|
-
countAnsiEscapeCodes = false,
|
|
812
|
-
skipEmojis = false,
|
|
813
|
-
} = {},
|
|
908
|
+
{ ambiguousIsNarrow = true, countAnsiEscapeCodes = false } = {},
|
|
814
909
|
) => {
|
|
815
910
|
if (typeof string !== "string" || string.length === 0) {
|
|
816
911
|
return 0;
|
|
817
912
|
}
|
|
818
913
|
|
|
819
|
-
|
|
914
|
+
// Only strip ANSI when escape codes are actually present
|
|
915
|
+
if (
|
|
916
|
+
!countAnsiEscapeCodes &&
|
|
917
|
+
(string.includes("\u001B") || string.includes("\u009B"))
|
|
918
|
+
) {
|
|
820
919
|
string = stripAnsi(string);
|
|
821
920
|
}
|
|
822
921
|
|
|
@@ -824,70 +923,54 @@ const createMeasureTextWidth = ({ stripAnsi }) => {
|
|
|
824
923
|
return 0;
|
|
825
924
|
}
|
|
826
925
|
|
|
926
|
+
// Fast path: printable ASCII needs no segmenter or EAW lookup
|
|
927
|
+
if (/^[\u0020-\u007E]*$/.test(string)) {
|
|
928
|
+
return string.length;
|
|
929
|
+
}
|
|
930
|
+
|
|
827
931
|
let width = 0;
|
|
828
932
|
const eastAsianWidthOptions = { ambiguousAsWide: !ambiguousIsNarrow };
|
|
829
933
|
|
|
830
|
-
for (const { segment
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
// Ignore control characters
|
|
834
|
-
if (codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f)) {
|
|
835
|
-
continue;
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
// Ignore zero-width characters
|
|
839
|
-
if (
|
|
840
|
-
(codePoint >= 0x20_0b && codePoint <= 0x20_0f) || // Zero-width space, non-joiner, joiner, left-to-right mark, right-to-left mark
|
|
841
|
-
codePoint === 0xfe_ff // Zero-width no-break space
|
|
842
|
-
) {
|
|
934
|
+
for (const { segment } of segmenter.segment(string)) {
|
|
935
|
+
if (zeroWidthClusterRegex.test(segment)) {
|
|
843
936
|
continue;
|
|
844
937
|
}
|
|
845
938
|
|
|
846
|
-
//
|
|
939
|
+
// RGI emoji + unqualified emoji sequences are double-width
|
|
847
940
|
if (
|
|
848
|
-
(
|
|
849
|
-
(
|
|
850
|
-
(codePoint >= 0x1d_c0 && codePoint <= 0x1d_ff) || // Combining diacritical marks supplement
|
|
851
|
-
(codePoint >= 0x20_d0 && codePoint <= 0x20_ff) || // Combining diacritical marks for symbols
|
|
852
|
-
(codePoint >= 0xfe_20 && codePoint <= 0xfe_2f) // Combining half marks
|
|
941
|
+
rgiEmojiRegex.test(segment) ||
|
|
942
|
+
isDoubleWidthNonRgiEmojiSequence(segment)
|
|
853
943
|
) {
|
|
944
|
+
if (process.env.CAPTURING_SIDE_EFFECTS && segment === "✔️") {
|
|
945
|
+
width += 2;
|
|
946
|
+
continue;
|
|
947
|
+
}
|
|
948
|
+
width += 2;
|
|
854
949
|
continue;
|
|
855
950
|
}
|
|
856
951
|
|
|
857
|
-
|
|
858
|
-
if (codePoint >= 0xd8_00 && codePoint <= 0xdf_ff) {
|
|
859
|
-
continue;
|
|
860
|
-
}
|
|
952
|
+
const visibleSegment = baseVisible(segment);
|
|
861
953
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
if (defaultIgnorableCodePointRegex.test(character)) {
|
|
869
|
-
continue;
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
if (!skipEmojis && emojiRegex().test(character)) {
|
|
873
|
-
if (process.env.CAPTURING_SIDE_EFFECTS) {
|
|
874
|
-
if (character === "✔️") {
|
|
875
|
-
width += 2;
|
|
876
|
-
continue;
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
width += measureTextWidth(character, {
|
|
880
|
-
skipEmojis: true,
|
|
881
|
-
countAnsiEscapeCodes: true, // to skip call to stripAnsi
|
|
882
|
-
});
|
|
954
|
+
const hangulWidth = hangulClusterWidth(
|
|
955
|
+
visibleSegment,
|
|
956
|
+
eastAsianWidthOptions,
|
|
957
|
+
);
|
|
958
|
+
if (hangulWidth !== undefined) {
|
|
959
|
+
width += hangulWidth;
|
|
883
960
|
continue;
|
|
884
961
|
}
|
|
885
962
|
|
|
963
|
+
// EAW of the cluster's first visible scalar
|
|
964
|
+
const codePoint = visibleSegment.codePointAt(0);
|
|
886
965
|
width += eastAsianWidth(codePoint, eastAsianWidthOptions);
|
|
966
|
+
|
|
967
|
+
// Add width for trailing Halfwidth/Fullwidth Forms (e.g. ゙, ゚, ー)
|
|
968
|
+
width += trailingHalfwidthWidth(visibleSegment, eastAsianWidthOptions);
|
|
887
969
|
}
|
|
888
970
|
|
|
889
971
|
return width;
|
|
890
972
|
};
|
|
973
|
+
|
|
891
974
|
return measureTextWidth;
|
|
892
975
|
};
|
|
893
976
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "41.2.
|
|
3
|
+
"version": "41.2.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Tool to develop, test and build js projects",
|
|
6
6
|
"repository": {
|
|
@@ -72,12 +72,12 @@
|
|
|
72
72
|
"test:snapshot_clear": "npx @jsenv/filesystem clear **/tests/**/side_effects/"
|
|
73
73
|
},
|
|
74
74
|
"dependencies": {
|
|
75
|
-
"@jsenv/ast": "6.8.
|
|
76
|
-
"@jsenv/js-module-fallback": "1.4.
|
|
75
|
+
"@jsenv/ast": "6.8.1",
|
|
76
|
+
"@jsenv/js-module-fallback": "1.4.31",
|
|
77
77
|
"@jsenv/plugin-bundling": "2.10.11",
|
|
78
78
|
"@jsenv/plugin-minification": "1.7.3",
|
|
79
|
-
"@jsenv/plugin-supervisor": "1.8.
|
|
80
|
-
"@jsenv/plugin-transpilation": "1.5.
|
|
79
|
+
"@jsenv/plugin-supervisor": "1.8.2",
|
|
80
|
+
"@jsenv/plugin-transpilation": "1.5.73",
|
|
81
81
|
"@jsenv/server": "17.3.0",
|
|
82
82
|
"@jsenv/sourcemap": "1.3.17",
|
|
83
83
|
"react-table": "7.8.0"
|