@jsenv/core 41.2.6 → 41.2.8
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/build.js +24 -1
- package/dist/build/jsenv_core_node_modules.js +14 -22
- package/dist/build/jsenv_core_packages.js +149 -57
- package/dist/client/directory_listing/directory_listing.html +1 -0
- 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 +149 -57
- package/dist/start_dev_server/start_dev_server.js +25 -2
- package/package.json +7 -7
- package/src/dev/start_dev_server.js +1 -1
- package/src/plugins/protocol_file/client/directory_listing.html +1 -0
- package/src/plugins/protocol_file/jsenv_plugin_directory_listing.js +24 -1
package/dist/build/build.js
CHANGED
|
@@ -6411,7 +6411,30 @@ const jsenvPluginDirectoryListing = ({
|
|
|
6411
6411
|
const { request, requestedUrl, mainFilePath, rootDirectoryUrl } =
|
|
6412
6412
|
reference.ownerUrlInfo.context;
|
|
6413
6413
|
if (!fsStat) {
|
|
6414
|
-
if (!request
|
|
6414
|
+
if (!request) {
|
|
6415
|
+
// no request we should not serve directoy listing
|
|
6416
|
+
return null;
|
|
6417
|
+
}
|
|
6418
|
+
const secFetchDest = request.headers["sec-fetch-dest"];
|
|
6419
|
+
if (secFetchDest && secFetchDest !== "document") {
|
|
6420
|
+
// we have sec fetch dest and it's not document so it's not a navigation request, we should not serve directory listing
|
|
6421
|
+
return null;
|
|
6422
|
+
}
|
|
6423
|
+
if (!secFetchDest) {
|
|
6424
|
+
// beware we might end up here when nav context is not trusted (http, ip url etc)
|
|
6425
|
+
// in that case we fallback to detecting if the request explicitly accepts html.
|
|
6426
|
+
// browsers navigating to a page send "text/html,..." explicitly; programmatic
|
|
6427
|
+
// fetch clients like Node.js send "*/*" which should NOT trigger directory listing.
|
|
6428
|
+
// We must NOT use pickContentType here because it matches "text/html" via the
|
|
6429
|
+
// "*/*" wildcard, causing programmatic fetches to receive the directory listing
|
|
6430
|
+
// HTML page (status 200) instead of a 404.
|
|
6431
|
+
const acceptHeader = request.headers.accept || "";
|
|
6432
|
+
if (!acceptHeader.includes("text/html")) {
|
|
6433
|
+
return null;
|
|
6434
|
+
}
|
|
6435
|
+
}
|
|
6436
|
+
// requestedUrl must be a proper file:// URL (no encoded slashes)
|
|
6437
|
+
if (requestedUrl.includes("%2F") || requestedUrl.includes("%2f")) {
|
|
6415
6438
|
return null;
|
|
6416
6439
|
}
|
|
6417
6440
|
if (url !== requestedUrl) {
|
|
@@ -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
|
-
}
|
|
1498
|
-
|
|
1499
|
-
// Ignore variation selectors
|
|
1500
|
-
if (codePoint >= 0xfe_00 && codePoint <= 0xfe_0f) {
|
|
1501
|
-
continue;
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
|
-
// This covers some of the above cases, but we still keep them for performance reasons.
|
|
1505
|
-
if (defaultIgnorableCodePointRegex.test(character)) {
|
|
1506
|
-
continue;
|
|
1507
|
-
}
|
|
1589
|
+
const visibleSegment = baseVisible(segment);
|
|
1508
1590
|
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
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
|
|
|
@@ -5659,13 +5742,11 @@ const applyPackageResolve = (packageSpecifier, resolutionContext) => {
|
|
|
5659
5742
|
if (packageSpecifier === "") {
|
|
5660
5743
|
throw new Error("invalid module specifier");
|
|
5661
5744
|
}
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
isSpecifierForNodeBuiltin(packageSpecifier)
|
|
5665
|
-
) {
|
|
5745
|
+
// "node:" prefixed specifiers always resolve to node builtins
|
|
5746
|
+
if (packageSpecifier.startsWith("node:")) {
|
|
5666
5747
|
return createResolutionResult({
|
|
5667
5748
|
type: "node_builtin_specifier",
|
|
5668
|
-
url:
|
|
5749
|
+
url: packageSpecifier,
|
|
5669
5750
|
});
|
|
5670
5751
|
}
|
|
5671
5752
|
let { packageName, packageSubpath } = parsePackageSpecifier(packageSpecifier);
|
|
@@ -5725,6 +5806,17 @@ const applyPackageResolve = (packageSpecifier, resolutionContext) => {
|
|
|
5725
5806
|
packageJson,
|
|
5726
5807
|
});
|
|
5727
5808
|
}
|
|
5809
|
+
// Bare builtin names (without "node:" prefix) are valid only if no local package found
|
|
5810
|
+
// Local packages always take priority over builtins with the same name
|
|
5811
|
+
if (
|
|
5812
|
+
conditions.includes("node") &&
|
|
5813
|
+
isSpecifierForNodeBuiltin(packageSpecifier)
|
|
5814
|
+
) {
|
|
5815
|
+
return createResolutionResult({
|
|
5816
|
+
type: "node_builtin_specifier",
|
|
5817
|
+
url: `node:${packageSpecifier}`,
|
|
5818
|
+
});
|
|
5819
|
+
}
|
|
5728
5820
|
throw createModuleNotFoundError(packageName, resolutionContext);
|
|
5729
5821
|
};
|
|
5730
5822
|
|
|
@@ -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
|
-
}
|
|
861
|
-
|
|
862
|
-
// Ignore variation selectors
|
|
863
|
-
if (codePoint >= 0xfe_00 && codePoint <= 0xfe_0f) {
|
|
864
|
-
continue;
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
// This covers some of the above cases, but we still keep them for performance reasons.
|
|
868
|
-
if (defaultIgnorableCodePointRegex.test(character)) {
|
|
869
|
-
continue;
|
|
870
|
-
}
|
|
952
|
+
const visibleSegment = baseVisible(segment);
|
|
871
953
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
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
|
|
|
@@ -5125,13 +5208,11 @@ const applyPackageResolve = (packageSpecifier, resolutionContext) => {
|
|
|
5125
5208
|
if (packageSpecifier === "") {
|
|
5126
5209
|
throw new Error("invalid module specifier");
|
|
5127
5210
|
}
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
isSpecifierForNodeBuiltin(packageSpecifier)
|
|
5131
|
-
) {
|
|
5211
|
+
// "node:" prefixed specifiers always resolve to node builtins
|
|
5212
|
+
if (packageSpecifier.startsWith("node:")) {
|
|
5132
5213
|
return createResolutionResult({
|
|
5133
5214
|
type: "node_builtin_specifier",
|
|
5134
|
-
url:
|
|
5215
|
+
url: packageSpecifier,
|
|
5135
5216
|
});
|
|
5136
5217
|
}
|
|
5137
5218
|
let { packageName, packageSubpath } = parsePackageSpecifier(packageSpecifier);
|
|
@@ -5191,6 +5272,17 @@ const applyPackageResolve = (packageSpecifier, resolutionContext) => {
|
|
|
5191
5272
|
packageJson,
|
|
5192
5273
|
});
|
|
5193
5274
|
}
|
|
5275
|
+
// Bare builtin names (without "node:" prefix) are valid only if no local package found
|
|
5276
|
+
// Local packages always take priority over builtins with the same name
|
|
5277
|
+
if (
|
|
5278
|
+
conditions.includes("node") &&
|
|
5279
|
+
isSpecifierForNodeBuiltin(packageSpecifier)
|
|
5280
|
+
) {
|
|
5281
|
+
return createResolutionResult({
|
|
5282
|
+
type: "node_builtin_specifier",
|
|
5283
|
+
url: `node:${packageSpecifier}`,
|
|
5284
|
+
});
|
|
5285
|
+
}
|
|
5194
5286
|
throw createModuleNotFoundError(packageName, resolutionContext);
|
|
5195
5287
|
};
|
|
5196
5288
|
|
|
@@ -2471,7 +2471,30 @@ const jsenvPluginDirectoryListing = ({
|
|
|
2471
2471
|
const { request, requestedUrl, mainFilePath, rootDirectoryUrl } =
|
|
2472
2472
|
reference.ownerUrlInfo.context;
|
|
2473
2473
|
if (!fsStat) {
|
|
2474
|
-
if (!request
|
|
2474
|
+
if (!request) {
|
|
2475
|
+
// no request we should not serve directoy listing
|
|
2476
|
+
return null;
|
|
2477
|
+
}
|
|
2478
|
+
const secFetchDest = request.headers["sec-fetch-dest"];
|
|
2479
|
+
if (secFetchDest && secFetchDest !== "document") {
|
|
2480
|
+
// we have sec fetch dest and it's not document so it's not a navigation request, we should not serve directory listing
|
|
2481
|
+
return null;
|
|
2482
|
+
}
|
|
2483
|
+
if (!secFetchDest) {
|
|
2484
|
+
// beware we might end up here when nav context is not trusted (http, ip url etc)
|
|
2485
|
+
// in that case we fallback to detecting if the request explicitly accepts html.
|
|
2486
|
+
// browsers navigating to a page send "text/html,..." explicitly; programmatic
|
|
2487
|
+
// fetch clients like Node.js send "*/*" which should NOT trigger directory listing.
|
|
2488
|
+
// We must NOT use pickContentType here because it matches "text/html" via the
|
|
2489
|
+
// "*/*" wildcard, causing programmatic fetches to receive the directory listing
|
|
2490
|
+
// HTML page (status 200) instead of a 404.
|
|
2491
|
+
const acceptHeader = request.headers.accept || "";
|
|
2492
|
+
if (!acceptHeader.includes("text/html")) {
|
|
2493
|
+
return null;
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
// requestedUrl must be a proper file:// URL (no encoded slashes)
|
|
2497
|
+
if (requestedUrl.includes("%2F") || requestedUrl.includes("%2f")) {
|
|
2475
2498
|
return null;
|
|
2476
2499
|
}
|
|
2477
2500
|
if (url !== requestedUrl) {
|
|
@@ -10148,7 +10171,7 @@ const startDevServer = async ({
|
|
|
10148
10171
|
ignore,
|
|
10149
10172
|
port = 3456,
|
|
10150
10173
|
hostname,
|
|
10151
|
-
acceptAnyIp,
|
|
10174
|
+
acceptAnyIp = true,
|
|
10152
10175
|
https,
|
|
10153
10176
|
// it's better to use http1 by default because it allows to get statusText in devtools
|
|
10154
10177
|
// which gives valuable information when there is errors
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "41.2.
|
|
3
|
+
"version": "41.2.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Tool to develop, test and build js projects",
|
|
6
6
|
"repository": {
|
|
@@ -72,14 +72,14 @@
|
|
|
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.
|
|
77
|
-
"@jsenv/plugin-bundling": "2.10.
|
|
75
|
+
"@jsenv/ast": "6.8.2",
|
|
76
|
+
"@jsenv/js-module-fallback": "1.4.32",
|
|
77
|
+
"@jsenv/plugin-bundling": "2.10.12",
|
|
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.3",
|
|
80
|
+
"@jsenv/plugin-transpilation": "1.5.74",
|
|
81
81
|
"@jsenv/server": "17.3.0",
|
|
82
|
-
"@jsenv/sourcemap": "1.3.
|
|
82
|
+
"@jsenv/sourcemap": "1.3.18",
|
|
83
83
|
"react-table": "7.8.0"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
@@ -53,7 +53,7 @@ export const startDevServer = async ({
|
|
|
53
53
|
ignore,
|
|
54
54
|
port = 3456,
|
|
55
55
|
hostname,
|
|
56
|
-
acceptAnyIp,
|
|
56
|
+
acceptAnyIp = true,
|
|
57
57
|
https,
|
|
58
58
|
// it's better to use http1 by default because it allows to get statusText in devtools
|
|
59
59
|
// which gives valuable information when there is errors
|
|
@@ -71,7 +71,30 @@ export const jsenvPluginDirectoryListing = ({
|
|
|
71
71
|
const { request, requestedUrl, mainFilePath, rootDirectoryUrl } =
|
|
72
72
|
reference.ownerUrlInfo.context;
|
|
73
73
|
if (!fsStat) {
|
|
74
|
-
if (!request
|
|
74
|
+
if (!request) {
|
|
75
|
+
// no request we should not serve directoy listing
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const secFetchDest = request.headers["sec-fetch-dest"];
|
|
79
|
+
if (secFetchDest && secFetchDest !== "document") {
|
|
80
|
+
// we have sec fetch dest and it's not document so it's not a navigation request, we should not serve directory listing
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
if (!secFetchDest) {
|
|
84
|
+
// beware we might end up here when nav context is not trusted (http, ip url etc)
|
|
85
|
+
// in that case we fallback to detecting if the request explicitly accepts html.
|
|
86
|
+
// browsers navigating to a page send "text/html,..." explicitly; programmatic
|
|
87
|
+
// fetch clients like Node.js send "*/*" which should NOT trigger directory listing.
|
|
88
|
+
// We must NOT use pickContentType here because it matches "text/html" via the
|
|
89
|
+
// "*/*" wildcard, causing programmatic fetches to receive the directory listing
|
|
90
|
+
// HTML page (status 200) instead of a 404.
|
|
91
|
+
const acceptHeader = request.headers.accept || "";
|
|
92
|
+
if (!acceptHeader.includes("text/html")) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// requestedUrl must be a proper file:// URL (no encoded slashes)
|
|
97
|
+
if (requestedUrl.includes("%2F") || requestedUrl.includes("%2f")) {
|
|
75
98
|
return null;
|
|
76
99
|
}
|
|
77
100
|
if (url !== requestedUrl) {
|