@jsenv/test 3.0.13 → 3.0.15

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 = {
@@ -16,7 +16,7 @@ import { applyBabelPlugins } from "@jsenv/ast";
16
16
  import { spawn, spawnSync, fork } from "node:child_process";
17
17
  import { createServer } from "node:net";
18
18
  import { injectSupervisorIntoHTML, supervisorFileUrl } from "@jsenv/plugin-supervisor";
19
- import { generateSourcemapDataUrl, SOURCEMAP } from "@jsenv/sourcemap";
19
+ import { SOURCEMAP, generateSourcemapDataUrl } from "@jsenv/sourcemap";
20
20
  import { findFreePort } from "@jsenv/server";
21
21
  import { Worker } from "node:worker_threads";
22
22
  import he from "he";
@@ -207,7 +207,7 @@ const createOperation = () => {
207
207
  const operationSignal = operationAbortController.signal;
208
208
 
209
209
  // abortCallbackList is used to ignore the max listeners warning from Node.js
210
- // this warning is useful but becomes problematic when it's expected
210
+ // this warning is useful but becomes problematic when it's expect
211
211
  // (a function doing 20 http call in parallel)
212
212
  // To be 100% sure we don't have memory leak, only Abortable.asyncCallback
213
213
  // uses abortCallbackList to know when something is aborted
@@ -618,170 +618,86 @@ const error = (...args) => console.error(...args);
618
618
 
619
619
  const errorDisabled = () => {};
620
620
 
621
- const ESC = '\u001B[';
622
- const OSC = '\u001B]';
623
- const BEL = '\u0007';
624
- const SEP = ';';
621
+ /* globals WorkerGlobalScope, DedicatedWorkerGlobalScope, SharedWorkerGlobalScope, ServiceWorkerGlobalScope */
625
622
 
626
- /* global window */
627
- const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
623
+ const isBrowser = globalThis.window?.document !== undefined;
628
624
 
629
- const isTerminalApp = !isBrowser && process$1.env.TERM_PROGRAM === 'Apple_Terminal';
630
- const isWindows$3 = !isBrowser && process$1.platform === 'win32';
631
- const cwdFunction = isBrowser ? () => {
632
- throw new Error('`process.cwd()` only works in Node.js, not the browser.');
633
- } : process$1.cwd;
625
+ globalThis.process?.versions?.node !== undefined;
634
626
 
635
- const ansiEscapes = {};
627
+ globalThis.process?.versions?.bun !== undefined;
636
628
 
637
- ansiEscapes.cursorTo = (x, y) => {
638
- if (typeof x !== 'number') {
639
- throw new TypeError('The `x` argument is required');
640
- }
629
+ globalThis.Deno?.version?.deno !== undefined;
641
630
 
642
- if (typeof y !== 'number') {
643
- return ESC + (x + 1) + 'G';
644
- }
631
+ globalThis.process?.versions?.electron !== undefined;
645
632
 
646
- return ESC + (y + 1) + SEP + (x + 1) + 'H';
647
- };
633
+ globalThis.navigator?.userAgent?.includes('jsdom') === true;
648
634
 
649
- ansiEscapes.cursorMove = (x, y) => {
650
- if (typeof x !== 'number') {
651
- throw new TypeError('The `x` argument is required');
652
- }
635
+ typeof WorkerGlobalScope !== 'undefined' && globalThis instanceof WorkerGlobalScope;
653
636
 
654
- let returnValue = '';
637
+ typeof DedicatedWorkerGlobalScope !== 'undefined' && globalThis instanceof DedicatedWorkerGlobalScope;
655
638
 
656
- if (x < 0) {
657
- returnValue += ESC + (-x) + 'D';
658
- } else if (x > 0) {
659
- returnValue += ESC + x + 'C';
660
- }
639
+ typeof SharedWorkerGlobalScope !== 'undefined' && globalThis instanceof SharedWorkerGlobalScope;
661
640
 
662
- if (y < 0) {
663
- returnValue += ESC + (-y) + 'A';
664
- } else if (y > 0) {
665
- returnValue += ESC + y + 'B';
666
- }
641
+ typeof ServiceWorkerGlobalScope !== 'undefined' && globalThis instanceof ServiceWorkerGlobalScope;
667
642
 
668
- return returnValue;
669
- };
643
+ // Note: I'm intentionally not DRYing up the other variables to keep them "lazy".
644
+ const platform = globalThis.navigator?.userAgentData?.platform;
645
+
646
+ platform === 'macOS'
647
+ || globalThis.navigator?.platform === 'MacIntel' // Even on Apple silicon Macs.
648
+ || globalThis.navigator?.userAgent?.includes(' Mac ') === true
649
+ || globalThis.process?.platform === 'darwin';
650
+
651
+ platform === 'Windows'
652
+ || globalThis.navigator?.platform === 'Win32'
653
+ || globalThis.process?.platform === 'win32';
670
654
 
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';
655
+ platform === 'Linux'
656
+ || globalThis.navigator?.platform?.startsWith('Linux') === true
657
+ || globalThis.navigator?.userAgent?.includes(' Linux ') === true
658
+ || globalThis.process?.platform === 'linux';
675
659
 
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';
660
+ platform === 'Android'
661
+ || globalThis.navigator?.platform === 'Android'
662
+ || globalThis.navigator?.userAgent?.includes(' Android ') === true
663
+ || globalThis.process?.platform === 'android';
684
664
 
685
- ansiEscapes.eraseLines = count => {
665
+ const ESC = '\u001B[';
666
+
667
+ !isBrowser && process$1.env.TERM_PROGRAM === 'Apple_Terminal';
668
+ const isWindows$3 = !isBrowser && process$1.platform === 'win32';
669
+
670
+ isBrowser ? () => {
671
+ throw new Error('`process.cwd()` only works in Node.js, not the browser.');
672
+ } : process$1.cwd;
673
+
674
+ const cursorUp = (count = 1) => ESC + count + 'A';
675
+
676
+ const cursorLeft = ESC + 'G';
677
+
678
+ const eraseLines = count => {
686
679
  let clear = '';
687
680
 
688
681
  for (let i = 0; i < count; i++) {
689
- clear += ansiEscapes.eraseLine + (i < count - 1 ? ansiEscapes.cursorUp() : '');
682
+ clear += eraseLine + (i < count - 1 ? cursorUp() : '');
690
683
  }
691
684
 
692
685
  if (count) {
693
- clear += ansiEscapes.cursorLeft;
686
+ clear += cursorLeft;
694
687
  }
695
688
 
696
689
  return clear;
697
690
  };
691
+ const eraseLine = ESC + '2K';
692
+ const eraseScreen = ESC + '2J';
698
693
 
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`
694
+ const clearTerminal = isWindows$3
695
+ ? `${eraseScreen}${ESC}0f`
712
696
  // 1. Erases the screen (Only done in case `2` is not supported)
713
697
  // 2. Erases the whole screen including scrollback buffer
714
698
  // 3. Moves cursor to the top-left position
715
699
  // 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
- };
700
+ : `${eraseScreen}${ESC}3J${ESC}H`;
785
701
 
786
702
  /*
787
703
  * see also https://github.com/vadimdemedes/ink
@@ -829,7 +745,7 @@ const createDynamicLog = ({
829
745
  if (visualLineCount > rows) {
830
746
  if (clearTerminalAllowed) {
831
747
  clearAttemptResult = true;
832
- return ansiEscapes.clearTerminal;
748
+ return clearTerminal;
833
749
  }
834
750
  // the whole log cannot be cleared because it's vertically to long
835
751
  // (longer than terminal height)
@@ -842,7 +758,7 @@ const createDynamicLog = ({
842
758
  }
843
759
 
844
760
  clearAttemptResult = true;
845
- return ansiEscapes.eraseLines(visualLineCount);
761
+ return eraseLines(visualLineCount);
846
762
  };
847
763
 
848
764
  const update = (string) => {
@@ -871,20 +787,22 @@ const createDynamicLog = ({
871
787
  clearAttemptResult = undefined;
872
788
  };
873
789
 
874
- const clearDuringFunctionCall = (callback) => {
790
+ const clearDuringFunctionCall = (
791
+ callback,
792
+ ouputAfterCallback = lastOutput,
793
+ ) => {
875
794
  // 1. Erase the current log
876
- // 2. Call callback (expected to write something on stdout)
795
+ // 2. Call callback (expect to write something on stdout)
877
796
  // 3. Restore the current log
878
797
  // During step 2. we expect a "write from outside" so we uninstall
879
798
  // the stream spy during function call
880
- const currentOutput = lastOutput;
881
799
  update("");
882
800
 
883
801
  writing = true;
884
802
  callback();
885
803
  writing = false;
886
804
 
887
- update(currentOutput);
805
+ update(ouputAfterCallback);
888
806
  };
889
807
 
890
808
  const writeFromOutsideEffect = (value) => {
@@ -1139,10 +1057,10 @@ function createSupportsColor(stream, options = {}) {
1139
1057
  return translateLevel(level);
1140
1058
  }
1141
1059
 
1142
- ({
1060
+ const supportsColor = {
1143
1061
  stdout: createSupportsColor({isTTY: tty.isatty(1)}),
1144
1062
  stderr: createSupportsColor({isTTY: tty.isatty(2)}),
1145
- });
1063
+ };
1146
1064
 
1147
1065
  const processSupportsBasicColor = createSupportsColor(process.stdout).hasBasic;
1148
1066
  // https://github.com/Marak/colors.js/blob/master/lib/styles.js
@@ -1157,14 +1075,19 @@ const ANSI = {
1157
1075
  YELLOW: "\x1b[33m",
1158
1076
  BLUE: "\x1b[34m",
1159
1077
  MAGENTA: "\x1b[35m",
1078
+ CYAN: "\x1b[36m",
1160
1079
  GREY: "\x1b[90m",
1161
1080
  color: (text, ANSI_COLOR) => {
1162
- return ANSI.supported ? `${ANSI_COLOR}${text}${RESET}` : text;
1081
+ return ANSI.supported && ANSI_COLOR ? `${ANSI_COLOR}${text}${RESET}` : text;
1163
1082
  },
1164
1083
 
1165
1084
  BOLD: "\x1b[1m",
1085
+ UNDERLINE: "\x1b[4m",
1086
+ STRIKE: "\x1b[9m",
1166
1087
  effect: (text, ANSI_EFFECT) => {
1167
- return ANSI.supported ? `${ANSI_EFFECT}${text}${RESET}` : text;
1088
+ return ANSI.supported && ANSI_EFFECT
1089
+ ? `${ANSI_EFFECT}${text}${RESET}`
1090
+ : text;
1168
1091
  },
1169
1092
  };
1170
1093
 
@@ -1432,6 +1355,9 @@ const UNICODE = {
1432
1355
  get CIRCLE_CROSS() {
1433
1356
  return ANSI.color(UNICODE.CIRCLE_CROSS_RAW, ANSI.RED);
1434
1357
  },
1358
+ get ELLIPSIS() {
1359
+ return UNICODE.supported ? `…` : `...`;
1360
+ },
1435
1361
  };
1436
1362
 
1437
1363
  const createDetailedMessage = (message, details = {}) => {
@@ -2078,7 +2004,7 @@ const ensureWindowsDriveLetter = (url, baseUrl) => {
2078
2004
  try {
2079
2005
  url = String(new URL(url));
2080
2006
  } catch (e) {
2081
- throw new Error(`absolute url expected but got ${url}`);
2007
+ throw new Error(`absolute url expect but got ${url}`);
2082
2008
  }
2083
2009
 
2084
2010
  if (!isWindows$2) {
@@ -2089,7 +2015,7 @@ const ensureWindowsDriveLetter = (url, baseUrl) => {
2089
2015
  baseUrl = String(new URL(baseUrl));
2090
2016
  } catch (e) {
2091
2017
  throw new Error(
2092
- `absolute baseUrl expected but got ${baseUrl} to ensure windows drive letter on ${url}`,
2018
+ `absolute baseUrl expect but got ${baseUrl} to ensure windows drive letter on ${url}`,
2093
2019
  );
2094
2020
  }
2095
2021
 
@@ -2111,7 +2037,7 @@ const ensureWindowsDriveLetter = (url, baseUrl) => {
2111
2037
  );
2112
2038
  if (!driveLetter) {
2113
2039
  throw new Error(
2114
- `drive letter expected on baseUrl but got ${baseUrl} to ensure windows drive letter on ${url}`,
2040
+ `drive letter expect on baseUrl but got ${baseUrl} to ensure windows drive letter on ${url}`,
2115
2041
  );
2116
2042
  }
2117
2043
  return `file:///${driveLetter}:${afterProtocol}`;
@@ -2162,67 +2088,11 @@ const readDirectory = async (url, { emfileMaxWait = 1000 } = {}) => {
2162
2088
  return attempt();
2163
2089
  };
2164
2090
 
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
2091
  const writeEntryPermissions = async (source, permissions) => {
2199
2092
  const sourceUrl = assertAndNormalizeFileUrl(source);
2200
2093
 
2201
2094
  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 {
2095
+ {
2226
2096
  binaryFlags = permissions;
2227
2097
  }
2228
2098
 
@@ -2237,45 +2107,6 @@ const writeEntryPermissions = async (source, permissions) => {
2237
2107
  });
2238
2108
  };
2239
2109
 
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
2110
  /*
2280
2111
  * - stats object documentation on Node.js
2281
2112
  * https://nodejs.org/docs/latest-v13.x/api/fs.html#fs_class_fs_stats
@@ -2812,75 +2643,13 @@ const writeEntryPermissionsSync = (source, permissions) => {
2812
2643
  const sourceUrl = assertAndNormalizeFileUrl(source);
2813
2644
 
2814
2645
  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 {
2646
+ {
2839
2647
  binaryFlags = permissions;
2840
2648
  }
2841
2649
 
2842
2650
  chmodSync(new URL(sourceUrl), binaryFlags);
2843
2651
  };
2844
2652
 
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
2653
  /*
2885
2654
  * - stats object documentation on Node.js
2886
2655
  * https://nodejs.org/docs/latest-v13.x/api/fs.html#fs_class_fs_stats
@@ -5033,6 +4802,7 @@ const reporterList = ({
5033
4802
  });
5034
4803
  const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
5035
4804
  let frameIndex = 0;
4805
+ let oneExecutionWritten = false;
5036
4806
  const renderDynamicLog = (testPlanResult) => {
5037
4807
  frameIndex = frameIndex === frames.length - 1 ? 0 : frameIndex + 1;
5038
4808
  let dynamicLogContent = "";
@@ -5065,7 +4835,10 @@ const reporterList = ({
5065
4835
  ANSI.GREY,
5066
4836
  )}${infoFormatted}${ANSI.color("]", ANSI.GREY)}`;
5067
4837
 
5068
- dynamicLogContent = `\n${dynamicLogContent}\n`;
4838
+ if (oneExecutionWritten) {
4839
+ dynamicLogContent = `\n${dynamicLogContent}`;
4840
+ }
4841
+ dynamicLogContent = `${dynamicLogContent}\n`;
5069
4842
  return dynamicLogContent;
5070
4843
  };
5071
4844
  dynamicLog.update(renderDynamicLog(testPlanResult));
@@ -5080,10 +4853,16 @@ const reporterList = ({
5080
4853
  });
5081
4854
  },
5082
4855
  afterEachInOrder: (execution) => {
5083
- dynamicLog.clearDuringFunctionCall(() => {
5084
- const log = renderExecutionLog(execution, logOptions);
5085
- write(log);
5086
- });
4856
+ oneExecutionWritten = true;
4857
+ dynamicLog.clearDuringFunctionCall(
4858
+ () => {
4859
+ const log = renderExecutionLog(execution, logOptions);
4860
+ write(log);
4861
+ },
4862
+ // regenerate the dynamic log to put the leading "\n"
4863
+ // because of oneExecutionWritten becoming true
4864
+ renderDynamicLog(testPlanResult),
4865
+ );
5087
4866
  },
5088
4867
  afterAll: async () => {
5089
4868
  dynamicLog.update("");
@@ -8021,6 +7800,7 @@ const nodeChildProcess = ({
8021
7800
  env = {
8022
7801
  ...env,
8023
7802
  JSENV: true,
7803
+ FORCE_COLOR: supportsColor.stdout,
8024
7804
  };
8025
7805
 
8026
7806
  return {
@@ -8495,6 +8275,7 @@ const nodeWorkerThread = ({
8495
8275
  env = {
8496
8276
  ...env,
8497
8277
  JSENV: true,
8278
+ FORCE_COLOR: supportsColor.stdout,
8498
8279
  };
8499
8280
 
8500
8281
  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.15",
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,