@jsenv/test 3.0.13 → 3.0.14

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.
@@ -88,7 +88,7 @@ const applyMatching = (pattern, string) => {
88
88
  }
89
89
  // pattern consumed, string not consumed
90
90
  if (remainingPattern === "" && remainingString !== "") {
91
- return false; // fails because string longer than expected
91
+ return false; // fails because string longer than expect
92
92
  }
93
93
  // -- from this point pattern is not consumed --
94
94
  // string consumed, pattern not consumed
@@ -101,7 +101,7 @@ const applyMatching = (pattern, string) => {
101
101
  if (remainingPattern === "*") {
102
102
  groups.push({ string: "" });
103
103
  }
104
- return false; // fail because string shorter than expected
104
+ return false; // fail because string shorter than expect
105
105
  }
106
106
  // -- from this point pattern and string are not consumed --
107
107
  // fast path trailing slash
@@ -163,7 +163,7 @@ const applyMatching = (pattern, string) => {
163
163
  groups.push({ string: consumeString(slashIndex) });
164
164
  return false;
165
165
  }
166
- // the next char must not the one expected by remainingPattern[0]
166
+ // the next char must not the one expect by remainingPattern[0]
167
167
  // because * is greedy and expect to skip at least one char
168
168
  if (remainingPattern[0] === remainingString[0]) {
169
169
  groups.push({ string: "" });
@@ -709,7 +709,7 @@ function parseStackTrace(stack) {
709
709
 
710
710
 
711
711
  const isDev = process.execArgv.includes("--conditions=development");
712
- const jsenvCoreDirectoryUrl = new URL("file:///Users/d.maillard/dev/jsenv/jsenv-core/", import.meta.url);
712
+ const jsenvCoreDirectoryUrl = new URL("file:///Users/damien.maillard/dev/perso/jsenv-core/", import.meta.url);
713
713
 
714
714
  const createException = (reason, { rootDirectoryUrl } = {}) => {
715
715
  const exception = {
@@ -5,6 +5,7 @@ import { takeCoverage } from "node:v8";
5
5
  import stripAnsi from "strip-ansi";
6
6
  import { URL_META, createException } from "./js/exception.js";
7
7
  import stringWidth from "string-width";
8
+ import { isBrowser } from "environment";
8
9
  import tty from "node:tty";
9
10
  import { pathToFileURL, fileURLToPath } from "node:url";
10
11
  import { dirname } from "node:path";
@@ -16,7 +17,7 @@ import { applyBabelPlugins } from "@jsenv/ast";
16
17
  import { spawn, spawnSync, fork } from "node:child_process";
17
18
  import { createServer } from "node:net";
18
19
  import { injectSupervisorIntoHTML, supervisorFileUrl } from "@jsenv/plugin-supervisor";
19
- import { generateSourcemapDataUrl, SOURCEMAP } from "@jsenv/sourcemap";
20
+ import { SOURCEMAP, generateSourcemapDataUrl } from "@jsenv/sourcemap";
20
21
  import { findFreePort } from "@jsenv/server";
21
22
  import { Worker } from "node:worker_threads";
22
23
  import he from "he";
@@ -207,7 +208,7 @@ const createOperation = () => {
207
208
  const operationSignal = operationAbortController.signal;
208
209
 
209
210
  // abortCallbackList is used to ignore the max listeners warning from Node.js
210
- // this warning is useful but becomes problematic when it's expected
211
+ // this warning is useful but becomes problematic when it's expect
211
212
  // (a function doing 20 http call in parallel)
212
213
  // To be 100% sure we don't have memory leak, only Abortable.asyncCallback
213
214
  // uses abortCallbackList to know when something is aborted
@@ -619,169 +620,41 @@ const error = (...args) => console.error(...args);
619
620
  const errorDisabled = () => {};
620
621
 
621
622
  const ESC = '\u001B[';
622
- const OSC = '\u001B]';
623
- const BEL = '\u0007';
624
- const SEP = ';';
625
623
 
626
- /* global window */
627
- const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
628
-
629
- const isTerminalApp = !isBrowser && process$1.env.TERM_PROGRAM === 'Apple_Terminal';
624
+ !isBrowser && process$1.env.TERM_PROGRAM === 'Apple_Terminal';
630
625
  const isWindows$3 = !isBrowser && process$1.platform === 'win32';
631
- const cwdFunction = isBrowser ? () => {
626
+
627
+ isBrowser ? () => {
632
628
  throw new Error('`process.cwd()` only works in Node.js, not the browser.');
633
629
  } : process$1.cwd;
634
630
 
635
- const ansiEscapes = {};
636
-
637
- ansiEscapes.cursorTo = (x, y) => {
638
- if (typeof x !== 'number') {
639
- throw new TypeError('The `x` argument is required');
640
- }
641
-
642
- if (typeof y !== 'number') {
643
- return ESC + (x + 1) + 'G';
644
- }
645
-
646
- return ESC + (y + 1) + SEP + (x + 1) + 'H';
647
- };
648
-
649
- ansiEscapes.cursorMove = (x, y) => {
650
- if (typeof x !== 'number') {
651
- throw new TypeError('The `x` argument is required');
652
- }
653
-
654
- let returnValue = '';
655
-
656
- if (x < 0) {
657
- returnValue += ESC + (-x) + 'D';
658
- } else if (x > 0) {
659
- returnValue += ESC + x + 'C';
660
- }
661
-
662
- if (y < 0) {
663
- returnValue += ESC + (-y) + 'A';
664
- } else if (y > 0) {
665
- returnValue += ESC + y + 'B';
666
- }
667
-
668
- return returnValue;
669
- };
670
-
671
- ansiEscapes.cursorUp = (count = 1) => ESC + count + 'A';
672
- ansiEscapes.cursorDown = (count = 1) => ESC + count + 'B';
673
- ansiEscapes.cursorForward = (count = 1) => ESC + count + 'C';
674
- ansiEscapes.cursorBackward = (count = 1) => ESC + count + 'D';
631
+ const cursorUp = (count = 1) => ESC + count + 'A';
675
632
 
676
- ansiEscapes.cursorLeft = ESC + 'G';
677
- ansiEscapes.cursorSavePosition = isTerminalApp ? '\u001B7' : ESC + 's';
678
- ansiEscapes.cursorRestorePosition = isTerminalApp ? '\u001B8' : ESC + 'u';
679
- ansiEscapes.cursorGetPosition = ESC + '6n';
680
- ansiEscapes.cursorNextLine = ESC + 'E';
681
- ansiEscapes.cursorPrevLine = ESC + 'F';
682
- ansiEscapes.cursorHide = ESC + '?25l';
683
- ansiEscapes.cursorShow = ESC + '?25h';
633
+ const cursorLeft = ESC + 'G';
684
634
 
685
- ansiEscapes.eraseLines = count => {
635
+ const eraseLines = count => {
686
636
  let clear = '';
687
637
 
688
638
  for (let i = 0; i < count; i++) {
689
- clear += ansiEscapes.eraseLine + (i < count - 1 ? ansiEscapes.cursorUp() : '');
639
+ clear += eraseLine + (i < count - 1 ? cursorUp() : '');
690
640
  }
691
641
 
692
642
  if (count) {
693
- clear += ansiEscapes.cursorLeft;
643
+ clear += cursorLeft;
694
644
  }
695
645
 
696
646
  return clear;
697
647
  };
648
+ const eraseLine = ESC + '2K';
649
+ const eraseScreen = ESC + '2J';
698
650
 
699
- ansiEscapes.eraseEndLine = ESC + 'K';
700
- ansiEscapes.eraseStartLine = ESC + '1K';
701
- ansiEscapes.eraseLine = ESC + '2K';
702
- ansiEscapes.eraseDown = ESC + 'J';
703
- ansiEscapes.eraseUp = ESC + '1J';
704
- ansiEscapes.eraseScreen = ESC + '2J';
705
- ansiEscapes.scrollUp = ESC + 'S';
706
- ansiEscapes.scrollDown = ESC + 'T';
707
-
708
- ansiEscapes.clearScreen = '\u001Bc';
709
-
710
- ansiEscapes.clearTerminal = isWindows$3
711
- ? `${ansiEscapes.eraseScreen}${ESC}0f`
651
+ const clearTerminal = isWindows$3
652
+ ? `${eraseScreen}${ESC}0f`
712
653
  // 1. Erases the screen (Only done in case `2` is not supported)
713
654
  // 2. Erases the whole screen including scrollback buffer
714
655
  // 3. Moves cursor to the top-left position
715
656
  // More info: https://www.real-world-systems.com/docs/ANSIcode.html
716
- : `${ansiEscapes.eraseScreen}${ESC}3J${ESC}H`;
717
-
718
- ansiEscapes.enterAlternativeScreen = ESC + '?1049h';
719
- ansiEscapes.exitAlternativeScreen = ESC + '?1049l';
720
-
721
- ansiEscapes.beep = BEL;
722
-
723
- ansiEscapes.link = (text, url) => [
724
- OSC,
725
- '8',
726
- SEP,
727
- SEP,
728
- url,
729
- BEL,
730
- text,
731
- OSC,
732
- '8',
733
- SEP,
734
- SEP,
735
- BEL,
736
- ].join('');
737
-
738
- ansiEscapes.image = (buffer, options = {}) => {
739
- let returnValue = `${OSC}1337;File=inline=1`;
740
-
741
- if (options.width) {
742
- returnValue += `;width=${options.width}`;
743
- }
744
-
745
- if (options.height) {
746
- returnValue += `;height=${options.height}`;
747
- }
748
-
749
- if (options.preserveAspectRatio === false) {
750
- returnValue += ';preserveAspectRatio=0';
751
- }
752
-
753
- return returnValue + ':' + buffer.toString('base64') + BEL;
754
- };
755
-
756
- ansiEscapes.iTerm = {
757
- setCwd: (cwd = cwdFunction()) => `${OSC}50;CurrentDir=${cwd}${BEL}`,
758
-
759
- annotation(message, options = {}) {
760
- let returnValue = `${OSC}1337;`;
761
-
762
- const hasX = typeof options.x !== 'undefined';
763
- const hasY = typeof options.y !== 'undefined';
764
- if ((hasX || hasY) && !(hasX && hasY && typeof options.length !== 'undefined')) {
765
- throw new Error('`x`, `y` and `length` must be defined when `x` or `y` is defined');
766
- }
767
-
768
- message = message.replace(/\|/g, '');
769
-
770
- returnValue += options.isHidden ? 'AddHiddenAnnotation=' : 'AddAnnotation=';
771
-
772
- if (options.length > 0) {
773
- returnValue += (
774
- hasX
775
- ? [message, options.length, options.x, options.y]
776
- : [options.length, message]
777
- ).join('|');
778
- } else {
779
- returnValue += message;
780
- }
781
-
782
- return returnValue + BEL;
783
- },
784
- };
657
+ : `${eraseScreen}${ESC}3J${ESC}H`;
785
658
 
786
659
  /*
787
660
  * see also https://github.com/vadimdemedes/ink
@@ -829,7 +702,7 @@ const createDynamicLog = ({
829
702
  if (visualLineCount > rows) {
830
703
  if (clearTerminalAllowed) {
831
704
  clearAttemptResult = true;
832
- return ansiEscapes.clearTerminal;
705
+ return clearTerminal;
833
706
  }
834
707
  // the whole log cannot be cleared because it's vertically to long
835
708
  // (longer than terminal height)
@@ -842,7 +715,7 @@ const createDynamicLog = ({
842
715
  }
843
716
 
844
717
  clearAttemptResult = true;
845
- return ansiEscapes.eraseLines(visualLineCount);
718
+ return eraseLines(visualLineCount);
846
719
  };
847
720
 
848
721
  const update = (string) => {
@@ -871,20 +744,22 @@ const createDynamicLog = ({
871
744
  clearAttemptResult = undefined;
872
745
  };
873
746
 
874
- const clearDuringFunctionCall = (callback) => {
747
+ const clearDuringFunctionCall = (
748
+ callback,
749
+ ouputAfterCallback = lastOutput,
750
+ ) => {
875
751
  // 1. Erase the current log
876
- // 2. Call callback (expected to write something on stdout)
752
+ // 2. Call callback (expect to write something on stdout)
877
753
  // 3. Restore the current log
878
754
  // During step 2. we expect a "write from outside" so we uninstall
879
755
  // the stream spy during function call
880
- const currentOutput = lastOutput;
881
756
  update("");
882
757
 
883
758
  writing = true;
884
759
  callback();
885
760
  writing = false;
886
761
 
887
- update(currentOutput);
762
+ update(ouputAfterCallback);
888
763
  };
889
764
 
890
765
  const writeFromOutsideEffect = (value) => {
@@ -1139,10 +1014,10 @@ function createSupportsColor(stream, options = {}) {
1139
1014
  return translateLevel(level);
1140
1015
  }
1141
1016
 
1142
- ({
1017
+ const supportsColor = {
1143
1018
  stdout: createSupportsColor({isTTY: tty.isatty(1)}),
1144
1019
  stderr: createSupportsColor({isTTY: tty.isatty(2)}),
1145
- });
1020
+ };
1146
1021
 
1147
1022
  const processSupportsBasicColor = createSupportsColor(process.stdout).hasBasic;
1148
1023
  // https://github.com/Marak/colors.js/blob/master/lib/styles.js
@@ -1157,14 +1032,19 @@ const ANSI = {
1157
1032
  YELLOW: "\x1b[33m",
1158
1033
  BLUE: "\x1b[34m",
1159
1034
  MAGENTA: "\x1b[35m",
1035
+ CYAN: "\x1b[36m",
1160
1036
  GREY: "\x1b[90m",
1161
1037
  color: (text, ANSI_COLOR) => {
1162
- return ANSI.supported ? `${ANSI_COLOR}${text}${RESET}` : text;
1038
+ return ANSI.supported && ANSI_COLOR ? `${ANSI_COLOR}${text}${RESET}` : text;
1163
1039
  },
1164
1040
 
1165
1041
  BOLD: "\x1b[1m",
1042
+ UNDERLINE: "\x1b[4m",
1043
+ STRIKE: "\x1b[9m",
1166
1044
  effect: (text, ANSI_EFFECT) => {
1167
- return ANSI.supported ? `${ANSI_EFFECT}${text}${RESET}` : text;
1045
+ return ANSI.supported && ANSI_EFFECT
1046
+ ? `${ANSI_EFFECT}${text}${RESET}`
1047
+ : text;
1168
1048
  },
1169
1049
  };
1170
1050
 
@@ -1432,6 +1312,9 @@ const UNICODE = {
1432
1312
  get CIRCLE_CROSS() {
1433
1313
  return ANSI.color(UNICODE.CIRCLE_CROSS_RAW, ANSI.RED);
1434
1314
  },
1315
+ get ELLIPSIS() {
1316
+ return UNICODE.supported ? `…` : `...`;
1317
+ },
1435
1318
  };
1436
1319
 
1437
1320
  const createDetailedMessage = (message, details = {}) => {
@@ -2078,7 +1961,7 @@ const ensureWindowsDriveLetter = (url, baseUrl) => {
2078
1961
  try {
2079
1962
  url = String(new URL(url));
2080
1963
  } catch (e) {
2081
- throw new Error(`absolute url expected but got ${url}`);
1964
+ throw new Error(`absolute url expect but got ${url}`);
2082
1965
  }
2083
1966
 
2084
1967
  if (!isWindows$2) {
@@ -2089,7 +1972,7 @@ const ensureWindowsDriveLetter = (url, baseUrl) => {
2089
1972
  baseUrl = String(new URL(baseUrl));
2090
1973
  } catch (e) {
2091
1974
  throw new Error(
2092
- `absolute baseUrl expected but got ${baseUrl} to ensure windows drive letter on ${url}`,
1975
+ `absolute baseUrl expect but got ${baseUrl} to ensure windows drive letter on ${url}`,
2093
1976
  );
2094
1977
  }
2095
1978
 
@@ -2111,7 +1994,7 @@ const ensureWindowsDriveLetter = (url, baseUrl) => {
2111
1994
  );
2112
1995
  if (!driveLetter) {
2113
1996
  throw new Error(
2114
- `drive letter expected on baseUrl but got ${baseUrl} to ensure windows drive letter on ${url}`,
1997
+ `drive letter expect on baseUrl but got ${baseUrl} to ensure windows drive letter on ${url}`,
2115
1998
  );
2116
1999
  }
2117
2000
  return `file:///${driveLetter}:${afterProtocol}`;
@@ -2162,67 +2045,11 @@ const readDirectory = async (url, { emfileMaxWait = 1000 } = {}) => {
2162
2045
  return attempt();
2163
2046
  };
2164
2047
 
2165
- // https://github.com/coderaiser/cloudcmd/issues/63#issuecomment-195478143
2166
- // https://nodejs.org/api/fs.html#fs_file_modes
2167
- // https://github.com/TooTallNate/stat-mode
2168
-
2169
- // cannot get from fs.constants because they are not available on windows
2170
- const S_IRUSR = 256; /* 0000400 read permission, owner */
2171
- const S_IWUSR = 128; /* 0000200 write permission, owner */
2172
- const S_IXUSR = 64; /* 0000100 execute/search permission, owner */
2173
- const S_IRGRP = 32; /* 0000040 read permission, group */
2174
- const S_IWGRP = 16; /* 0000020 write permission, group */
2175
- const S_IXGRP = 8; /* 0000010 execute/search permission, group */
2176
- const S_IROTH = 4; /* 0000004 read permission, others */
2177
- const S_IWOTH = 2; /* 0000002 write permission, others */
2178
- const S_IXOTH = 1; /* 0000001 execute/search permission, others */
2179
-
2180
- const permissionsToBinaryFlags = ({ owner, group, others }) => {
2181
- let binaryFlags = 0;
2182
-
2183
- if (owner.read) binaryFlags |= S_IRUSR;
2184
- if (owner.write) binaryFlags |= S_IWUSR;
2185
- if (owner.execute) binaryFlags |= S_IXUSR;
2186
-
2187
- if (group.read) binaryFlags |= S_IRGRP;
2188
- if (group.write) binaryFlags |= S_IWGRP;
2189
- if (group.execute) binaryFlags |= S_IXGRP;
2190
-
2191
- if (others.read) binaryFlags |= S_IROTH;
2192
- if (others.write) binaryFlags |= S_IWOTH;
2193
- if (others.execute) binaryFlags |= S_IXOTH;
2194
-
2195
- return binaryFlags;
2196
- };
2197
-
2198
2048
  const writeEntryPermissions = async (source, permissions) => {
2199
2049
  const sourceUrl = assertAndNormalizeFileUrl(source);
2200
2050
 
2201
2051
  let binaryFlags;
2202
- if (typeof permissions === "object") {
2203
- permissions = {
2204
- owner: {
2205
- read: getPermissionOrComputeDefault$1("read", "owner", permissions),
2206
- write: getPermissionOrComputeDefault$1("write", "owner", permissions),
2207
- execute: getPermissionOrComputeDefault$1("execute", "owner", permissions),
2208
- },
2209
- group: {
2210
- read: getPermissionOrComputeDefault$1("read", "group", permissions),
2211
- write: getPermissionOrComputeDefault$1("write", "group", permissions),
2212
- execute: getPermissionOrComputeDefault$1("execute", "group", permissions),
2213
- },
2214
- others: {
2215
- read: getPermissionOrComputeDefault$1("read", "others", permissions),
2216
- write: getPermissionOrComputeDefault$1("write", "others", permissions),
2217
- execute: getPermissionOrComputeDefault$1(
2218
- "execute",
2219
- "others",
2220
- permissions,
2221
- ),
2222
- },
2223
- };
2224
- binaryFlags = permissionsToBinaryFlags(permissions);
2225
- } else {
2052
+ {
2226
2053
  binaryFlags = permissions;
2227
2054
  }
2228
2055
 
@@ -2237,45 +2064,6 @@ const writeEntryPermissions = async (source, permissions) => {
2237
2064
  });
2238
2065
  };
2239
2066
 
2240
- const actionLevels$1 = { read: 0, write: 1, execute: 2 };
2241
- const subjectLevels$1 = { others: 0, group: 1, owner: 2 };
2242
-
2243
- const getPermissionOrComputeDefault$1 = (action, subject, permissions) => {
2244
- if (subject in permissions) {
2245
- const subjectPermissions = permissions[subject];
2246
- if (action in subjectPermissions) {
2247
- return subjectPermissions[action];
2248
- }
2249
-
2250
- const actionLevel = actionLevels$1[action];
2251
- const actionFallback = Object.keys(actionLevels$1).find(
2252
- (actionFallbackCandidate) =>
2253
- actionLevels$1[actionFallbackCandidate] > actionLevel &&
2254
- actionFallbackCandidate in subjectPermissions,
2255
- );
2256
- if (actionFallback) {
2257
- return subjectPermissions[actionFallback];
2258
- }
2259
- }
2260
-
2261
- const subjectLevel = subjectLevels$1[subject];
2262
- // do we have a subject with a stronger level (group or owner)
2263
- // where we could read the action permission ?
2264
- const subjectFallback = Object.keys(subjectLevels$1).find(
2265
- (subjectFallbackCandidate) =>
2266
- subjectLevels$1[subjectFallbackCandidate] > subjectLevel &&
2267
- subjectFallbackCandidate in permissions,
2268
- );
2269
- if (subjectFallback) {
2270
- const subjectPermissions = permissions[subjectFallback];
2271
- return action in subjectPermissions
2272
- ? subjectPermissions[action]
2273
- : getPermissionOrComputeDefault$1(action, subjectFallback, permissions);
2274
- }
2275
-
2276
- return false;
2277
- };
2278
-
2279
2067
  /*
2280
2068
  * - stats object documentation on Node.js
2281
2069
  * https://nodejs.org/docs/latest-v13.x/api/fs.html#fs_class_fs_stats
@@ -2812,75 +2600,13 @@ const writeEntryPermissionsSync = (source, permissions) => {
2812
2600
  const sourceUrl = assertAndNormalizeFileUrl(source);
2813
2601
 
2814
2602
  let binaryFlags;
2815
- if (typeof permissions === "object") {
2816
- permissions = {
2817
- owner: {
2818
- read: getPermissionOrComputeDefault("read", "owner", permissions),
2819
- write: getPermissionOrComputeDefault("write", "owner", permissions),
2820
- execute: getPermissionOrComputeDefault("execute", "owner", permissions),
2821
- },
2822
- group: {
2823
- read: getPermissionOrComputeDefault("read", "group", permissions),
2824
- write: getPermissionOrComputeDefault("write", "group", permissions),
2825
- execute: getPermissionOrComputeDefault("execute", "group", permissions),
2826
- },
2827
- others: {
2828
- read: getPermissionOrComputeDefault("read", "others", permissions),
2829
- write: getPermissionOrComputeDefault("write", "others", permissions),
2830
- execute: getPermissionOrComputeDefault(
2831
- "execute",
2832
- "others",
2833
- permissions,
2834
- ),
2835
- },
2836
- };
2837
- binaryFlags = permissionsToBinaryFlags(permissions);
2838
- } else {
2603
+ {
2839
2604
  binaryFlags = permissions;
2840
2605
  }
2841
2606
 
2842
2607
  chmodSync(new URL(sourceUrl), binaryFlags);
2843
2608
  };
2844
2609
 
2845
- const actionLevels = { read: 0, write: 1, execute: 2 };
2846
- const subjectLevels = { others: 0, group: 1, owner: 2 };
2847
-
2848
- const getPermissionOrComputeDefault = (action, subject, permissions) => {
2849
- if (subject in permissions) {
2850
- const subjectPermissions = permissions[subject];
2851
- if (action in subjectPermissions) {
2852
- return subjectPermissions[action];
2853
- }
2854
-
2855
- const actionLevel = actionLevels[action];
2856
- const actionFallback = Object.keys(actionLevels).find(
2857
- (actionFallbackCandidate) =>
2858
- actionLevels[actionFallbackCandidate] > actionLevel &&
2859
- actionFallbackCandidate in subjectPermissions,
2860
- );
2861
- if (actionFallback) {
2862
- return subjectPermissions[actionFallback];
2863
- }
2864
- }
2865
-
2866
- const subjectLevel = subjectLevels[subject];
2867
- // do we have a subject with a stronger level (group or owner)
2868
- // where we could read the action permission ?
2869
- const subjectFallback = Object.keys(subjectLevels).find(
2870
- (subjectFallbackCandidate) =>
2871
- subjectLevels[subjectFallbackCandidate] > subjectLevel &&
2872
- subjectFallbackCandidate in permissions,
2873
- );
2874
- if (subjectFallback) {
2875
- const subjectPermissions = permissions[subjectFallback];
2876
- return action in subjectPermissions
2877
- ? subjectPermissions[action]
2878
- : getPermissionOrComputeDefault(action, subjectFallback, permissions);
2879
- }
2880
-
2881
- return false;
2882
- };
2883
-
2884
2610
  /*
2885
2611
  * - stats object documentation on Node.js
2886
2612
  * https://nodejs.org/docs/latest-v13.x/api/fs.html#fs_class_fs_stats
@@ -5033,6 +4759,7 @@ const reporterList = ({
5033
4759
  });
5034
4760
  const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
5035
4761
  let frameIndex = 0;
4762
+ let oneExecutionWritten = false;
5036
4763
  const renderDynamicLog = (testPlanResult) => {
5037
4764
  frameIndex = frameIndex === frames.length - 1 ? 0 : frameIndex + 1;
5038
4765
  let dynamicLogContent = "";
@@ -5065,7 +4792,10 @@ const reporterList = ({
5065
4792
  ANSI.GREY,
5066
4793
  )}${infoFormatted}${ANSI.color("]", ANSI.GREY)}`;
5067
4794
 
5068
- dynamicLogContent = `\n${dynamicLogContent}\n`;
4795
+ if (oneExecutionWritten) {
4796
+ dynamicLogContent = `\n${dynamicLogContent}`;
4797
+ }
4798
+ dynamicLogContent = `${dynamicLogContent}\n`;
5069
4799
  return dynamicLogContent;
5070
4800
  };
5071
4801
  dynamicLog.update(renderDynamicLog(testPlanResult));
@@ -5080,10 +4810,16 @@ const reporterList = ({
5080
4810
  });
5081
4811
  },
5082
4812
  afterEachInOrder: (execution) => {
5083
- dynamicLog.clearDuringFunctionCall(() => {
5084
- const log = renderExecutionLog(execution, logOptions);
5085
- write(log);
5086
- });
4813
+ oneExecutionWritten = true;
4814
+ dynamicLog.clearDuringFunctionCall(
4815
+ () => {
4816
+ const log = renderExecutionLog(execution, logOptions);
4817
+ write(log);
4818
+ },
4819
+ // regenerate the dynamic log to put the leading "\n"
4820
+ // because of oneExecutionWritten becoming true
4821
+ renderDynamicLog(testPlanResult),
4822
+ );
5087
4823
  },
5088
4824
  afterAll: async () => {
5089
4825
  dynamicLog.update("");
@@ -8021,6 +7757,7 @@ const nodeChildProcess = ({
8021
7757
  env = {
8022
7758
  ...env,
8023
7759
  JSENV: true,
7760
+ FORCE_COLOR: supportsColor.stdout,
8024
7761
  };
8025
7762
 
8026
7763
  return {
@@ -8495,6 +8232,7 @@ const nodeWorkerThread = ({
8495
8232
  env = {
8496
8233
  ...env,
8497
8234
  JSENV: true,
8235
+ FORCE_COLOR: supportsColor.stdout,
8498
8236
  };
8499
8237
 
8500
8238
  return {
@@ -57,9 +57,9 @@ const sendToParent = (type, data) => {
57
57
  if (!process.connected) {
58
58
  return;
59
59
  }
60
- // this can keep process alive longer than expected
60
+ // this can keep process alive longer than expect
61
61
  // when source is a long string.
62
- // It means node process may stay alive longer than expected
62
+ // It means node process may stay alive longer than expect
63
63
  // the time to send the data to the parent.
64
64
  process.send({
65
65
  __jsenv__: type,
@@ -29,9 +29,9 @@ const ACTIONS_AVAILABLE = {
29
29
  };
30
30
 
31
31
  const sendToParent = (type, data) => {
32
- // this can keep process alive longer than expected
32
+ // this can keep process alive longer than expect
33
33
  // when source is a long string.
34
- // It means node process may stay alive longer than expected
34
+ // It means node process may stay alive longer than expect
35
35
  // the time to send the data to the parent.
36
36
  parentPort.postMessage({
37
37
  __jsenv__: type,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/test",
3
- "version": "3.0.13",
3
+ "version": "3.0.14",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -38,26 +38,26 @@
38
38
  "dependencies": {
39
39
  "@c88/v8-coverage": "0.1.1",
40
40
  "@jsenv/abort": "4.3.0",
41
- "@jsenv/ast": "6.0.3",
42
- "@jsenv/filesystem": "4.6.5",
43
- "@jsenv/github-check-run": "0.1.10",
44
- "@jsenv/humanize": "1.0.0",
45
- "@jsenv/plugin-supervisor": "1.4.3",
41
+ "@jsenv/ast": "6.0.4",
42
+ "@jsenv/filesystem": "4.6.6",
43
+ "@jsenv/github-check-run": "0.1.11",
44
+ "@jsenv/humanize": "1.1.0",
45
+ "@jsenv/plugin-supervisor": "1.4.4",
46
46
  "@jsenv/url-meta": "8.4.0",
47
- "@jsenv/urls": "2.2.3",
47
+ "@jsenv/urls": "2.2.4",
48
48
  "@jsenv/utils": "2.1.1",
49
49
  "istanbul-lib-coverage": "3.2.2",
50
- "istanbul-lib-instrument": "6.0.1",
50
+ "istanbul-lib-instrument": "6.0.3",
51
51
  "istanbul-lib-report": "3.0.1",
52
- "istanbul-reports": "3.1.6",
52
+ "istanbul-reports": "3.1.7",
53
53
  "he": "1.2.0",
54
54
  "pidtree": "0.6.0",
55
55
  "strip-ansi": "7.1.0",
56
- "v8-to-istanbul": "9.2.0",
57
- "wrap-ansi": "9.0.0"
56
+ "supports-color": "9.4.0",
57
+ "v8-to-istanbul": "9.3.0",
58
+ "errorstacks": "2.4.1"
58
59
  },
59
60
  "devDependencies": {
60
- "@jsenv/terminal-recorder": "../independent/terminal-recorder/",
61
- "errorstacks": "2.4.1"
61
+ "@jsenv/terminal-recorder": "../independent/terminal-recorder/"
62
62
  }
63
63
  }
@@ -103,6 +103,7 @@ export const reporterList = ({
103
103
  });
104
104
  const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
105
105
  let frameIndex = 0;
106
+ let oneExecutionWritten = false;
106
107
  const renderDynamicLog = (testPlanResult) => {
107
108
  frameIndex = frameIndex === frames.length - 1 ? 0 : frameIndex + 1;
108
109
  let dynamicLogContent = "";
@@ -135,7 +136,10 @@ export const reporterList = ({
135
136
  ANSI.GREY,
136
137
  )}${infoFormatted}${ANSI.color("]", ANSI.GREY)}`;
137
138
 
138
- dynamicLogContent = `\n${dynamicLogContent}\n`;
139
+ if (oneExecutionWritten) {
140
+ dynamicLogContent = `\n${dynamicLogContent}`;
141
+ }
142
+ dynamicLogContent = `${dynamicLogContent}\n`;
139
143
  return dynamicLogContent;
140
144
  };
141
145
  dynamicLog.update(renderDynamicLog(testPlanResult));
@@ -150,10 +154,16 @@ export const reporterList = ({
150
154
  });
151
155
  },
152
156
  afterEachInOrder: (execution) => {
153
- dynamicLog.clearDuringFunctionCall(() => {
154
- const log = renderExecutionLog(execution, logOptions);
155
- write(log);
156
- });
157
+ oneExecutionWritten = true;
158
+ dynamicLog.clearDuringFunctionCall(
159
+ () => {
160
+ const log = renderExecutionLog(execution, logOptions);
161
+ write(log);
162
+ },
163
+ // regenerate the dynamic log to put the leading "\n"
164
+ // because of oneExecutionWritten becoming true
165
+ renderDynamicLog(testPlanResult),
166
+ );
157
167
  },
158
168
  afterAll: async () => {
159
169
  dynamicLog.update("");
@@ -1,5 +1,6 @@
1
1
  import { fork } from "node:child_process";
2
2
  import { fileURLToPath } from "node:url";
3
+ import supportsColor from "supports-color";
3
4
  import { Abort, raceCallbacks } from "@jsenv/abort";
4
5
  import { createDetailedMessage } from "@jsenv/humanize";
5
6
  import { memoize } from "@jsenv/utils/src/memoize/memoize.js";
@@ -36,6 +37,7 @@ export const nodeChildProcess = ({
36
37
  env = {
37
38
  ...env,
38
39
  JSENV: true,
40
+ FORCE_COLOR: supportsColor.stdout,
39
41
  };
40
42
 
41
43
  return {
@@ -55,9 +55,9 @@ const sendToParent = (type, data) => {
55
55
  if (!process.connected) {
56
56
  return;
57
57
  }
58
- // this can keep process alive longer than expected
58
+ // this can keep process alive longer than expect
59
59
  // when source is a long string.
60
- // It means node process may stay alive longer than expected
60
+ // It means node process may stay alive longer than expect
61
61
  // the time to send the data to the parent.
62
62
  process.send({
63
63
  __jsenv__: type,
@@ -3,6 +3,7 @@
3
3
  // https://github.com/avajs/ava/blob/576f534b345259055c95fa0c2b33bef10847a2af/lib/worker/base.js
4
4
  import { Worker } from "node:worker_threads";
5
5
  import { fileURLToPath } from "node:url";
6
+ import supportsColor from "supports-color";
6
7
  import { Abort, raceCallbacks } from "@jsenv/abort";
7
8
  import { memoize } from "@jsenv/utils/src/memoize/memoize.js";
8
9
 
@@ -32,6 +33,7 @@ export const nodeWorkerThread = ({
32
33
  env = {
33
34
  ...env,
34
35
  JSENV: true,
36
+ FORCE_COLOR: supportsColor.stdout,
35
37
  };
36
38
 
37
39
  return {
@@ -27,9 +27,9 @@ const ACTIONS_AVAILABLE = {
27
27
  };
28
28
 
29
29
  const sendToParent = (type, data) => {
30
- // this can keep process alive longer than expected
30
+ // this can keep process alive longer than expect
31
31
  // when source is a long string.
32
- // It means node process may stay alive longer than expected
32
+ // It means node process may stay alive longer than expect
33
33
  // the time to send the data to the parent.
34
34
  parentPort.postMessage({
35
35
  __jsenv__: type,