@jsenv/test 3.0.16 → 3.0.18

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.
@@ -4,8 +4,8 @@ import { readdir, chmod, stat, lstat, promises, readFile as readFile$1, writeFil
4
4
  import { takeCoverage } from "node:v8";
5
5
  import stripAnsi from "strip-ansi";
6
6
  import { URL_META, createException } from "./js/exception.js";
7
- import stringWidth from "string-width";
8
7
  import tty from "node:tty";
8
+ import stringWidth from "string-width";
9
9
  import { pathToFileURL, fileURLToPath } from "node:url";
10
10
  import { dirname } from "node:path";
11
11
  import crypto from "node:crypto";
@@ -530,599 +530,339 @@ const SIGINT_CALLBACK = {
530
530
  },
531
531
  };
532
532
 
533
- const LOG_LEVEL_OFF = "off";
534
-
535
- const LOG_LEVEL_DEBUG = "debug";
536
-
537
- const LOG_LEVEL_INFO = "info";
538
-
539
- const LOG_LEVEL_WARN = "warn";
533
+ const createDetailedMessage = (message, details = {}) => {
534
+ let string = `${message}`;
540
535
 
541
- const LOG_LEVEL_ERROR = "error";
536
+ Object.keys(details).forEach((key) => {
537
+ const value = details[key];
538
+ string += `
539
+ --- ${key} ---
540
+ ${
541
+ Array.isArray(value)
542
+ ? value.join(`
543
+ `)
544
+ : value
545
+ }`;
546
+ });
542
547
 
543
- const createLogger = ({ logLevel = LOG_LEVEL_INFO } = {}) => {
544
- if (logLevel === LOG_LEVEL_DEBUG) {
545
- return {
546
- level: "debug",
547
- levels: { debug: true, info: true, warn: true, error: true },
548
- debug,
549
- info,
550
- warn,
551
- error,
552
- };
553
- }
554
- if (logLevel === LOG_LEVEL_INFO) {
555
- return {
556
- level: "info",
557
- levels: { debug: false, info: true, warn: true, error: true },
558
- debug: debugDisabled,
559
- info,
560
- warn,
561
- error,
562
- };
563
- }
564
- if (logLevel === LOG_LEVEL_WARN) {
565
- return {
566
- level: "warn",
567
- levels: { debug: false, info: false, warn: true, error: true },
568
- debug: debugDisabled,
569
- info: infoDisabled,
570
- warn,
571
- error,
572
- };
573
- }
574
- if (logLevel === LOG_LEVEL_ERROR) {
575
- return {
576
- level: "error",
577
- levels: { debug: false, info: false, warn: false, error: true },
578
- debug: debugDisabled,
579
- info: infoDisabled,
580
- warn: warnDisabled,
581
- error,
582
- };
583
- }
584
- if (logLevel === LOG_LEVEL_OFF) {
585
- return {
586
- level: "off",
587
- levels: { debug: false, info: false, warn: false, error: false },
588
- debug: debugDisabled,
589
- info: infoDisabled,
590
- warn: warnDisabled,
591
- error: errorDisabled,
592
- };
593
- }
594
- throw new Error(`unexpected logLevel.
595
- --- logLevel ---
596
- ${logLevel}
597
- --- allowed log levels ---
598
- ${LOG_LEVEL_OFF}
599
- ${LOG_LEVEL_ERROR}
600
- ${LOG_LEVEL_WARN}
601
- ${LOG_LEVEL_INFO}
602
- ${LOG_LEVEL_DEBUG}`);
548
+ return string;
603
549
  };
604
550
 
605
- const debug = (...args) => console.debug(...args);
606
-
607
- const debugDisabled = () => {};
608
-
609
- const info = (...args) => console.info(...args);
551
+ // From: https://github.com/sindresorhus/has-flag/blob/main/index.js
552
+ /// function hasFlag(flag, argv = globalThis.Deno?.args ?? process.argv) {
553
+ function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process$1.argv) {
554
+ const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--');
555
+ const position = argv.indexOf(prefix + flag);
556
+ const terminatorPosition = argv.indexOf('--');
557
+ return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
558
+ }
610
559
 
611
- const infoDisabled = () => {};
560
+ const {env} = process$1;
612
561
 
613
- const warn = (...args) => console.warn(...args);
562
+ let flagForceColor;
563
+ if (
564
+ hasFlag('no-color')
565
+ || hasFlag('no-colors')
566
+ || hasFlag('color=false')
567
+ || hasFlag('color=never')
568
+ ) {
569
+ flagForceColor = 0;
570
+ } else if (
571
+ hasFlag('color')
572
+ || hasFlag('colors')
573
+ || hasFlag('color=true')
574
+ || hasFlag('color=always')
575
+ ) {
576
+ flagForceColor = 1;
577
+ }
614
578
 
615
- const warnDisabled = () => {};
579
+ function envForceColor() {
580
+ if ('FORCE_COLOR' in env) {
581
+ if (env.FORCE_COLOR === 'true') {
582
+ return 1;
583
+ }
616
584
 
617
- const error = (...args) => console.error(...args);
585
+ if (env.FORCE_COLOR === 'false') {
586
+ return 0;
587
+ }
618
588
 
619
- const errorDisabled = () => {};
589
+ return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
590
+ }
591
+ }
620
592
 
621
- /* globals WorkerGlobalScope, DedicatedWorkerGlobalScope, SharedWorkerGlobalScope, ServiceWorkerGlobalScope */
593
+ function translateLevel(level) {
594
+ if (level === 0) {
595
+ return false;
596
+ }
622
597
 
623
- const isBrowser = globalThis.window?.document !== undefined;
598
+ return {
599
+ level,
600
+ hasBasic: true,
601
+ has256: level >= 2,
602
+ has16m: level >= 3,
603
+ };
604
+ }
624
605
 
625
- globalThis.process?.versions?.node !== undefined;
606
+ function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
607
+ const noFlagForceColor = envForceColor();
608
+ if (noFlagForceColor !== undefined) {
609
+ flagForceColor = noFlagForceColor;
610
+ }
626
611
 
627
- globalThis.process?.versions?.bun !== undefined;
612
+ const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
628
613
 
629
- globalThis.Deno?.version?.deno !== undefined;
614
+ if (forceColor === 0) {
615
+ return 0;
616
+ }
630
617
 
