@jsenv/test 3.7.23 → 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 +53 -25
- package/package.json +4 -4
package/dist/jsenv_test.js
CHANGED
|
@@ -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
|
};
|
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",
|