@jsenv/test 3.7.22 → 3.7.24
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/jsenv_test.js +76 -53
- package/package.json +4 -4
- package/src/helpers/ping_server.js +9 -23
package/dist/jsenv_test.js
CHANGED
|
@@ -9,7 +9,7 @@ import { cpuUsage, memoryUsage } from "node:process";
|
|
|
9
9
|
import { stripVTControlCharacters } from "node:util";
|
|
10
10
|
import crypto from "node:crypto";
|
|
11
11
|
import { dirname } from "node:path";
|
|
12
|
-
import { createServer } from "node:net";
|
|
12
|
+
import { createConnection, createServer } from "node:net";
|
|
13
13
|
import { spawn, spawnSync, fork } from "node:child_process";
|
|
14
14
|
import { availableParallelism, cpus, totalmem, release, freemem } from "node:os";
|
|
15
15
|
import { SOURCEMAP, generateSourcemapDataUrl } from "@jsenv/sourcemap";
|
|
@@ -854,44 +854,53 @@ const TIME_DICTIONARY_EN = {
|
|
|
854
854
|
second: { long: "second", plural: "seconds", short: "s" },
|
|
855
855
|
joinDuration: (primary, remaining) => `${primary} and ${remaining}`,
|
|
856
856
|
};
|
|
857
|
-
const TIME_DICTIONARY_FR = {
|
|
858
|
-
year: { long: "an", plural: "ans", short: "a" },
|
|
859
|
-
month: { long: "mois", plural: "mois", short: "m" },
|
|
860
|
-
week: { long: "semaine", plural: "semaines", short: "s" },
|
|
861
|
-
day: { long: "jour", plural: "jours", short: "j" },
|
|
862
|
-
hour: { long: "heure", plural: "heures", short: "h" },
|
|
863
|
-
minute: { long: "minute", plural: "minutes", short: "m" },
|
|
864
|
-
second: { long: "seconde", plural: "secondes", short: "s" },
|
|
865
|
-
joinDuration: (primary, remaining) => `${primary} et ${remaining}`,
|
|
866
|
-
};
|
|
867
857
|
|
|
858
|
+
/**
|
|
859
|
+
* Converts a duration in milliseconds into a human-readable string intended for display in
|
|
860
|
+
* CLI output — where readability matters more than precision.
|
|
861
|
+
*
|
|
862
|
+
* - Values below 1ms are displayed as "0 second". Sub-millisecond durations are not
|
|
863
|
+
* meaningful at human scale, and showing "0.0001 second" (or switching to a "millisecond"
|
|
864
|
+
* unit) would hurt readability. The chosen trade-off is to always use "second" as the
|
|
865
|
+
* smallest unit and accept the loss of precision for very small values.
|
|
866
|
+
* - Values below 1s are displayed in fractional seconds (e.g. "0.05 second").
|
|
867
|
+
* - Values are expressed using the two most significant units (e.g. "1 hour and 23 minutes").
|
|
868
|
+
* - Rounding never causes a value to display as the next unit boundary
|
|
869
|
+
* (e.g. 59_999ms → "59.9 seconds", never "60 seconds").
|
|
870
|
+
*
|
|
871
|
+
* @param {number} ms - Duration in milliseconds.
|
|
872
|
+
* @param {object} [options]
|
|
873
|
+
* @param {boolean} [options.short=false] - Use compact unit symbols (e.g. "1h and 23m").
|
|
874
|
+
* @param {boolean} [options.rounded=true] - Round the last displayed digit. When false, truncates instead.
|
|
875
|
+
* @param {number} [options.decimals] - Override the number of decimal places shown.
|
|
876
|
+
* @returns {string}
|
|
877
|
+
*/
|
|
868
878
|
const humanizeDuration = (
|
|
869
879
|
ms,
|
|
870
880
|
{
|
|
871
881
|
short,
|
|
872
882
|
rounded = true,
|
|
873
883
|
decimals,
|
|
874
|
-
|
|
875
|
-
timeDictionnary = lang === "fr" ? TIME_DICTIONARY_FR : TIME_DICTIONARY_EN,
|
|
884
|
+
timeDictionnary = TIME_DICTIONARY_EN,
|
|
876
885
|
} = {},
|
|
877
886
|
) => {
|
|
878
|
-
// ignore ms below meaningfulMs so that:
|
|
879
|
-
// humanizeDuration(0.5) -> "0 second"
|
|
880
|
-
// humanizeDuration(1.1) -> "0.001 second" (and not "0.0011 second")
|
|
881
|
-
// This tool is meant to be read by humans and it would be barely readable to see
|
|
882
|
-
// "0.0001 second" (stands for 0.1 millisecond)
|
|
883
|
-
// yes we could return "0.1 millisecond" but we choosed consistency over precision
|
|
884
|
-
// so that the prefered unit is "second" (and does not become millisecond when ms is super small)
|
|
885
887
|
if (ms < 1) {
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
888
|
+
if (short) {
|
|
889
|
+
return `0${timeDictionnary.second.short}`;
|
|
890
|
+
}
|
|
891
|
+
return `0 ${timeDictionnary.second.long}`;
|
|
889
892
|
}
|
|
890
893
|
const { primary, remaining } = parseMs(ms);
|
|
891
894
|
if (!remaining) {
|
|
895
|
+
const primaryUnitIndex = UNIT_KEYS.indexOf(primary.name);
|
|
896
|
+
const nextUnitName = UNIT_KEYS[primaryUnitIndex - 1];
|
|
897
|
+
const maxCount = nextUnitName
|
|
898
|
+
? UNIT_MS[nextUnitName] / UNIT_MS[primary.name]
|
|
899
|
+
: null;
|
|
892
900
|
return humanizeDurationUnit(primary, {
|
|
893
901
|
decimals:
|
|
894
902
|
decimals === undefined ? (primary.name === "second" ? 1 : 0) : decimals,
|
|
903
|
+
maxCount,
|
|
895
904
|
short,
|
|
896
905
|
rounded,
|
|
897
906
|
timeDictionnary,
|
|
@@ -909,15 +918,23 @@ const humanizeDuration = (
|
|
|
909
918
|
rounded,
|
|
910
919
|
timeDictionnary,
|
|
911
920
|
});
|
|
921
|
+
if (short) {
|
|
922
|
+
return `${primaryText}${remainingText}`;
|
|
923
|
+
}
|
|
912
924
|
return timeDictionnary.joinDuration(primaryText, remainingText);
|
|
913
925
|
};
|
|
914
926
|
const humanizeDurationUnit = (
|
|
915
927
|
unit,
|
|
916
|
-
{ decimals, short, rounded, timeDictionnary },
|
|
928
|
+
{ decimals, maxCount, short, rounded, timeDictionnary },
|
|
917
929
|
) => {
|
|
918
|
-
|
|
930
|
+
let count = rounded
|
|
919
931
|
? setRoundedPrecision(unit.count, { decimals })
|
|
920
932
|
: setPrecision(unit.count, { decimals });
|
|
933
|
+
if (maxCount !== null && maxCount !== undefined && count >= maxCount) {
|
|
934
|
+
// Prevent rounding up to the next unit boundary (e.g. 59.999s → 60s → cap to 59.9s)
|
|
935
|
+
const factor = Math.pow(10, decimals ?? 0);
|
|
936
|
+
count = Math.floor(unit.count * factor) / factor;
|
|
937
|
+
}
|
|
921
938
|
const name = unit.name;
|
|
922
939
|
if (short) {
|
|
923
940
|
const unitText = timeDictionnary[name].short;
|
|
@@ -970,6 +987,17 @@ const parseMs = (ms) => {
|
|
|
970
987
|
},
|
|
971
988
|
};
|
|
972
989
|
}
|
|
990
|
+
// When remaining rounds up to a full next-unit (e.g. 59.999s rounds to 60s = 1min),
|
|
991
|
+
// drop the remaining to avoid displaying "59 minutes and 60 seconds".
|
|
992
|
+
const remainingUnitMs = UNIT_MS[remainingUnitName];
|
|
993
|
+
const nextUnitMs = UNIT_MS[firstUnitName];
|
|
994
|
+
const maxRemainingCount = nextUnitMs / remainingUnitMs; // e.g. 60 for seconds-in-a-minute
|
|
995
|
+
// Cap remaining so it never rounds up to the next unit boundary
|
|
996
|
+
// (e.g. 59.5s stays as 59s instead of rounding to 60s = 1min)
|
|
997
|
+
const cappedRemainingCount =
|
|
998
|
+
remainingUnitCount >= maxRemainingCount - 1
|
|
999
|
+
? maxRemainingCount - 1
|
|
1000
|
+
: remainingUnitCount;
|
|
973
1001
|
// - 1 year and 1 month is great
|
|
974
1002
|
return {
|
|
975
1003
|
primary: {
|
|
@@ -978,7 +1006,7 @@ const parseMs = (ms) => {
|
|
|
978
1006
|
},
|
|
979
1007
|
remaining: {
|
|
980
1008
|
name: remainingUnitName,
|
|
981
|
-
count:
|
|
1009
|
+
count: cappedRemainingCount,
|
|
982
1010
|
},
|
|
983
1011
|
};
|
|
984
1012
|
};
|
|
@@ -4184,13 +4212,11 @@ const applyPackageResolve = (packageSpecifier, resolutionContext) => {
|
|
|
4184
4212
|
if (packageSpecifier === "") {
|
|
4185
4213
|
throw new Error("invalid module specifier");
|
|
4186
4214
|
}
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
isSpecifierForNodeBuiltin(packageSpecifier)
|
|
4190
|
-
) {
|
|
4215
|
+
// "node:" prefixed specifiers always resolve to node builtins
|
|
4216
|
+
if (packageSpecifier.startsWith("node:")) {
|
|
4191
4217
|
return createResolutionResult({
|
|
4192
4218
|
type: "node_builtin_specifier",
|
|
4193
|
-
url:
|
|
4219
|
+
url: packageSpecifier,
|
|
4194
4220
|
});
|
|
4195
4221
|
}
|
|
4196
4222
|
let { packageName, packageSubpath } = parsePackageSpecifier(packageSpecifier);
|
|
@@ -4250,6 +4276,17 @@ const applyPackageResolve = (packageSpecifier, resolutionContext) => {
|
|
|
4250
4276
|
packageJson,
|
|
4251
4277
|
});
|
|
4252
4278
|
}
|
|
4279
|
+
// Bare builtin names (without "node:" prefix) are valid only if no local package found
|
|
4280
|
+
// Local packages always take priority over builtins with the same name
|
|
4281
|
+
if (
|
|
4282
|
+
conditions.includes("node") &&
|
|
4283
|
+
isSpecifierForNodeBuiltin(packageSpecifier)
|
|
4284
|
+
) {
|
|
4285
|
+
return createResolutionResult({
|
|
4286
|
+
type: "node_builtin_specifier",
|
|
4287
|
+
url: `node:${packageSpecifier}`,
|
|
4288
|
+
});
|
|
4289
|
+
}
|
|
4253
4290
|
throw createModuleNotFoundError(packageName, resolutionContext);
|
|
4254
4291
|
};
|
|
4255
4292
|
|
|
@@ -7203,32 +7240,18 @@ const basicFetch = async (
|
|
|
7203
7240
|
};
|
|
7204
7241
|
|
|
7205
7242
|
const pingServer = async (url) => {
|
|
7206
|
-
const server = createServer();
|
|
7207
7243
|
const { hostname, port } = new URL(url);
|
|
7208
7244
|
|
|
7209
|
-
|
|
7210
|
-
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7245
|
+
return new Promise((resolve) => {
|
|
7246
|
+
const socket = createConnection({ hostname, port: Number(port) });
|
|
7247
|
+
socket.on("connect", () => {
|
|
7248
|
+
socket.destroy();
|
|
7249
|
+
resolve(true);
|
|
7250
|
+
});
|
|
7251
|
+
socket.on("error", () => {
|
|
7252
|
+
resolve(false);
|
|
7216
7253
|
});
|
|
7217
|
-
} catch (error) {
|
|
7218
|
-
if (error && error.code === "EADDRINUSE") {
|
|
7219
|
-
return true;
|
|
7220
|
-
}
|
|
7221
|
-
if (error && error.code === "EACCES") {
|
|
7222
|
-
return true;
|
|
7223
|
-
}
|
|
7224
|
-
throw error;
|
|
7225
|
-
}
|
|
7226
|
-
await new Promise((resolve, reject) => {
|
|
7227
|
-
server.on("error", reject);
|
|
7228
|
-
server.on("close", resolve);
|
|
7229
|
-
server.close();
|
|
7230
7254
|
});
|
|
7231
|
-
return false;
|
|
7232
7255
|
};
|
|
7233
7256
|
|
|
7234
7257
|
const startServerUsingCommand = async (
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/test",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.24",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@c88/v8-coverage": "0.1.1",
|
|
33
|
-
"@jsenv/ast": "6.8.
|
|
34
|
-
"@jsenv/plugin-supervisor": "1.8.
|
|
35
|
-
"@jsenv/sourcemap": "1.3.
|
|
33
|
+
"@jsenv/ast": "6.8.3",
|
|
34
|
+
"@jsenv/plugin-supervisor": "1.8.4",
|
|
35
|
+
"@jsenv/sourcemap": "1.3.19",
|
|
36
36
|
"he": "1.2.0",
|
|
37
37
|
"istanbul-lib-coverage": "3.2.2",
|
|
38
38
|
"istanbul-lib-instrument": "6.0.3",
|
|
@@ -1,30 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createConnection } from "node:net";
|
|
2
2
|
|
|
3
3
|
export const pingServer = async (url) => {
|
|
4
|
-
const server = createServer();
|
|
5
4
|
const { hostname, port } = new URL(url);
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
return new Promise((resolve) => {
|
|
7
|
+
const socket = createConnection({ hostname, port: Number(port) });
|
|
8
|
+
socket.on("connect", () => {
|
|
9
|
+
socket.destroy();
|
|
10
|
+
resolve(true);
|
|
11
|
+
});
|
|
12
|
+
socket.on("error", () => {
|
|
13
|
+
resolve(false);
|
|
14
14
|
});
|
|
15
|
-
} catch (error) {
|
|
16
|
-
if (error && error.code === "EADDRINUSE") {
|
|
17
|
-
return true;
|
|
18
|
-
}
|
|
19
|
-
if (error && error.code === "EACCES") {
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
throw error;
|
|
23
|
-
}
|
|
24
|
-
await new Promise((resolve, reject) => {
|
|
25
|
-
server.on("error", reject);
|
|
26
|
-
server.on("close", resolve);
|
|
27
|
-
server.close();
|
|
28
15
|
});
|
|
29
|
-
return false;
|
|
30
16
|
};
|