631
- globalThis.process?.versions?.electron !== undefined;
618
+ if (sniffFlags) {
619
+ if (hasFlag('color=16m')
620
+ || hasFlag('color=full')
621
+ || hasFlag('color=truecolor')) {
622
+ return 3;
623
+ }
632
624
 
633
- globalThis.navigator?.userAgent?.includes('jsdom') === true;
625
+ if (hasFlag('color=256')) {
626
+ return 2;
627
+ }
628
+ }
634
629
 
635
- typeof WorkerGlobalScope !== 'undefined' && globalThis instanceof WorkerGlobalScope;
630
+ // Check for Azure DevOps pipelines.
631
+ // Has to be above the `!streamIsTTY` check.
632
+ if ('TF_BUILD' in env && 'AGENT_NAME' in env) {
633
+ return 1;
634
+ }
636
635
 
637
- typeof DedicatedWorkerGlobalScope !== 'undefined' && globalThis instanceof DedicatedWorkerGlobalScope;
636
+ if (haveStream && !streamIsTTY && forceColor === undefined) {
637
+ return 0;
638
+ }
638
639
 
639
- typeof SharedWorkerGlobalScope !== 'undefined' && globalThis instanceof SharedWorkerGlobalScope;
640
+ const min = forceColor || 0;
640
641
 
641
- typeof ServiceWorkerGlobalScope !== 'undefined' && globalThis instanceof ServiceWorkerGlobalScope;
642
+ if (env.TERM === 'dumb') {
643
+ return min;
644
+ }
642
645
 
643
- // Note: I'm intentionally not DRYing up the other variables to keep them "lazy".
644
- const platform = globalThis.navigator?.userAgentData?.platform;
646
+ if (process$1.platform === 'win32') {
647
+ // Windows 10 build 10586 is the first Windows release that supports 256 colors.
648
+ // Windows 10 build 14931 is the first release that supports 16m/TrueColor.
649
+ const osRelease = os.release().split('.');
650
+ if (
651
+ Number(osRelease[0]) >= 10
652
+ && Number(osRelease[2]) >= 10_586
653
+ ) {
654
+ return Number(osRelease[2]) >= 14_931 ? 3 : 2;
655
+ }
645
656
 
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';
657
+ return 1;
658
+ }
650
659
 
651
- platform === 'Windows'
652
- || globalThis.navigator?.platform === 'Win32'
653
- || globalThis.process?.platform === 'win32';
660
+ if ('CI' in env) {
661
+ if ('GITHUB_ACTIONS' in env || 'GITEA_ACTIONS' in env) {
662
+ return 3;
663
+ }
654
664
 
655
- platform === 'Linux'
656
- || globalThis.navigator?.platform?.startsWith('Linux') === true
657
- || globalThis.navigator?.userAgent?.includes(' Linux ') === true
658
- || globalThis.process?.platform === 'linux';
665
+ if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => sign in env) || env.CI_NAME === 'codeship') {
666
+ return 1;
667
+ }
659
668
 
660
- platform === 'Android'
661
- || globalThis.navigator?.platform === 'Android'
662
- || globalThis.navigator?.userAgent?.includes(' Android ') === true
663
- || globalThis.process?.platform === 'android';
669
+ return min;
670
+ }
664
671
 
665
- const ESC = '\u001B[';
672
+ if ('TEAMCITY_VERSION' in env) {
673
+ return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
674
+ }
666
675
 
667
- !isBrowser && process$1.env.TERM_PROGRAM === 'Apple_Terminal';
668
- const isWindows$3 = !isBrowser && process$1.platform === 'win32';
676
+ if (env.COLORTERM === 'truecolor') {
677
+ return 3;
678
+ }
669
679
 
670
- isBrowser ? () => {
671
- throw new Error('`process.cwd()` only works in Node.js, not the browser.');
672
- } : process$1.cwd;
680
+ if (env.TERM === 'xterm-kitty') {
681
+ return 3;
682
+ }
673
683
 
674
- const cursorUp = (count = 1) => ESC + count + 'A';
684
+ if ('TERM_PROGRAM' in env) {
685
+ const version = Number.parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10);
675
686
 
676
- const cursorLeft = ESC + 'G';
687
+ switch (env.TERM_PROGRAM) {
688
+ case 'iTerm.app': {
689
+ return version >= 3 ? 3 : 2;
690
+ }
677
691
 
678
- const eraseLines = count => {
679
- let clear = '';
692
+ case 'Apple_Terminal': {
693
+ return 2;
694
+ }
695
+ // No default
696
+ }
697
+ }
680
698
 
681
- for (let i = 0; i < count; i++) {
682
- clear += eraseLine + (i < count - 1 ? cursorUp() : '');
699
+ if (/-256(color)?$/i.test(env.TERM)) {
700
+ return 2;
683
701
  }
684
702
 
685
- if (count) {
686
- clear += cursorLeft;
703
+ if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
704
+ return 1;
687
705
  }
688
706
 
689
- return clear;
690
- };
691
- const eraseLine = ESC + '2K';
692
- const eraseScreen = ESC + '2J';
693
-
694
- const clearTerminal = isWindows$3
695
- ? `${eraseScreen}${ESC}0f`
696
- // 1. Erases the screen (Only done in case `2` is not supported)
697
- // 2. Erases the whole screen including scrollback buffer
698
- // 3. Moves cursor to the top-left position
699
- // More info: https://www.real-world-systems.com/docs/ANSIcode.html
700
- : `${eraseScreen}${ESC}3J${ESC}H`;
701
-
702
- /*
703
- * see also https://github.com/vadimdemedes/ink
704
- */
707
+ if ('COLORTERM' in env) {
708
+ return 1;
709
+ }
705
710
 
711
+ return min;
712
+ }
706
713
 
707
- const createDynamicLog = ({
708
- stream = process.stdout,
709
- clearTerminalAllowed,
710
- onVerticalOverflow = () => {},
711
- onWriteFromOutside = () => {},
712
- } = {}) => {
713
- const { columns = 80, rows = 24 } = stream;
714
- const dynamicLog = {
715
- destroyed: false,
716
- onVerticalOverflow,
717
- onWriteFromOutside,
718
- };
714
+ function createSupportsColor(stream, options = {}) {
715
+ const level = _supportsColor(stream, {
716
+ streamIsTTY: stream && stream.isTTY,
717
+ ...options,
718
+ });
719
719
 
720
- let lastOutput = "";
721
- let lastOutputFromOutside = "";
722
- let clearAttemptResult;
723
- let writing = false;
720
+ return translateLevel(level);
721
+ }
724
722
 
725
- const getErasePreviousOutput = () => {
726
- // nothing to clear
727
- if (!lastOutput) {
728
- return "";
729
- }
730
- if (clearAttemptResult !== undefined) {
731
- return "";
732
- }
723
+ const supportsColor = {
724
+ stdout: createSupportsColor({isTTY: tty.isatty(1)}),
725
+ stderr: createSupportsColor({isTTY: tty.isatty(2)}),
726
+ };
733
727
 
734
- const logLines = lastOutput.split(/\r\n|\r|\n/);
735
- let visualLineCount = 0;
736
- for (const logLine of logLines) {
737
- const width = stringWidth(logLine);
738
- if (width === 0) {
739
- visualLineCount++;
740
- } else {
741
- visualLineCount += Math.ceil(width / columns);
742
- }
743
- }
728
+ // https://github.com/Marak/colors.js/blob/master/lib/styles.js
729
+ // https://stackoverflow.com/a/75985833/2634179
730
+ const RESET = "\x1b[0m";
744
731
 
745
- if (visualLineCount > rows) {
746
- if (clearTerminalAllowed) {
747
- clearAttemptResult = true;
748
- return clearTerminal;
749
- }
750
- // the whole log cannot be cleared because it's vertically to long
751
- // (longer than terminal height)
752
- // readline.moveCursor cannot move cursor higher than screen height
753
- // it means we would only clear the visible part of the log
754
- // better keep the log untouched
755
- clearAttemptResult = false;
756
- dynamicLog.onVerticalOverflow();
757
- return "";
758
- }
732
+ const createAnsi = ({ supported }) => {
733
+ const ANSI = {
734
+ supported,
735
+
736
+ RED: "\x1b[31m",
737
+ GREEN: "\x1b[32m",
738
+ YELLOW: "\x1b[33m",
739
+ BLUE: "\x1b[34m",
740
+ MAGENTA: "\x1b[35m",
741
+ CYAN: "\x1b[36m",
742
+ GREY: "\x1b[90m",
743
+ color: (text, ANSI_COLOR) => {
744
+ return ANSI.supported && ANSI_COLOR
745
+ ? `${ANSI_COLOR}${text}${RESET}`
746
+ : text;
747
+ },
759
748
 
760
- clearAttemptResult = true;
761
- return eraseLines(visualLineCount);
749
+ BOLD: "\x1b[1m",
750
+ UNDERLINE: "\x1b[4m",
751
+ STRIKE: "\x1b[9m",
752
+ effect: (text, ANSI_EFFECT) => {
753
+ return ANSI.supported && ANSI_EFFECT
754
+ ? `${ANSI_EFFECT}${text}${RESET}`
755
+ : text;
756
+ },
762
757
  };
763
758
 
764
- const update = (string) => {
765
- if (dynamicLog.destroyed) {
766
- throw new Error("Cannot write log after destroy");
767
- }
768
- let stringToWrite = string;
769
- if (lastOutput) {
770
- if (lastOutputFromOutside) {
771
- // We don't want to clear logs written by other code,
772
- // it makes output unreadable and might erase precious information
773
- // To detect this we put a spy on the stream.
774
- // The spy is required only if we actually wrote something in the stream
775
- // something else than this code has written in the stream
776
- // so we just write without clearing (append instead of replacing)
777
- lastOutput = "";
778
- lastOutputFromOutside = "";
779
- } else {
780
- stringToWrite = `${getErasePreviousOutput()}${string}`;
781
- }
782
- }
783
- writing = true;
784
- stream.write(stringToWrite);
785
- lastOutput = string;
786
- writing = false;
787
- clearAttemptResult = undefined;
788
- };
759
+ return ANSI;
760
+ };
789
761
 
790
- const clearDuringFunctionCall = (
791
- callback,
792
- ouputAfterCallback = lastOutput,
793
- ) => {
794
- // 1. Erase the current log
795
- // 2. Call callback (expect to write something on stdout)
796
- // 3. Restore the current log
797
- // During step 2. we expect a "write from outside" so we uninstall
798
- // the stream spy during function call
799
- update("");
762
+ const processSupportsBasicColor = createSupportsColor(process.stdout).hasBasic;
800
763
 
801
- writing = true;
802
- callback();
803
- writing = false;
764
+ const ANSI = createAnsi({
765
+ supported:
766
+ processSupportsBasicColor ||
767
+ // GitHub workflow does support ANSI but "supports-color" returns false
768
+ // because stream.isTTY returns false, see https://github.com/actions/runner/issues/241
769
+ process.env.GITHUB_WORKFLOW,
770
+ });
804
771
 
805
- update(ouputAfterCallback);
806
- };
772
+ function isUnicodeSupported() {
773
+ if (process$1.platform !== 'win32') {
774
+ return process$1.env.TERM !== 'linux'; // Linux console (kernel)
775
+ }
807
776
 
808
- const writeFromOutsideEffect = (value) => {
809
- if (!lastOutput) {
810
- // we don't care if the log never wrote anything
811
- // or if last update() wrote an empty string
812
- return;
813
- }
814
- if (writing) {
815
- return;
816
- }
817
- lastOutputFromOutside = value;
818
- dynamicLog.onWriteFromOutside(value);
819
- };
777
+ return Boolean(process$1.env.WT_SESSION) // Windows Terminal
778
+ || Boolean(process$1.env.TERMINUS_SUBLIME) // Terminus (<0.2.27)
779
+ || process$1.env.ConEmuTask === '{cmd::Cmder}' // ConEmu and cmder
780
+ || process$1.env.TERM_PROGRAM === 'Terminus-Sublime'
781
+ || process$1.env.TERM_PROGRAM === 'vscode'
782
+ || process$1.env.TERM === 'xterm-256color'
783
+ || process$1.env.TERM === 'alacritty'
784
+ || process$1.env.TERMINAL_EMULATOR === 'JetBrains-JediTerm';
785
+ }
820
786
 
821
- let removeStreamSpy;
822
- if (stream === process.stdout) {
823
- const removeStdoutSpy = spyStreamOutput(
824
- process.stdout,
825
- writeFromOutsideEffect,
826
- );
827
- const removeStderrSpy = spyStreamOutput(
828
- process.stderr,
829
- writeFromOutsideEffect,
830
- );
831
- removeStreamSpy = () => {
832
- removeStdoutSpy();
833
- removeStderrSpy();
834
- };
835
- } else {
836
- removeStreamSpy = spyStreamOutput(stream, writeFromOutsideEffect);
837
- }
787
+ // see also https://github.com/sindresorhus/figures
838
788
 
839
- const destroy = () => {
840
- dynamicLog.destroyed = true;
841
- if (removeStreamSpy) {
842
- removeStreamSpy();
843
- removeStreamSpy = null;
844
- lastOutput = "";
845
- lastOutputFromOutside = "";
846
- }
789
+ const createUnicode = ({ supported, ANSI }) => {
790
+ const UNICODE = {
791
+ supported,
792
+ get COMMAND_RAW() {
793
+ return UNICODE.supported ? `❯` : `>`;
794
+ },
795
+ get OK_RAW() {
796
+ return UNICODE.supported ? `✔` : `√`;
797
+ },
798
+ get FAILURE_RAW() {
799
+ return UNICODE.supported ? `✖` : `×`;
800
+ },
801
+ get DEBUG_RAW() {
802
+ return UNICODE.supported ? `◆` : `♦`;
803
+ },
804
+ get INFO_RAW() {
805
+ return UNICODE.supported ? `ℹ` : `i`;
806
+ },
807
+ get WARNING_RAW() {
808
+ return UNICODE.supported ? `⚠` : `‼`;
809
+ },
810
+ get CIRCLE_CROSS_RAW() {
811
+ return UNICODE.supported ? `ⓧ` : `(×)`;
812
+ },
813
+ get COMMAND() {
814
+ return ANSI.color(UNICODE.COMMAND_RAW, ANSI.GREY); // ANSI_MAGENTA)
815
+ },
816
+ get OK() {
817
+ return ANSI.color(UNICODE.OK_RAW, ANSI.GREEN);
818
+ },
819
+ get FAILURE() {
820
+ return ANSI.color(UNICODE.FAILURE_RAW, ANSI.RED);
821
+ },
822
+ get DEBUG() {
823
+ return ANSI.color(UNICODE.DEBUG_RAW, ANSI.GREY);
824
+ },
825
+ get INFO() {
826
+ return ANSI.color(UNICODE.INFO_RAW, ANSI.BLUE);
827
+ },
828
+ get WARNING() {
829
+ return ANSI.color(UNICODE.WARNING_RAW, ANSI.YELLOW);
830
+ },
831
+ get CIRCLE_CROSS() {
832
+ return ANSI.color(UNICODE.CIRCLE_CROSS_RAW, ANSI.RED);
833
+ },
834
+ get ELLIPSIS() {
835
+ return UNICODE.supported ? `…` : `...`;
836
+ },
847
837
  };
848
-
849
- Object.assign(dynamicLog, {
850
- update,
851
- destroy,
852
- stream,
853
- clearDuringFunctionCall,
854
- });
855
- return dynamicLog;
838
+ return UNICODE;
856
839
  };
857
840
 
858
- // maybe https://github.com/gajus/output-interceptor/tree/v3.0.0 ?
859
- // the problem with listening data on stdout
860
- // is that node.js will later throw error if stream gets closed
861
- // while something listening data on it
862
- const spyStreamOutput = (stream, callback) => {
863
- const originalWrite = stream.write;
864
-
865
- let output = "";
866
- let installed = true;
867
-
868
- stream.write = function (...args /* chunk, encoding, callback */) {
869
- output += args;
870
- callback(output);
871
- return originalWrite.call(stream, ...args);
872
- };
841
+ const UNICODE = createUnicode({
842
+ supported: isUnicodeSupported(),
843
+ ANSI,
844
+ });
873
845
 
874
- const uninstall = () => {
875
- if (!installed) {
876
- return;
877
- }
878
- stream.write = originalWrite;
879
- installed = false;
880
- };
846
+ const setRoundedPrecision = (
847
+ number,
848
+ { decimals = 1, decimalsWhenSmall = decimals } = {},
849
+ ) => {
850
+ return setDecimalsPrecision(number, {
851
+ decimals,
852
+ decimalsWhenSmall,
853
+ transform: Math.round,
854
+ });
855
+ };
881
856
 
882
- return () => {
883
- uninstall();
884
- return output;
885
- };
886
- };
887
-
888
- // From: https://github.com/sindresorhus/has-flag/blob/main/index.js
889
- /// function hasFlag(flag, argv = globalThis.Deno?.args ?? process.argv) {
890
- function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process$1.argv) {
891
- const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--');
892
- const position = argv.indexOf(prefix + flag);
893
- const terminatorPosition = argv.indexOf('--');
894
- return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
895
- }
896
-
897
- const {env} = process$1;
898
-
899
- let flagForceColor;
900
- if (
901
- hasFlag('no-color')
902
- || hasFlag('no-colors')
903
- || hasFlag('color=false')
904
- || hasFlag('color=never')
905
- ) {
906
- flagForceColor = 0;
907
- } else if (
908
- hasFlag('color')
909
- || hasFlag('colors')
910
- || hasFlag('color=true')
911
- || hasFlag('color=always')
912
- ) {
913
- flagForceColor = 1;
914
- }
915
-
916
- function envForceColor() {
917
- if ('FORCE_COLOR' in env) {
918
- if (env.FORCE_COLOR === 'true') {
919
- return 1;
920
- }
921
-
922
- if (env.FORCE_COLOR === 'false') {
923
- return 0;
924
- }
925
-
926
- return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
927
- }
928
- }
929
-
930
- function translateLevel(level) {
931
- if (level === 0) {
932
- return false;
933
- }
934
-
935
- return {
936
- level,
937
- hasBasic: true,
938
- has256: level >= 2,
939
- has16m: level >= 3,
940
- };
941
- }
942
-
943
- function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
944
- const noFlagForceColor = envForceColor();
945
- if (noFlagForceColor !== undefined) {
946
- flagForceColor = noFlagForceColor;
947
- }
948
-
949
- const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
950
-
951
- if (forceColor === 0) {
952
- return 0;
953
- }
954
-
955
- if (sniffFlags) {
956
- if (hasFlag('color=16m')
957
- || hasFlag('color=full')
958
- || hasFlag('color=truecolor')) {
959
- return 3;
960
- }
961
-
962
- if (hasFlag('color=256')) {
963
- return 2;
964
- }
965
- }
966
-
967
- // Check for Azure DevOps pipelines.
968
- // Has to be above the `!streamIsTTY` check.
969
- if ('TF_BUILD' in env && 'AGENT_NAME' in env) {
970
- return 1;
971
- }
972
-
973
- if (haveStream && !streamIsTTY && forceColor === undefined) {
974
- return 0;
975
- }
976
-
977
- const min = forceColor || 0;
978
-
979
- if (env.TERM === 'dumb') {
980
- return min;
981
- }
982
-
983
- if (process$1.platform === 'win32') {
984
- // Windows 10 build 10586 is the first Windows release that supports 256 colors.
985
- // Windows 10 build 14931 is the first release that supports 16m/TrueColor.
986
- const osRelease = os.release().split('.');
987
- if (
988
- Number(osRelease[0]) >= 10
989
- && Number(osRelease[2]) >= 10_586
990
- ) {
991
- return Number(osRelease[2]) >= 14_931 ? 3 : 2;
992
- }
993
-
994
- return 1;
995
- }
996
-
997
- if ('CI' in env) {
998
- if ('GITHUB_ACTIONS' in env || 'GITEA_ACTIONS' in env) {
999
- return 3;
1000
- }
1001
-
1002
- if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => sign in env) || env.CI_NAME === 'codeship') {
1003
- return 1;
1004
- }
1005
-
1006
- return min;
1007
- }
1008
-
1009
- if ('TEAMCITY_VERSION' in env) {
1010
- return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
1011
- }
1012
-
1013
- if (env.COLORTERM === 'truecolor') {
1014
- return 3;
1015
- }
1016
-
1017
- if (env.TERM === 'xterm-kitty') {
1018
- return 3;
1019
- }
1020
-
1021
- if ('TERM_PROGRAM' in env) {
1022
- const version = Number.parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10);
1023
-
1024
- switch (env.TERM_PROGRAM) {
1025
- case 'iTerm.app': {
1026
- return version >= 3 ? 3 : 2;
1027
- }
1028
-
1029
- case 'Apple_Terminal': {
1030
- return 2;
1031
- }
1032
- // No default
1033
- }
1034
- }
1035
-
1036
- if (/-256(color)?$/i.test(env.TERM)) {
1037
- return 2;
1038
- }
1039
-
1040
- if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
1041
- return 1;
1042
- }
1043
-
1044
- if ('COLORTERM' in env) {
1045
- return 1;
1046
- }
1047
-
1048
- return min;
1049
- }
1050
-
1051
- function createSupportsColor(stream, options = {}) {
1052
- const level = _supportsColor(stream, {
1053
- streamIsTTY: stream && stream.isTTY,
1054
- ...options,
1055
- });
1056
-
1057
- return translateLevel(level);
1058
- }
1059
-
1060
- const supportsColor = {
1061
- stdout: createSupportsColor({isTTY: tty.isatty(1)}),
1062
- stderr: createSupportsColor({isTTY: tty.isatty(2)}),
1063
- };
1064
-
1065
- const processSupportsBasicColor = createSupportsColor(process.stdout).hasBasic;
1066
- // https://github.com/Marak/colors.js/blob/master/lib/styles.js
1067
- // https://stackoverflow.com/a/75985833/2634179
1068
- const RESET = "\x1b[0m";
1069
-
1070
- const ANSI = {
1071
- supported: processSupportsBasicColor,
1072
-
1073
- RED: "\x1b[31m",
1074
- GREEN: "\x1b[32m",
1075
- YELLOW: "\x1b[33m",
1076
- BLUE: "\x1b[34m",
1077
- MAGENTA: "\x1b[35m",
1078
- CYAN: "\x1b[36m",
1079
- GREY: "\x1b[90m",
1080
- color: (text, ANSI_COLOR) => {
1081
- return ANSI.supported && ANSI_COLOR ? `${ANSI_COLOR}${text}${RESET}` : text;
1082
- },
1083
-
1084
- BOLD: "\x1b[1m",
1085
- UNDERLINE: "\x1b[4m",
1086
- STRIKE: "\x1b[9m",
1087
- effect: (text, ANSI_EFFECT) => {
1088
- return ANSI.supported && ANSI_EFFECT
1089
- ? `${ANSI_EFFECT}${text}${RESET}`
1090
- : text;
1091
- },
1092
- };
1093
-
1094
- // GitHub workflow does support ANSI but "supports-color" returns false
1095
- // because stream.isTTY returns false, see https://github.com/actions/runner/issues/241
1096
- if (
1097
- process.env.GITHUB_WORKFLOW &&
1098
- // Check on FORCE_COLOR is to ensure it is prio over GitHub workflow check
1099
- // in unit test we use process.env.FORCE_COLOR = 'false' to fake
1100
- // that colors are not supported. Let it have priority
1101
- process.env.FORCE_COLOR !== "false"
1102
- ) {
1103
- ANSI.supported = true;
1104
- }
1105
-
1106
- const setRoundedPrecision = (
1107
- number,
1108
- { decimals = 1, decimalsWhenSmall = decimals } = {},
1109
- ) => {
1110
- return setDecimalsPrecision(number, {
1111
- decimals,
1112
- decimalsWhenSmall,
1113
- transform: Math.round,
1114
- });
1115
- };
1116
-
1117
- const setPrecision = (
1118
- number,
1119
- { decimals = 1, decimalsWhenSmall = decimals } = {},
1120
- ) => {
1121
- return setDecimalsPrecision(number, {
1122
- decimals,
1123
- decimalsWhenSmall,
1124
- transform: parseInt,
1125
- });
857
+ const setPrecision = (
858
+ number,
859
+ { decimals = 1, decimalsWhenSmall = decimals } = {},
860
+ ) => {
861
+ return setDecimalsPrecision(number, {
862
+ decimals,
863
+ decimalsWhenSmall,
864
+ transform: parseInt,
865
+ });
1126
866
  };
1127
867
 
1128
868
  const setDecimalsPrecision = (
@@ -1292,99 +1032,13 @@ const parseMs = (ms) => {
1292
1032
  };
1293
1033
  };
1294
1034
 
1295
- function isUnicodeSupported() {
1296
- if (process$1.platform !== 'win32') {
1297
- return process$1.env.TERM !== 'linux'; // Linux console (kernel)
1298
- }
1299
-
1300
- return Boolean(process$1.env.WT_SESSION) // Windows Terminal
1301
- || Boolean(process$1.env.TERMINUS_SUBLIME) // Terminus (<0.2.27)
1302
- || process$1.env.ConEmuTask === '{cmd::Cmder}' // ConEmu and cmder
1303
- || process$1.env.TERM_PROGRAM === 'Terminus-Sublime'
1304
- || process$1.env.TERM_PROGRAM === 'vscode'
1305
- || process$1.env.TERM === 'xterm-256color'
1306
- || process$1.env.TERM === 'alacritty'
1307
- || process$1.env.TERMINAL_EMULATOR === 'JetBrains-JediTerm';
1308
- }
1309
-
1310
- // see also https://github.com/sindresorhus/figures
1311
-
1312
-
1313
- const UNICODE = {
1314
- supported: isUnicodeSupported(),
1315
-
1316
- get COMMAND_RAW() {
1317
- return UNICODE.supported ? `❯` : `>`;
1318
- },
1319
- get OK_RAW() {
1320
- return UNICODE.supported ? `✔` : `√`;
1321
- },
1322
- get FAILURE_RAW() {
1323
- return UNICODE.supported ? `✖` : `×`;
1324
- },
1325
- get DEBUG_RAW() {
1326
- return UNICODE.supported ? `◆` : `♦`;
1327
- },
1328
- get INFO_RAW() {
1329
- return UNICODE.supported ? `ℹ` : `i`;
1330
- },
1331
- get WARNING_RAW() {
1332
- return UNICODE.supported ? `⚠` : `‼`;
1333
- },
1334
- get CIRCLE_CROSS_RAW() {
1335
- return UNICODE.supported ? `ⓧ` : `(×)`;
1336
- },
1337
- get COMMAND() {
1338
- return ANSI.color(UNICODE.COMMAND_RAW, ANSI.GREY); // ANSI_MAGENTA)
1339
- },
1340
- get OK() {
1341
- return ANSI.color(UNICODE.OK_RAW, ANSI.GREEN);
1342
- },
1343
- get FAILURE() {
1344
- return ANSI.color(UNICODE.FAILURE_RAW, ANSI.RED);
1345
- },
1346
- get DEBUG() {
1347
- return ANSI.color(UNICODE.DEBUG_RAW, ANSI.GREY);
1348
- },
1349
- get INFO() {
1350
- return ANSI.color(UNICODE.INFO_RAW, ANSI.BLUE);
1351
- },
1352
- get WARNING() {
1353
- return ANSI.color(UNICODE.WARNING_RAW, ANSI.YELLOW);
1354
- },
1355
- get CIRCLE_CROSS() {
1356
- return ANSI.color(UNICODE.CIRCLE_CROSS_RAW, ANSI.RED);
1357
- },
1358
- get ELLIPSIS() {
1359
- return UNICODE.supported ? `…` : `...`;
1360
- },
1035
+ const humanizeFileSize = (numberOfBytes, { decimals, short } = {}) => {
1036
+ return inspectBytes(numberOfBytes, { decimals, short });
1361
1037
  };
1362
1038
 
1363
- const createDetailedMessage = (message, details = {}) => {
1364
- let string = `${message}`;
1365
-
1366
- Object.keys(details).forEach((key) => {
1367
- const value = details[key];
1368
- string += `
1369
- --- ${key} ---
1370
- ${
1371
- Array.isArray(value)
1372
- ? value.join(`
1373
- `)
1374
- : value
1375
- }`;
1376
- });
1377
-
1378
- return string;
1379
- };
1380
-
1381
- const humanizeFileSize = (numberOfBytes, { decimals, short } = {}) => {
1382
- return inspectBytes(numberOfBytes, { decimals, short });
1383
- };
1384
-
1385
- const humanizeMemory = (metricValue, { decimals, short } = {}) => {
1386
- return inspectBytes(metricValue, { decimals, fixedDecimals: true, short });
1387
- };
1039
+ const humanizeMemory = (metricValue, { decimals, short } = {}) => {
1040
+ return inspectBytes(metricValue, { decimals, fixedDecimals: true, short });
1041
+ };
1388
1042
 
1389
1043
  const inspectBytes = (
1390
1044
  number,
@@ -1579,6 +1233,361 @@ const fillLeft$1 = (value, biggestValue, char = " ") => {
1579
1233
  return padded;
1580
1234
  };
1581
1235
 
1236
+ const LOG_LEVEL_OFF = "off";
1237
+
1238
+ const LOG_LEVEL_DEBUG = "debug";
1239
+
1240
+ const LOG_LEVEL_INFO = "info";
1241
+
1242
+ const LOG_LEVEL_WARN = "warn";
1243
+
1244
+ const LOG_LEVEL_ERROR = "error";
1245
+
1246
+ const createLogger = ({ logLevel = LOG_LEVEL_INFO } = {}) => {
1247
+ if (logLevel === LOG_LEVEL_DEBUG) {
1248
+ return {
1249
+ level: "debug",
1250
+ levels: { debug: true, info: true, warn: true, error: true },
1251
+ debug,
1252
+ info,
1253
+ warn,
1254
+ error,
1255
+ };
1256
+ }
1257
+ if (logLevel === LOG_LEVEL_INFO) {
1258
+ return {
1259
+ level: "info",
1260
+ levels: { debug: false, info: true, warn: true, error: true },
1261
+ debug: debugDisabled,
1262
+ info,
1263
+ warn,
1264
+ error,
1265
+ };
1266
+ }
1267
+ if (logLevel === LOG_LEVEL_WARN) {
1268
+ return {
1269
+ level: "warn",
1270
+ levels: { debug: false, info: false, warn: true, error: true },
1271
+ debug: debugDisabled,
1272
+ info: infoDisabled,
1273
+ warn,
1274
+ error,
1275
+ };
1276
+ }
1277
+ if (logLevel === LOG_LEVEL_ERROR) {
1278
+ return {
1279
+ level: "error",
1280
+ levels: { debug: false, info: false, warn: false, error: true },
1281
+ debug: debugDisabled,
1282
+ info: infoDisabled,
1283
+ warn: warnDisabled,
1284
+ error,
1285
+ };
1286
+ }
1287
+ if (logLevel === LOG_LEVEL_OFF) {
1288
+ return {
1289
+ level: "off",
1290
+ levels: { debug: false, info: false, warn: false, error: false },
1291
+ debug: debugDisabled,
1292
+ info: infoDisabled,
1293
+ warn: warnDisabled,
1294
+ error: errorDisabled,
1295
+ };
1296
+ }
1297
+ throw new Error(`unexpected logLevel.
1298
+ --- logLevel ---
1299
+ ${logLevel}
1300
+ --- allowed log levels ---
1301
+ ${LOG_LEVEL_OFF}
1302
+ ${LOG_LEVEL_ERROR}
1303
+ ${LOG_LEVEL_WARN}
1304
+ ${LOG_LEVEL_INFO}
1305
+ ${LOG_LEVEL_DEBUG}`);
1306
+ };
1307
+
1308
+ const debug = (...args) => console.debug(...args);
1309
+
1310
+ const debugDisabled = () => {};
1311
+
1312
+ const info = (...args) => console.info(...args);
1313
+
1314
+ const infoDisabled = () => {};
1315
+
1316
+ const warn = (...args) => console.warn(...args);
1317
+
1318
+ const warnDisabled = () => {};
1319
+
1320
+ const error = (...args) => console.error(...args);
1321
+
1322
+ const errorDisabled = () => {};
1323
+
1324
+ /* globals WorkerGlobalScope, DedicatedWorkerGlobalScope, SharedWorkerGlobalScope, ServiceWorkerGlobalScope */
1325
+
1326
+ const isBrowser = globalThis.window?.document !== undefined;
1327
+
1328
+ globalThis.process?.versions?.node !== undefined;
1329
+
1330
+ globalThis.process?.versions?.bun !== undefined;
1331
+
1332
+ globalThis.Deno?.version?.deno !== undefined;
1333
+
1334
+ globalThis.process?.versions?.electron !== undefined;
1335
+
1336
+ globalThis.navigator?.userAgent?.includes('jsdom') === true;
1337
+
1338
+ typeof WorkerGlobalScope !== 'undefined' && globalThis instanceof WorkerGlobalScope;
1339
+
1340
+ typeof DedicatedWorkerGlobalScope !== 'undefined' && globalThis instanceof DedicatedWorkerGlobalScope;
1341
+
1342
+ typeof SharedWorkerGlobalScope !== 'undefined' && globalThis instanceof SharedWorkerGlobalScope;
1343
+
1344
+ typeof ServiceWorkerGlobalScope !== 'undefined' && globalThis instanceof ServiceWorkerGlobalScope;
1345
+
1346
+ // Note: I'm intentionally not DRYing up the other variables to keep them "lazy".
1347
+ const platform = globalThis.navigator?.userAgentData?.platform;
1348
+
1349
+ platform === 'macOS'
1350
+ || globalThis.navigator?.platform === 'MacIntel' // Even on Apple silicon Macs.
1351
+ || globalThis.navigator?.userAgent?.includes(' Mac ') === true
1352
+ || globalThis.process?.platform === 'darwin';
1353
+
1354
+ platform === 'Windows'
1355
+ || globalThis.navigator?.platform === 'Win32'
1356
+ || globalThis.process?.platform === 'win32';
1357
+
1358
+ platform === 'Linux'
1359
+ || globalThis.navigator?.platform?.startsWith('Linux') === true
1360
+ || globalThis.navigator?.userAgent?.includes(' Linux ') === true
1361
+ || globalThis.process?.platform === 'linux';
1362
+
1363
+ platform === 'Android'
1364
+ || globalThis.navigator?.platform === 'Android'
1365
+ || globalThis.navigator?.userAgent?.includes(' Android ') === true
1366
+ || globalThis.process?.platform === 'android';
1367
+
1368
+ const ESC = '\u001B[';
1369
+
1370
+ !isBrowser && process$1.env.TERM_PROGRAM === 'Apple_Terminal';
1371
+ const isWindows$3 = !isBrowser && process$1.platform === 'win32';
1372
+
1373
+ isBrowser ? () => {
1374
+ throw new Error('`process.cwd()` only works in Node.js, not the browser.');
1375
+ } : process$1.cwd;
1376
+
1377
+ const cursorUp = (count = 1) => ESC + count + 'A';
1378
+
1379
+ const cursorLeft = ESC + 'G';
1380
+
1381
+ const eraseLines = count => {
1382
+ let clear = '';
1383
+
1384
+ for (let i = 0; i < count; i++) {
1385
+ clear += eraseLine + (i < count - 1 ? cursorUp() : '');
1386
+ }
1387
+
1388
+ if (count) {
1389
+ clear += cursorLeft;
1390
+ }
1391
+
1392
+ return clear;
1393
+ };
1394
+ const eraseLine = ESC + '2K';
1395
+ const eraseScreen = ESC + '2J';
1396
+
1397
+ const clearTerminal = isWindows$3
1398
+ ? `${eraseScreen}${ESC}0f`
1399
+ // 1. Erases the screen (Only done in case `2` is not supported)
1400
+ // 2. Erases the whole screen including scrollback buffer
1401
+ // 3. Moves cursor to the top-left position
1402
+ // More info: https://www.real-world-systems.com/docs/ANSIcode.html
1403
+ : `${eraseScreen}${ESC}3J${ESC}H`;
1404
+
1405
+ /*
1406
+ * see also https://github.com/vadimdemedes/ink
1407
+ */
1408
+
1409
+
1410
+ const createDynamicLog = ({
1411
+ stream = process.stdout,
1412
+ clearTerminalAllowed,
1413
+ onVerticalOverflow = () => {},
1414
+ onWriteFromOutside = () => {},
1415
+ } = {}) => {
1416
+ const { columns = 80, rows = 24 } = stream;
1417
+ const dynamicLog = {
1418
+ destroyed: false,
1419
+ onVerticalOverflow,
1420
+ onWriteFromOutside,
1421
+ };
1422
+
1423
+ let lastOutput = "";
1424
+ let lastOutputFromOutside = "";
1425
+ let clearAttemptResult;
1426
+ let writing = false;
1427
+
1428
+ const getErasePreviousOutput = () => {
1429
+ // nothing to clear
1430
+ if (!lastOutput) {
1431
+ return "";
1432
+ }
1433
+ if (clearAttemptResult !== undefined) {
1434
+ return "";
1435
+ }
1436
+
1437
+ const logLines = lastOutput.split(/\r\n|\r|\n/);
1438
+ let visualLineCount = 0;
1439
+ for (const logLine of logLines) {
1440
+ const width = stringWidth(logLine);
1441
+ if (width === 0) {
1442
+ visualLineCount++;
1443
+ } else {
1444
+ visualLineCount += Math.ceil(width / columns);
1445
+ }
1446
+ }
1447
+
1448
+ if (visualLineCount > rows) {
1449
+ if (clearTerminalAllowed) {
1450
+ clearAttemptResult = true;
1451
+ return clearTerminal;
1452
+ }
1453
+ // the whole log cannot be cleared because it's vertically to long
1454
+ // (longer than terminal height)
1455
+ // readline.moveCursor cannot move cursor higher than screen height
1456
+ // it means we would only clear the visible part of the log
1457
+ // better keep the log untouched
1458
+ clearAttemptResult = false;
1459
+ dynamicLog.onVerticalOverflow();
1460
+ return "";
1461
+ }
1462
+
1463
+ clearAttemptResult = true;
1464
+ return eraseLines(visualLineCount);
1465
+ };
1466
+
1467
+ const update = (string) => {
1468
+ if (dynamicLog.destroyed) {
1469
+ throw new Error("Cannot write log after destroy");
1470
+ }
1471
+ let stringToWrite = string;
1472
+ if (lastOutput) {
1473
+ if (lastOutputFromOutside) {
1474
+ // We don't want to clear logs written by other code,
1475
+ // it makes output unreadable and might erase precious information
1476
+ // To detect this we put a spy on the stream.
1477
+ // The spy is required only if we actually wrote something in the stream
1478
+ // something else than this code has written in the stream
1479
+ // so we just write without clearing (append instead of replacing)
1480
+ lastOutput = "";
1481
+ lastOutputFromOutside = "";
1482
+ } else {
1483
+ stringToWrite = `${getErasePreviousOutput()}${string}`;
1484
+ }
1485
+ }
1486
+ writing = true;
1487
+ stream.write(stringToWrite);
1488
+ lastOutput = string;
1489
+ writing = false;
1490
+ clearAttemptResult = undefined;
1491
+ };
1492
+
1493
+ const clearDuringFunctionCall = (
1494
+ callback,
1495
+ ouputAfterCallback = lastOutput,
1496
+ ) => {
1497
+ // 1. Erase the current log
1498
+ // 2. Call callback (expect to write something on stdout)
1499
+ // 3. Restore the current log
1500
+ // During step 2. we expect a "write from outside" so we uninstall
1501
+ // the stream spy during function call
1502
+ update("");
1503
+
1504
+ writing = true;
1505
+ callback();
1506
+ writing = false;
1507
+
1508
+ update(ouputAfterCallback);
1509
+ };
1510
+
1511
+ const writeFromOutsideEffect = (value) => {
1512
+ if (!lastOutput) {
1513
+ // we don't care if the log never wrote anything
1514
+ // or if last update() wrote an empty string
1515
+ return;
1516
+ }
1517
+ if (writing) {
1518
+ return;
1519
+ }
1520
+ lastOutputFromOutside = value;
1521
+ dynamicLog.onWriteFromOutside(value);
1522
+ };
1523
+
1524
+ let removeStreamSpy;
1525
+ if (stream === process.stdout) {
1526
+ const removeStdoutSpy = spyStreamOutput(
1527
+ process.stdout,
1528
+ writeFromOutsideEffect,
1529
+ );
1530
+ const removeStderrSpy = spyStreamOutput(
1531
+ process.stderr,
1532
+ writeFromOutsideEffect,
1533
+ );
1534
+ removeStreamSpy = () => {
1535
+ removeStdoutSpy();
1536
+ removeStderrSpy();
1537
+ };
1538
+ } else {
1539
+ removeStreamSpy = spyStreamOutput(stream, writeFromOutsideEffect);
1540
+ }
1541
+
1542
+ const destroy = () => {
1543
+ dynamicLog.destroyed = true;
1544
+ if (removeStreamSpy) {
1545
+ removeStreamSpy();
1546
+ removeStreamSpy = null;
1547
+ lastOutput = "";
1548
+ lastOutputFromOutside = "";
1549
+ }
1550
+ };
1551
+
1552
+ Object.assign(dynamicLog, {
1553
+ update,
1554
+ destroy,
1555
+ stream,
1556
+ clearDuringFunctionCall,
1557
+ });
1558
+ return dynamicLog;
1559
+ };
1560
+
1561
+ // maybe https://github.com/gajus/output-interceptor/tree/v3.0.0 ?
1562
+ // the problem with listening data on stdout
1563
+ // is that node.js will later throw error if stream gets closed
1564
+ // while something listening data on it
1565
+ const spyStreamOutput = (stream, callback) => {
1566
+ const originalWrite = stream.write;
1567
+
1568
+ let output = "";
1569
+ let installed = true;
1570
+
1571
+ stream.write = function (...args /* chunk, encoding, callback */) {
1572
+ output += args;
1573
+ callback(output);
1574
+ return originalWrite.call(stream, ...args);
1575
+ };
1576
+
1577
+ const uninstall = () => {
1578
+ if (!installed) {
1579
+ return;
1580
+ }
1581
+ stream.write = originalWrite;
1582
+ installed = false;
1583
+ };
1584
+
1585
+ return () => {
1586
+ uninstall();
1587
+ return output;
1588
+ };
1589
+ };
1590
+
1582
1591
  const urlToScheme = (url) => {
1583
1592
  const urlString = String(url);
1584
1593
  const colonIndex = urlString.indexOf(":");
@@ -7800,7 +7809,11 @@ const nodeChildProcess = ({
7800
7809
  env = {
7801
7810
  ...env,
7802
7811
  JSENV: true,
7803
- FORCE_COLOR: supportsColor.stdout,
7812
+ FORCE_COLOR:
7813
+ supportsColor.stdout ||
7814
+ // GitHub workflow does support ANSI but "supports-color" returns false
7815
+ // because stream.isTTY returns false, see https://github.com/actions/runner/issues/241
7816
+ process.env.GITHUB_WORKFLOW,
7804
7817
  };
7805
7818
 
7806
7819
  return {
@@ -8275,7 +8288,11 @@ const nodeWorkerThread = ({
8275
8288
  env = {
8276
8289
  ...env,
8277
8290
  JSENV: true,
8278
- FORCE_COLOR: supportsColor.stdout,
8291
+ FORCE_COLOR:
8292
+ supportsColor.stdout ||
8293
+ // GitHub workflow does support ANSI but "supports-color" returns false
8294
+ // because stream.isTTY returns false, see https://github.com/actions/runner/issues/241
8295
+ process.env.GITHUB_WORKFLOW,
8279
8296
  };
8280
8297
 
8281
8298
  return {