@jsenv/core 38.4.9 → 38.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/jsenv_core.js +741 -685
- package/package.json +15 -15
package/dist/jsenv_core.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { readdir, chmod, stat, lstat, promises, writeFileSync as writeFileSync$1, mkdirSync, unlink, openSync, closeSync, rmdir, watch, readdirSync, statSync, createReadStream, readFile, existsSync, readFileSync, realpathSync } from "node:fs";
|
|
2
|
-
import stringWidth from "string-width";
|
|
3
2
|
import process$1 from "node:process";
|
|
4
|
-
import { isBrowser } from "environment";
|
|
5
3
|
import os, { networkInterfaces } from "node:os";
|
|
6
4
|
import tty from "node:tty";
|
|
5
|
+
import stringWidth from "string-width";
|
|
7
6
|
import { pathToFileURL, fileURLToPath } from "node:url";
|
|
8
7
|
import { extname } from "node:path";
|
|
9
8
|
import crypto, { createHash } from "node:crypto";
|
|
@@ -589,611 +588,328 @@ const DATA_URL = {
|
|
|
589
588
|
},
|
|
590
589
|
};
|
|
591
590
|
|
|
592
|
-
const
|
|
593
|
-
|
|
594
|
-
const LOG_LEVEL_DEBUG = "debug";
|
|
591
|
+
const createDetailedMessage$1 = (message, details = {}) => {
|
|
592
|
+
let string = `${message}`;
|
|
595
593
|
|
|
596
|
-
|
|
594
|
+
Object.keys(details).forEach((key) => {
|
|
595
|
+
const value = details[key];
|
|
596
|
+
string += `
|
|
597
|
+
--- ${key} ---
|
|
598
|
+
${
|
|
599
|
+
Array.isArray(value)
|
|
600
|
+
? value.join(`
|
|
601
|
+
`)
|
|
602
|
+
: value
|
|
603
|
+
}`;
|
|
604
|
+
});
|
|
597
605
|
|
|
598
|
-
|
|
606
|
+
return string;
|
|
607
|
+
};
|
|
599
608
|
|
|
600
|
-
|
|
609
|
+
// From: https://github.com/sindresorhus/has-flag/blob/main/index.js
|
|
610
|
+
/// function hasFlag(flag, argv = globalThis.Deno?.args ?? process.argv) {
|
|
611
|
+
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process$1.argv) {
|
|
612
|
+
const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--');
|
|
613
|
+
const position = argv.indexOf(prefix + flag);
|
|
614
|
+
const terminatorPosition = argv.indexOf('--');
|
|
615
|
+
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
616
|
+
}
|
|
601
617
|
|
|
602
|
-
const
|
|
603
|
-
if (logLevel === LOG_LEVEL_DEBUG) {
|
|
604
|
-
return {
|
|
605
|
-
level: "debug",
|
|
606
|
-
levels: { debug: true, info: true, warn: true, error: true },
|
|
607
|
-
debug,
|
|
608
|
-
info,
|
|
609
|
-
warn,
|
|
610
|
-
error,
|
|
611
|
-
};
|
|
612
|
-
}
|
|
613
|
-
if (logLevel === LOG_LEVEL_INFO) {
|
|
614
|
-
return {
|
|
615
|
-
level: "info",
|
|
616
|
-
levels: { debug: false, info: true, warn: true, error: true },
|
|
617
|
-
debug: debugDisabled,
|
|
618
|
-
info,
|
|
619
|
-
warn,
|
|
620
|
-
error,
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
if (logLevel === LOG_LEVEL_WARN) {
|
|
624
|
-
return {
|
|
625
|
-
level: "warn",
|
|
626
|
-
levels: { debug: false, info: false, warn: true, error: true },
|
|
627
|
-
debug: debugDisabled,
|
|
628
|
-
info: infoDisabled,
|
|
629
|
-
warn,
|
|
630
|
-
error,
|
|
631
|
-
};
|
|
632
|
-
}
|
|
633
|
-
if (logLevel === LOG_LEVEL_ERROR) {
|
|
634
|
-
return {
|
|
635
|
-
level: "error",
|
|
636
|
-
levels: { debug: false, info: false, warn: false, error: true },
|
|
637
|
-
debug: debugDisabled,
|
|
638
|
-
info: infoDisabled,
|
|
639
|
-
warn: warnDisabled,
|
|
640
|
-
error,
|
|
641
|
-
};
|
|
642
|
-
}
|
|
643
|
-
if (logLevel === LOG_LEVEL_OFF) {
|
|
644
|
-
return {
|
|
645
|
-
level: "off",
|
|
646
|
-
levels: { debug: false, info: false, warn: false, error: false },
|
|
647
|
-
debug: debugDisabled,
|
|
648
|
-
info: infoDisabled,
|
|
649
|
-
warn: warnDisabled,
|
|
650
|
-
error: errorDisabled,
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
throw new Error(`unexpected logLevel.
|
|
654
|
-
--- logLevel ---
|
|
655
|
-
${logLevel}
|
|
656
|
-
--- allowed log levels ---
|
|
657
|
-
${LOG_LEVEL_OFF}
|
|
658
|
-
${LOG_LEVEL_ERROR}
|
|
659
|
-
${LOG_LEVEL_WARN}
|
|
660
|
-
${LOG_LEVEL_INFO}
|
|
661
|
-
${LOG_LEVEL_DEBUG}`);
|
|
662
|
-
};
|
|
618
|
+
const {env} = process$1;
|
|
663
619
|
|
|
664
|
-
|
|
620
|
+
let flagForceColor;
|
|
621
|
+
if (
|
|
622
|
+
hasFlag('no-color')
|
|
623
|
+
|| hasFlag('no-colors')
|
|
624
|
+
|| hasFlag('color=false')
|
|
625
|
+
|| hasFlag('color=never')
|
|
626
|
+
) {
|
|
627
|
+
flagForceColor = 0;
|
|
628
|
+
} else if (
|
|
629
|
+
hasFlag('color')
|
|
630
|
+
|| hasFlag('colors')
|
|
631
|
+
|| hasFlag('color=true')
|
|
632
|
+
|| hasFlag('color=always')
|
|
633
|
+
) {
|
|
634
|
+
flagForceColor = 1;
|
|
635
|
+
}
|
|
665
636
|
|
|
666
|
-
|
|
637
|
+
function envForceColor() {
|
|
638
|
+
if ('FORCE_COLOR' in env) {
|
|
639
|
+
if (env.FORCE_COLOR === 'true') {
|
|
640
|
+
return 1;
|
|
641
|
+
}
|
|
667
642
|
|
|
668
|
-
|
|
643
|
+
if (env.FORCE_COLOR === 'false') {
|
|
644
|
+
return 0;
|
|
645
|
+
}
|
|
669
646
|
|
|
670
|
-
|
|
647
|
+
return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
671
650
|
|
|
672
|
-
|
|
651
|
+
function translateLevel(level) {
|
|
652
|
+
if (level === 0) {
|
|
653
|
+
return false;
|
|
654
|
+
}
|
|
673
655
|
|
|
674
|
-
|
|
656
|
+
return {
|
|
657
|
+
level,
|
|
658
|
+
hasBasic: true,
|
|
659
|
+
has256: level >= 2,
|
|
660
|
+
has16m: level >= 3,
|
|
661
|
+
};
|
|
662
|
+
}
|
|
675
663
|
|
|
676
|
-
|
|
664
|
+
function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
|
|
665
|
+
const noFlagForceColor = envForceColor();
|
|
666
|
+
if (noFlagForceColor !== undefined) {
|
|
667
|
+
flagForceColor = noFlagForceColor;
|
|
668
|
+
}
|
|
677
669
|
|
|
678
|
-
const
|
|
670
|
+
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
679
671
|
|
|
680
|
-
|
|
672
|
+
if (forceColor === 0) {
|
|
673
|
+
return 0;
|
|
674
|
+
}
|
|
681
675
|
|
|
682
|
-
|
|
683
|
-
|
|
676
|
+
if (sniffFlags) {
|
|
677
|
+
if (hasFlag('color=16m')
|
|
678
|
+
|| hasFlag('color=full')
|
|
679
|
+
|| hasFlag('color=truecolor')) {
|
|
680
|
+
return 3;
|
|
681
|
+
}
|
|
684
682
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
}
|
|
683
|
+
if (hasFlag('color=256')) {
|
|
684
|
+
return 2;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
688
687
|
|
|
689
|
-
|
|
688
|
+
// Check for Azure DevOps pipelines.
|
|
689
|
+
// Has to be above the `!streamIsTTY` check.
|
|
690
|
+
if ('TF_BUILD' in env && 'AGENT_NAME' in env) {
|
|
691
|
+
return 1;
|
|
692
|
+
}
|
|
690
693
|
|
|
691
|
-
|
|
694
|
+
if (haveStream && !streamIsTTY && forceColor === undefined) {
|
|
695
|
+
return 0;
|
|
696
|
+
}
|
|
692
697
|
|
|
693
|
-
const
|
|
694
|
-
let clear = '';
|
|
698
|
+
const min = forceColor || 0;
|
|
695
699
|
|
|
696
|
-
|
|
697
|
-
|
|
700
|
+
if (env.TERM === 'dumb') {
|
|
701
|
+
return min;
|
|
698
702
|
}
|
|
699
703
|
|
|
700
|
-
if (
|
|
701
|
-
|
|
704
|
+
if (process$1.platform === 'win32') {
|
|
705
|
+
// Windows 10 build 10586 is the first Windows release that supports 256 colors.
|
|
706
|
+
// Windows 10 build 14931 is the first release that supports 16m/TrueColor.
|
|
707
|
+
const osRelease = os.release().split('.');
|
|
708
|
+
if (
|
|
709
|
+
Number(osRelease[0]) >= 10
|
|
710
|
+
&& Number(osRelease[2]) >= 10_586
|
|
711
|
+
) {
|
|
712
|
+
return Number(osRelease[2]) >= 14_931 ? 3 : 2;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
return 1;
|
|
702
716
|
}
|
|
703
717
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
718
|
+
if ('CI' in env) {
|
|
719
|
+
if ('GITHUB_ACTIONS' in env || 'GITEA_ACTIONS' in env) {
|
|
720
|
+
return 3;
|
|
721
|
+
}
|
|
708
722
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
// 2. Erases the whole screen including scrollback buffer
|
|
713
|
-
// 3. Moves cursor to the top-left position
|
|
714
|
-
// More info: https://www.real-world-systems.com/docs/ANSIcode.html
|
|
715
|
-
: `${eraseScreen}${ESC}3J${ESC}H`;
|
|
723
|
+
if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => sign in env) || env.CI_NAME === 'codeship') {
|
|
724
|
+
return 1;
|
|
725
|
+
}
|
|
716
726
|
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
*/
|
|
727
|
+
return min;
|
|
728
|
+
}
|
|
720
729
|
|
|
730
|
+
if ('TEAMCITY_VERSION' in env) {
|
|
731
|
+
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
732
|
+
}
|
|
721
733
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
onVerticalOverflow = () => {},
|
|
726
|
-
onWriteFromOutside = () => {},
|
|
727
|
-
} = {}) => {
|
|
728
|
-
const { columns = 80, rows = 24 } = stream;
|
|
729
|
-
const dynamicLog = {
|
|
730
|
-
destroyed: false,
|
|
731
|
-
onVerticalOverflow,
|
|
732
|
-
onWriteFromOutside,
|
|
733
|
-
};
|
|
734
|
+
if (env.COLORTERM === 'truecolor') {
|
|
735
|
+
return 3;
|
|
736
|
+
}
|
|
734
737
|
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
let writing = false;
|
|
738
|
+
if (env.TERM === 'xterm-kitty') {
|
|
739
|
+
return 3;
|
|
740
|
+
}
|
|
739
741
|
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
if (!lastOutput) {
|
|
743
|
-
return "";
|
|
744
|
-
}
|
|
745
|
-
if (clearAttemptResult !== undefined) {
|
|
746
|
-
return "";
|
|
747
|
-
}
|
|
742
|
+
if ('TERM_PROGRAM' in env) {
|
|
743
|
+
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10);
|
|
748
744
|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
if (width === 0) {
|
|
754
|
-
visualLineCount++;
|
|
755
|
-
} else {
|
|
756
|
-
visualLineCount += Math.ceil(width / columns);
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
if (visualLineCount > rows) {
|
|
761
|
-
if (clearTerminalAllowed) {
|
|
762
|
-
clearAttemptResult = true;
|
|
763
|
-
return clearTerminal;
|
|
764
|
-
}
|
|
765
|
-
// the whole log cannot be cleared because it's vertically to long
|
|
766
|
-
// (longer than terminal height)
|
|
767
|
-
// readline.moveCursor cannot move cursor higher than screen height
|
|
768
|
-
// it means we would only clear the visible part of the log
|
|
769
|
-
// better keep the log untouched
|
|
770
|
-
clearAttemptResult = false;
|
|
771
|
-
dynamicLog.onVerticalOverflow();
|
|
772
|
-
return "";
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
clearAttemptResult = true;
|
|
776
|
-
return eraseLines(visualLineCount);
|
|
777
|
-
};
|
|
778
|
-
|
|
779
|
-
const update = (string) => {
|
|
780
|
-
if (dynamicLog.destroyed) {
|
|
781
|
-
throw new Error("Cannot write log after destroy");
|
|
782
|
-
}
|
|
783
|
-
let stringToWrite = string;
|
|
784
|
-
if (lastOutput) {
|
|
785
|
-
if (lastOutputFromOutside) {
|
|
786
|
-
// We don't want to clear logs written by other code,
|
|
787
|
-
// it makes output unreadable and might erase precious information
|
|
788
|
-
// To detect this we put a spy on the stream.
|
|
789
|
-
// The spy is required only if we actually wrote something in the stream
|
|
790
|
-
// something else than this code has written in the stream
|
|
791
|
-
// so we just write without clearing (append instead of replacing)
|
|
792
|
-
lastOutput = "";
|
|
793
|
-
lastOutputFromOutside = "";
|
|
794
|
-
} else {
|
|
795
|
-
stringToWrite = `${getErasePreviousOutput()}${string}`;
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
writing = true;
|
|
799
|
-
stream.write(stringToWrite);
|
|
800
|
-
lastOutput = string;
|
|
801
|
-
writing = false;
|
|
802
|
-
clearAttemptResult = undefined;
|
|
803
|
-
};
|
|
745
|
+
switch (env.TERM_PROGRAM) {
|
|
746
|
+
case 'iTerm.app': {
|
|
747
|
+
return version >= 3 ? 3 : 2;
|
|
748
|
+
}
|
|
804
749
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
// 3. Restore the current log
|
|
812
|
-
// During step 2. we expect a "write from outside" so we uninstall
|
|
813
|
-
// the stream spy during function call
|
|
814
|
-
update("");
|
|
750
|
+
case 'Apple_Terminal': {
|
|
751
|
+
return 2;
|
|
752
|
+
}
|
|
753
|
+
// No default
|
|
754
|
+
}
|
|
755
|
+
}
|
|
815
756
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
757
|
+
if (/-256(color)?$/i.test(env.TERM)) {
|
|
758
|
+
return 2;
|
|
759
|
+
}
|
|
819
760
|
|
|
820
|
-
|
|
821
|
-
|
|
761
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
762
|
+
return 1;
|
|
763
|
+
}
|
|
822
764
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
// or if last update() wrote an empty string
|
|
827
|
-
return;
|
|
828
|
-
}
|
|
829
|
-
if (writing) {
|
|
830
|
-
return;
|
|
831
|
-
}
|
|
832
|
-
lastOutputFromOutside = value;
|
|
833
|
-
dynamicLog.onWriteFromOutside(value);
|
|
834
|
-
};
|
|
765
|
+
if ('COLORTERM' in env) {
|
|
766
|
+
return 1;
|
|
767
|
+
}
|
|
835
768
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
const removeStdoutSpy = spyStreamOutput(
|
|
839
|
-
process.stdout,
|
|
840
|
-
writeFromOutsideEffect,
|
|
841
|
-
);
|
|
842
|
-
const removeStderrSpy = spyStreamOutput(
|
|
843
|
-
process.stderr,
|
|
844
|
-
writeFromOutsideEffect,
|
|
845
|
-
);
|
|
846
|
-
removeStreamSpy = () => {
|
|
847
|
-
removeStdoutSpy();
|
|
848
|
-
removeStderrSpy();
|
|
849
|
-
};
|
|
850
|
-
} else {
|
|
851
|
-
removeStreamSpy = spyStreamOutput(stream, writeFromOutsideEffect);
|
|
852
|
-
}
|
|
769
|
+
return min;
|
|
770
|
+
}
|
|
853
771
|
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
lastOutput = "";
|
|
860
|
-
lastOutputFromOutside = "";
|
|
861
|
-
}
|
|
862
|
-
};
|
|
772
|
+
function createSupportsColor(stream, options = {}) {
|
|
773
|
+
const level = _supportsColor(stream, {
|
|
774
|
+
streamIsTTY: stream && stream.isTTY,
|
|
775
|
+
...options,
|
|
776
|
+
});
|
|
863
777
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
destroy,
|
|
867
|
-
stream,
|
|
868
|
-
clearDuringFunctionCall,
|
|
869
|
-
});
|
|
870
|
-
return dynamicLog;
|
|
871
|
-
};
|
|
778
|
+
return translateLevel(level);
|
|
779
|
+
}
|
|
872
780
|
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
const spyStreamOutput = (stream, callback) => {
|
|
878
|
-
const originalWrite = stream.write;
|
|
781
|
+
({
|
|
782
|
+
stdout: createSupportsColor({isTTY: tty.isatty(1)}),
|
|
783
|
+
stderr: createSupportsColor({isTTY: tty.isatty(2)}),
|
|
784
|
+
});
|
|
879
785
|
|
|
880
|
-
|
|
881
|
-
|
|
786
|
+
// https://github.com/Marak/colors.js/blob/master/lib/styles.js
|
|
787
|
+
// https://stackoverflow.com/a/75985833/2634179
|
|
788
|
+
const RESET = "\x1b[0m";
|
|
882
789
|
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
790
|
+
const createAnsi = ({ supported }) => {
|
|
791
|
+
const ANSI = {
|
|
792
|
+
supported,
|
|
793
|
+
|
|
794
|
+
RED: "\x1b[31m",
|
|
795
|
+
GREEN: "\x1b[32m",
|
|
796
|
+
YELLOW: "\x1b[33m",
|
|
797
|
+
BLUE: "\x1b[34m",
|
|
798
|
+
MAGENTA: "\x1b[35m",
|
|
799
|
+
CYAN: "\x1b[36m",
|
|
800
|
+
GREY: "\x1b[90m",
|
|
801
|
+
color: (text, ANSI_COLOR) => {
|
|
802
|
+
return ANSI.supported && ANSI_COLOR
|
|
803
|
+
? `${ANSI_COLOR}${text}${RESET}`
|
|
804
|
+
: text;
|
|
805
|
+
},
|
|
888
806
|
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
807
|
+
BOLD: "\x1b[1m",
|
|
808
|
+
UNDERLINE: "\x1b[4m",
|
|
809
|
+
STRIKE: "\x1b[9m",
|
|
810
|
+
effect: (text, ANSI_EFFECT) => {
|
|
811
|
+
return ANSI.supported && ANSI_EFFECT
|
|
812
|
+
? `${ANSI_EFFECT}${text}${RESET}`
|
|
813
|
+
: text;
|
|
814
|
+
},
|
|
895
815
|
};
|
|
896
816
|
|
|
897
|
-
return
|
|
898
|
-
uninstall();
|
|
899
|
-
return output;
|
|
900
|
-
};
|
|
817
|
+
return ANSI;
|
|
901
818
|
};
|
|
902
819
|
|
|
903
|
-
|
|
904
|
-
/// function hasFlag(flag, argv = globalThis.Deno?.args ?? process.argv) {
|
|
905
|
-
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process$1.argv) {
|
|
906
|
-
const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--');
|
|
907
|
-
const position = argv.indexOf(prefix + flag);
|
|
908
|
-
const terminatorPosition = argv.indexOf('--');
|
|
909
|
-
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
910
|
-
}
|
|
820
|
+
const processSupportsBasicColor = createSupportsColor(process.stdout).hasBasic;
|
|
911
821
|
|
|
912
|
-
const
|
|
822
|
+
const ANSI = createAnsi({
|
|
823
|
+
supported:
|
|
824
|
+
processSupportsBasicColor ||
|
|
825
|
+
// GitHub workflow does support ANSI but "supports-color" returns false
|
|
826
|
+
// because stream.isTTY returns false, see https://github.com/actions/runner/issues/241
|
|
827
|
+
(process.env.GITHUB_WORKFLOW &&
|
|
828
|
+
// Check on FORCE_COLOR is to ensure it is prio over GitHub workflow check
|
|
829
|
+
// in unit test we use process.env.FORCE_COLOR = 'false' to fake
|
|
830
|
+
// that colors are not supported. Let it have priority
|
|
831
|
+
process.env.FORCE_COLOR !== "false"),
|
|
832
|
+
});
|
|
913
833
|
|
|
914
|
-
|
|
915
|
-
if (
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
)
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
) {
|
|
928
|
-
flagForceColor = 1;
|
|
834
|
+
function isUnicodeSupported() {
|
|
835
|
+
if (process$1.platform !== 'win32') {
|
|
836
|
+
return process$1.env.TERM !== 'linux'; // Linux console (kernel)
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
return Boolean(process$1.env.WT_SESSION) // Windows Terminal
|
|
840
|
+
|| Boolean(process$1.env.TERMINUS_SUBLIME) // Terminus (<0.2.27)
|
|
841
|
+
|| process$1.env.ConEmuTask === '{cmd::Cmder}' // ConEmu and cmder
|
|
842
|
+
|| process$1.env.TERM_PROGRAM === 'Terminus-Sublime'
|
|
843
|
+
|| process$1.env.TERM_PROGRAM === 'vscode'
|
|
844
|
+
|| process$1.env.TERM === 'xterm-256color'
|
|
845
|
+
|| process$1.env.TERM === 'alacritty'
|
|
846
|
+
|| process$1.env.TERMINAL_EMULATOR === 'JetBrains-JediTerm';
|
|
929
847
|
}
|
|
930
848
|
|
|
931
|
-
|
|
932
|
-
if ('FORCE_COLOR' in env) {
|
|
933
|
-
if (env.FORCE_COLOR === 'true') {
|
|
934
|
-
return 1;
|
|
935
|
-
}
|
|
849
|
+
// see also https://github.com/sindresorhus/figures
|
|
936
850
|
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
851
|
+
const createUnicode = ({ supported, ANSI }) => {
|
|
852
|
+
const UNICODE = {
|
|
853
|
+
supported,
|
|
854
|
+
get COMMAND_RAW() {
|
|
855
|
+
return UNICODE.supported ? `❯` : `>`;
|
|
856
|
+
},
|
|
857
|
+
get OK_RAW() {
|
|
858
|
+
return UNICODE.supported ? `✔` : `√`;
|
|
859
|
+
},
|
|
860
|
+
get FAILURE_RAW() {
|
|
861
|
+
return UNICODE.supported ? `✖` : `×`;
|
|
862
|
+
},
|
|
863
|
+
get DEBUG_RAW() {
|
|
864
|
+
return UNICODE.supported ? `◆` : `♦`;
|
|
865
|
+
},
|
|
866
|
+
get INFO_RAW() {
|
|
867
|
+
return UNICODE.supported ? `ℹ` : `i`;
|
|
868
|
+
},
|
|
869
|
+
get WARNING_RAW() {
|
|
870
|
+
return UNICODE.supported ? `⚠` : `‼`;
|
|
871
|
+
},
|
|
872
|
+
get CIRCLE_CROSS_RAW() {
|
|
873
|
+
return UNICODE.supported ? `ⓧ` : `(×)`;
|
|
874
|
+
},
|
|
875
|
+
get COMMAND() {
|
|
876
|
+
return ANSI.color(UNICODE.COMMAND_RAW, ANSI.GREY); // ANSI_MAGENTA)
|
|
877
|
+
},
|
|
878
|
+
get OK() {
|
|
879
|
+
return ANSI.color(UNICODE.OK_RAW, ANSI.GREEN);
|
|
880
|
+
},
|
|
881
|
+
get FAILURE() {
|
|
882
|
+
return ANSI.color(UNICODE.FAILURE_RAW, ANSI.RED);
|
|
883
|
+
},
|
|
884
|
+
get DEBUG() {
|
|
885
|
+
return ANSI.color(UNICODE.DEBUG_RAW, ANSI.GREY);
|
|
886
|
+
},
|
|
887
|
+
get INFO() {
|
|
888
|
+
return ANSI.color(UNICODE.INFO_RAW, ANSI.BLUE);
|
|
889
|
+
},
|
|
890
|
+
get WARNING() {
|
|
891
|
+
return ANSI.color(UNICODE.WARNING_RAW, ANSI.YELLOW);
|
|
892
|
+
},
|
|
893
|
+
get CIRCLE_CROSS() {
|
|
894
|
+
return ANSI.color(UNICODE.CIRCLE_CROSS_RAW, ANSI.RED);
|
|
895
|
+
},
|
|
896
|
+
get ELLIPSIS() {
|
|
897
|
+
return UNICODE.supported ? `…` : `...`;
|
|
898
|
+
},
|
|
899
|
+
};
|
|
900
|
+
return UNICODE;
|
|
901
|
+
};
|
|
940
902
|
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
903
|
+
const UNICODE = createUnicode({
|
|
904
|
+
supported: isUnicodeSupported(),
|
|
905
|
+
ANSI,
|
|
906
|
+
});
|
|
944
907
|
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
return {
|
|
951
|
-
level,
|
|
952
|
-
hasBasic: true,
|
|
953
|
-
has256: level >= 2,
|
|
954
|
-
has16m: level >= 3,
|
|
955
|
-
};
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
|
|
959
|
-
const noFlagForceColor = envForceColor();
|
|
960
|
-
if (noFlagForceColor !== undefined) {
|
|
961
|
-
flagForceColor = noFlagForceColor;
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
965
|
-
|
|
966
|
-
if (forceColor === 0) {
|
|
967
|
-
return 0;
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
if (sniffFlags) {
|
|
971
|
-
if (hasFlag('color=16m')
|
|
972
|
-
|| hasFlag('color=full')
|
|
973
|
-
|| hasFlag('color=truecolor')) {
|
|
974
|
-
return 3;
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
if (hasFlag('color=256')) {
|
|
978
|
-
return 2;
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
// Check for Azure DevOps pipelines.
|
|
983
|
-
// Has to be above the `!streamIsTTY` check.
|
|
984
|
-
if ('TF_BUILD' in env && 'AGENT_NAME' in env) {
|
|
985
|
-
return 1;
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
if (haveStream && !streamIsTTY && forceColor === undefined) {
|
|
989
|
-
return 0;
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
const min = forceColor || 0;
|
|
993
|
-
|
|
994
|
-
if (env.TERM === 'dumb') {
|
|
995
|
-
return min;
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
if (process$1.platform === 'win32') {
|
|
999
|
-
// Windows 10 build 10586 is the first Windows release that supports 256 colors.
|
|
1000
|
-
// Windows 10 build 14931 is the first release that supports 16m/TrueColor.
|
|
1001
|
-
const osRelease = os.release().split('.');
|
|
1002
|
-
if (
|
|
1003
|
-
Number(osRelease[0]) >= 10
|
|
1004
|
-
&& Number(osRelease[2]) >= 10_586
|
|
1005
|
-
) {
|
|
1006
|
-
return Number(osRelease[2]) >= 14_931 ? 3 : 2;
|
|
1007
|
-
}
|
|
1008
|
-
|
|
1009
|
-
return 1;
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
if ('CI' in env) {
|
|
1013
|
-
if ('GITHUB_ACTIONS' in env || 'GITEA_ACTIONS' in env) {
|
|
1014
|
-
return 3;
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => sign in env) || env.CI_NAME === 'codeship') {
|
|
1018
|
-
return 1;
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
return min;
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
if ('TEAMCITY_VERSION' in env) {
|
|
1025
|
-
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
if (env.COLORTERM === 'truecolor') {
|
|
1029
|
-
return 3;
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
if (env.TERM === 'xterm-kitty') {
|
|
1033
|
-
return 3;
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
if ('TERM_PROGRAM' in env) {
|
|
1037
|
-
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10);
|
|
1038
|
-
|
|
1039
|
-
switch (env.TERM_PROGRAM) {
|
|
1040
|
-
case 'iTerm.app': {
|
|
1041
|
-
return version >= 3 ? 3 : 2;
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
case 'Apple_Terminal': {
|
|
1045
|
-
return 2;
|
|
1046
|
-
}
|
|
1047
|
-
// No default
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
if (/-256(color)?$/i.test(env.TERM)) {
|
|
1052
|
-
return 2;
|
|
1053
|
-
}
|
|
1054
|
-
|
|
1055
|
-
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
1056
|
-
return 1;
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
if ('COLORTERM' in env) {
|
|
1060
|
-
return 1;
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
return min;
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
function createSupportsColor(stream, options = {}) {
|
|
1067
|
-
const level = _supportsColor(stream, {
|
|
1068
|
-
streamIsTTY: stream && stream.isTTY,
|
|
1069
|
-
...options,
|
|
1070
|
-
});
|
|
1071
|
-
|
|
1072
|
-
return translateLevel(level);
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
|
-
({
|
|
1076
|
-
stdout: createSupportsColor({isTTY: tty.isatty(1)}),
|
|
1077
|
-
stderr: createSupportsColor({isTTY: tty.isatty(2)}),
|
|
1078
|
-
});
|
|
1079
|
-
|
|
1080
|
-
const processSupportsBasicColor = createSupportsColor(process.stdout).hasBasic;
|
|
1081
|
-
// https://github.com/Marak/colors.js/blob/master/lib/styles.js
|
|
1082
|
-
// https://stackoverflow.com/a/75985833/2634179
|
|
1083
|
-
const RESET = "\x1b[0m";
|
|
1084
|
-
|
|
1085
|
-
const ANSI = {
|
|
1086
|
-
supported: processSupportsBasicColor,
|
|
1087
|
-
|
|
1088
|
-
RED: "\x1b[31m",
|
|
1089
|
-
GREEN: "\x1b[32m",
|
|
1090
|
-
YELLOW: "\x1b[33m",
|
|
1091
|
-
BLUE: "\x1b[34m",
|
|
1092
|
-
MAGENTA: "\x1b[35m",
|
|
1093
|
-
CYAN: "\x1b[36m",
|
|
1094
|
-
GREY: "\x1b[90m",
|
|
1095
|
-
color: (text, ANSI_COLOR) => {
|
|
1096
|
-
return ANSI.supported && ANSI_COLOR ? `${ANSI_COLOR}${text}${RESET}` : text;
|
|
1097
|
-
},
|
|
1098
|
-
|
|
1099
|
-
BOLD: "\x1b[1m",
|
|
1100
|
-
UNDERLINE: "\x1b[4m",
|
|
1101
|
-
STRIKE: "\x1b[9m",
|
|
1102
|
-
effect: (text, ANSI_EFFECT) => {
|
|
1103
|
-
return ANSI.supported && ANSI_EFFECT
|
|
1104
|
-
? `${ANSI_EFFECT}${text}${RESET}`
|
|
1105
|
-
: text;
|
|
1106
|
-
},
|
|
1107
|
-
};
|
|
1108
|
-
|
|
1109
|
-
// GitHub workflow does support ANSI but "supports-color" returns false
|
|
1110
|
-
// because stream.isTTY returns false, see https://github.com/actions/runner/issues/241
|
|
1111
|
-
if (
|
|
1112
|
-
process.env.GITHUB_WORKFLOW &&
|
|
1113
|
-
// Check on FORCE_COLOR is to ensure it is prio over GitHub workflow check
|
|
1114
|
-
// in unit test we use process.env.FORCE_COLOR = 'false' to fake
|
|
1115
|
-
// that colors are not supported. Let it have priority
|
|
1116
|
-
process.env.FORCE_COLOR !== "false"
|
|
1117
|
-
) {
|
|
1118
|
-
ANSI.supported = true;
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
|
-
const startSpinner = ({
|
|
1122
|
-
dynamicLog,
|
|
1123
|
-
frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
|
|
1124
|
-
fps = 20,
|
|
1125
|
-
keepProcessAlive = false,
|
|
1126
|
-
stopOnWriteFromOutside = true,
|
|
1127
|
-
stopOnVerticalOverflow = true,
|
|
1128
|
-
render = () => "",
|
|
1129
|
-
effect = () => {},
|
|
1130
|
-
animated = dynamicLog.stream.isTTY,
|
|
1131
|
-
}) => {
|
|
1132
|
-
let frameIndex = 0;
|
|
1133
|
-
let interval;
|
|
1134
|
-
let running = true;
|
|
1135
|
-
|
|
1136
|
-
const spinner = {
|
|
1137
|
-
message: undefined,
|
|
1138
|
-
};
|
|
1139
|
-
|
|
1140
|
-
const update = (message) => {
|
|
1141
|
-
spinner.message = running
|
|
1142
|
-
? `${frames[frameIndex]} ${message}\n`
|
|
1143
|
-
: `${message}\n`;
|
|
1144
|
-
return spinner.message;
|
|
1145
|
-
};
|
|
1146
|
-
spinner.update = update;
|
|
1147
|
-
|
|
1148
|
-
let cleanup;
|
|
1149
|
-
if (animated && ANSI.supported) {
|
|
1150
|
-
running = true;
|
|
1151
|
-
cleanup = effect();
|
|
1152
|
-
dynamicLog.update(update(render()));
|
|
1153
|
-
|
|
1154
|
-
interval = setInterval(() => {
|
|
1155
|
-
frameIndex = frameIndex === frames.length - 1 ? 0 : frameIndex + 1;
|
|
1156
|
-
dynamicLog.update(update(render()));
|
|
1157
|
-
}, 1000 / fps);
|
|
1158
|
-
if (!keepProcessAlive) {
|
|
1159
|
-
interval.unref();
|
|
1160
|
-
}
|
|
1161
|
-
} else {
|
|
1162
|
-
dynamicLog.update(update(render()));
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1165
|
-
const stop = (message) => {
|
|
1166
|
-
running = false;
|
|
1167
|
-
if (interval) {
|
|
1168
|
-
clearInterval(interval);
|
|
1169
|
-
interval = null;
|
|
1170
|
-
}
|
|
1171
|
-
if (cleanup) {
|
|
1172
|
-
cleanup();
|
|
1173
|
-
cleanup = null;
|
|
1174
|
-
}
|
|
1175
|
-
if (dynamicLog && message) {
|
|
1176
|
-
dynamicLog.update(update(message));
|
|
1177
|
-
dynamicLog = null;
|
|
1178
|
-
}
|
|
1179
|
-
};
|
|
1180
|
-
spinner.stop = stop;
|
|
1181
|
-
|
|
1182
|
-
if (stopOnVerticalOverflow) {
|
|
1183
|
-
dynamicLog.onVerticalOverflow = stop;
|
|
1184
|
-
}
|
|
1185
|
-
if (stopOnWriteFromOutside) {
|
|
1186
|
-
dynamicLog.onWriteFromOutside = stop;
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
return spinner;
|
|
1190
|
-
};
|
|
1191
|
-
|
|
1192
|
-
const getPrecision = (number) => {
|
|
1193
|
-
if (Math.floor(number) === number) return 0;
|
|
1194
|
-
const [, decimals] = number.toString().split(".");
|
|
1195
|
-
return decimals.length || 0;
|
|
1196
|
-
};
|
|
908
|
+
const getPrecision = (number) => {
|
|
909
|
+
if (Math.floor(number) === number) return 0;
|
|
910
|
+
const [, decimals] = number.toString().split(".");
|
|
911
|
+
return decimals.length || 0;
|
|
912
|
+
};
|
|
1197
913
|
|
|
1198
914
|
const setRoundedPrecision = (
|
|
1199
915
|
number,
|
|
@@ -1384,136 +1100,8 @@ const parseMs = (ms) => {
|
|
|
1384
1100
|
};
|
|
1385
1101
|
};
|
|
1386
1102
|
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
return process$1.env.TERM !== 'linux'; // Linux console (kernel)
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1392
|
-
return Boolean(process$1.env.WT_SESSION) // Windows Terminal
|
|
1393
|
-
|| Boolean(process$1.env.TERMINUS_SUBLIME) // Terminus (<0.2.27)
|
|
1394
|
-
|| process$1.env.ConEmuTask === '{cmd::Cmder}' // ConEmu and cmder
|
|
1395
|
-
|| process$1.env.TERM_PROGRAM === 'Terminus-Sublime'
|
|
1396
|
-
|| process$1.env.TERM_PROGRAM === 'vscode'
|
|
1397
|
-
|| process$1.env.TERM === 'xterm-256color'
|
|
1398
|
-
|| process$1.env.TERM === 'alacritty'
|
|
1399
|
-
|| process$1.env.TERMINAL_EMULATOR === 'JetBrains-JediTerm';
|
|
1400
|
-
}
|
|
1401
|
-
|
|
1402
|
-
// see also https://github.com/sindresorhus/figures
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
const UNICODE = {
|
|
1406
|
-
supported: isUnicodeSupported(),
|
|
1407
|
-
|
|
1408
|
-
get COMMAND_RAW() {
|
|
1409
|
-
return UNICODE.supported ? `❯` : `>`;
|
|
1410
|
-
},
|
|
1411
|
-
get OK_RAW() {
|
|
1412
|
-
return UNICODE.supported ? `✔` : `√`;
|
|
1413
|
-
},
|
|
1414
|
-
get FAILURE_RAW() {
|
|
1415
|
-
return UNICODE.supported ? `✖` : `×`;
|
|
1416
|
-
},
|
|
1417
|
-
get DEBUG_RAW() {
|
|
1418
|
-
return UNICODE.supported ? `◆` : `♦`;
|
|
1419
|
-
},
|
|
1420
|
-
get INFO_RAW() {
|
|
1421
|
-
return UNICODE.supported ? `ℹ` : `i`;
|
|
1422
|
-
},
|
|
1423
|
-
get WARNING_RAW() {
|
|
1424
|
-
return UNICODE.supported ? `⚠` : `‼`;
|
|
1425
|
-
},
|
|
1426
|
-
get CIRCLE_CROSS_RAW() {
|
|
1427
|
-
return UNICODE.supported ? `ⓧ` : `(×)`;
|
|
1428
|
-
},
|
|
1429
|
-
get COMMAND() {
|
|
1430
|
-
return ANSI.color(UNICODE.COMMAND_RAW, ANSI.GREY); // ANSI_MAGENTA)
|
|
1431
|
-
},
|
|
1432
|
-
get OK() {
|
|
1433
|
-
return ANSI.color(UNICODE.OK_RAW, ANSI.GREEN);
|
|
1434
|
-
},
|
|
1435
|
-
get FAILURE() {
|
|
1436
|
-
return ANSI.color(UNICODE.FAILURE_RAW, ANSI.RED);
|
|
1437
|
-
},
|
|
1438
|
-
get DEBUG() {
|
|
1439
|
-
return ANSI.color(UNICODE.DEBUG_RAW, ANSI.GREY);
|
|
1440
|
-
},
|
|
1441
|
-
get INFO() {
|
|
1442
|
-
return ANSI.color(UNICODE.INFO_RAW, ANSI.BLUE);
|
|
1443
|
-
},
|
|
1444
|
-
get WARNING() {
|
|
1445
|
-
return ANSI.color(UNICODE.WARNING_RAW, ANSI.YELLOW);
|
|
1446
|
-
},
|
|
1447
|
-
get CIRCLE_CROSS() {
|
|
1448
|
-
return ANSI.color(UNICODE.CIRCLE_CROSS_RAW, ANSI.RED);
|
|
1449
|
-
},
|
|
1450
|
-
get ELLIPSIS() {
|
|
1451
|
-
return UNICODE.supported ? `…` : `...`;
|
|
1452
|
-
},
|
|
1453
|
-
};
|
|
1454
|
-
|
|
1455
|
-
const createTaskLog = (
|
|
1456
|
-
label,
|
|
1457
|
-
{ disabled = false, animated = true, stopOnWriteFromOutside } = {},
|
|
1458
|
-
) => {
|
|
1459
|
-
if (disabled) {
|
|
1460
|
-
return {
|
|
1461
|
-
setRightText: () => {},
|
|
1462
|
-
done: () => {},
|
|
1463
|
-
happen: () => {},
|
|
1464
|
-
fail: () => {},
|
|
1465
|
-
};
|
|
1466
|
-
}
|
|
1467
|
-
const startMs = Date.now();
|
|
1468
|
-
const dynamicLog = createDynamicLog();
|
|
1469
|
-
let message = label;
|
|
1470
|
-
const taskSpinner = startSpinner({
|
|
1471
|
-
dynamicLog,
|
|
1472
|
-
render: () => message,
|
|
1473
|
-
stopOnWriteFromOutside,
|
|
1474
|
-
animated,
|
|
1475
|
-
});
|
|
1476
|
-
return {
|
|
1477
|
-
setRightText: (value) => {
|
|
1478
|
-
message = `${label} ${value}`;
|
|
1479
|
-
},
|
|
1480
|
-
done: () => {
|
|
1481
|
-
const msEllapsed = Date.now() - startMs;
|
|
1482
|
-
taskSpinner.stop(
|
|
1483
|
-
`${UNICODE.OK} ${label} (done in ${humanizeDuration(msEllapsed)})`,
|
|
1484
|
-
);
|
|
1485
|
-
},
|
|
1486
|
-
happen: (message) => {
|
|
1487
|
-
taskSpinner.stop(
|
|
1488
|
-
`${UNICODE.INFO} ${message} (at ${new Date().toLocaleTimeString()})`,
|
|
1489
|
-
);
|
|
1490
|
-
},
|
|
1491
|
-
fail: (message = `failed to ${label}`) => {
|
|
1492
|
-
taskSpinner.stop(`${UNICODE.FAILURE} ${message}`);
|
|
1493
|
-
},
|
|
1494
|
-
};
|
|
1495
|
-
};
|
|
1496
|
-
|
|
1497
|
-
const createDetailedMessage$1 = (message, details = {}) => {
|
|
1498
|
-
let string = `${message}`;
|
|
1499
|
-
|
|
1500
|
-
Object.keys(details).forEach((key) => {
|
|
1501
|
-
const value = details[key];
|
|
1502
|
-
string += `
|
|
1503
|
-
--- ${key} ---
|
|
1504
|
-
${
|
|
1505
|
-
Array.isArray(value)
|
|
1506
|
-
? value.join(`
|
|
1507
|
-
`)
|
|
1508
|
-
: value
|
|
1509
|
-
}`;
|
|
1510
|
-
});
|
|
1511
|
-
|
|
1512
|
-
return string;
|
|
1513
|
-
};
|
|
1514
|
-
|
|
1515
|
-
const humanizeFileSize = (numberOfBytes, { decimals, short } = {}) => {
|
|
1516
|
-
return inspectBytes(numberOfBytes, { decimals, short });
|
|
1103
|
+
const humanizeFileSize = (numberOfBytes, { decimals, short } = {}) => {
|
|
1104
|
+
return inspectBytes(numberOfBytes, { decimals, short });
|
|
1517
1105
|
};
|
|
1518
1106
|
|
|
1519
1107
|
const inspectBytes = (
|
|
@@ -1761,6 +1349,474 @@ const fillLeft = (value, biggestValue, char = " ") => {
|
|
|
1761
1349
|
return padded;
|
|
1762
1350
|
};
|
|
1763
1351
|
|
|
1352
|
+
const LOG_LEVEL_OFF = "off";
|
|
1353
|
+
|
|
1354
|
+
const LOG_LEVEL_DEBUG = "debug";
|
|
1355
|
+
|
|
1356
|
+
const LOG_LEVEL_INFO = "info";
|
|
1357
|
+
|
|
1358
|
+
const LOG_LEVEL_WARN = "warn";
|
|
1359
|
+
|
|
1360
|
+
const LOG_LEVEL_ERROR = "error";
|
|
1361
|
+
|
|
1362
|
+
const createLogger = ({ logLevel = LOG_LEVEL_INFO } = {}) => {
|
|
1363
|
+
if (logLevel === LOG_LEVEL_DEBUG) {
|
|
1364
|
+
return {
|
|
1365
|
+
level: "debug",
|
|
1366
|
+
levels: { debug: true, info: true, warn: true, error: true },
|
|
1367
|
+
debug,
|
|
1368
|
+
info,
|
|
1369
|
+
warn,
|
|
1370
|
+
error,
|
|
1371
|
+
};
|
|
1372
|
+
}
|
|
1373
|
+
if (logLevel === LOG_LEVEL_INFO) {
|
|
1374
|
+
return {
|
|
1375
|
+
level: "info",
|
|
1376
|
+
levels: { debug: false, info: true, warn: true, error: true },
|
|
1377
|
+
debug: debugDisabled,
|
|
1378
|
+
info,
|
|
1379
|
+
warn,
|
|
1380
|
+
error,
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
if (logLevel === LOG_LEVEL_WARN) {
|
|
1384
|
+
return {
|
|
1385
|
+
level: "warn",
|
|
1386
|
+
levels: { debug: false, info: false, warn: true, error: true },
|
|
1387
|
+
debug: debugDisabled,
|
|
1388
|
+
info: infoDisabled,
|
|
1389
|
+
warn,
|
|
1390
|
+
error,
|
|
1391
|
+
};
|
|
1392
|
+
}
|
|
1393
|
+
if (logLevel === LOG_LEVEL_ERROR) {
|
|
1394
|
+
return {
|
|
1395
|
+
level: "error",
|
|
1396
|
+
levels: { debug: false, info: false, warn: false, error: true },
|
|
1397
|
+
debug: debugDisabled,
|
|
1398
|
+
info: infoDisabled,
|
|
1399
|
+
warn: warnDisabled,
|
|
1400
|
+
error,
|
|
1401
|
+
};
|
|
1402
|
+
}
|
|
1403
|
+
if (logLevel === LOG_LEVEL_OFF) {
|
|
1404
|
+
return {
|
|
1405
|
+
level: "off",
|
|
1406
|
+
levels: { debug: false, info: false, warn: false, error: false },
|
|
1407
|
+
debug: debugDisabled,
|
|
1408
|
+
info: infoDisabled,
|
|
1409
|
+
warn: warnDisabled,
|
|
1410
|
+
error: errorDisabled,
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
throw new Error(`unexpected logLevel.
|
|
1414
|
+
--- logLevel ---
|
|
1415
|
+
${logLevel}
|
|
1416
|
+
--- allowed log levels ---
|
|
1417
|
+
${LOG_LEVEL_OFF}
|
|
1418
|
+
${LOG_LEVEL_ERROR}
|
|
1419
|
+
${LOG_LEVEL_WARN}
|
|
1420
|
+
${LOG_LEVEL_INFO}
|
|
1421
|
+
${LOG_LEVEL_DEBUG}`);
|
|
1422
|
+
};
|
|
1423
|
+
|
|
1424
|
+
const debug = (...args) => console.debug(...args);
|
|
1425
|
+
|
|
1426
|
+
const debugDisabled = () => {};
|
|
1427
|
+
|
|
1428
|
+
const info = (...args) => console.info(...args);
|
|
1429
|
+
|
|
1430
|
+
const infoDisabled = () => {};
|
|
1431
|
+
|
|
1432
|
+
const warn = (...args) => console.warn(...args);
|
|
1433
|
+
|
|
1434
|
+
const warnDisabled = () => {};
|
|
1435
|
+
|
|
1436
|
+
const error = (...args) => console.error(...args);
|
|
1437
|
+
|
|
1438
|
+
const errorDisabled = () => {};
|
|
1439
|
+
|
|
1440
|
+
/* globals WorkerGlobalScope, DedicatedWorkerGlobalScope, SharedWorkerGlobalScope, ServiceWorkerGlobalScope */
|
|
1441
|
+
|
|
1442
|
+
const isBrowser = globalThis.window?.document !== undefined;
|
|
1443
|
+
|
|
1444
|
+
globalThis.process?.versions?.node !== undefined;
|
|
1445
|
+
|
|
1446
|
+
globalThis.process?.versions?.bun !== undefined;
|
|
1447
|
+
|
|
1448
|
+
globalThis.Deno?.version?.deno !== undefined;
|
|
1449
|
+
|
|
1450
|
+
globalThis.process?.versions?.electron !== undefined;
|
|
1451
|
+
|
|
1452
|
+
globalThis.navigator?.userAgent?.includes('jsdom') === true;
|
|
1453
|
+
|
|
1454
|
+
typeof WorkerGlobalScope !== 'undefined' && globalThis instanceof WorkerGlobalScope;
|
|
1455
|
+
|
|
1456
|
+
typeof DedicatedWorkerGlobalScope !== 'undefined' && globalThis instanceof DedicatedWorkerGlobalScope;
|
|
1457
|
+
|
|
1458
|
+
typeof SharedWorkerGlobalScope !== 'undefined' && globalThis instanceof SharedWorkerGlobalScope;
|
|
1459
|
+
|
|
1460
|
+
typeof ServiceWorkerGlobalScope !== 'undefined' && globalThis instanceof ServiceWorkerGlobalScope;
|
|
1461
|
+
|
|
1462
|
+
// Note: I'm intentionally not DRYing up the other variables to keep them "lazy".
|
|
1463
|
+
const platform = globalThis.navigator?.userAgentData?.platform;
|
|
1464
|
+
|
|
1465
|
+
platform === 'macOS'
|
|
1466
|
+
|| globalThis.navigator?.platform === 'MacIntel' // Even on Apple silicon Macs.
|
|
1467
|
+
|| globalThis.navigator?.userAgent?.includes(' Mac ') === true
|
|
1468
|
+
|| globalThis.process?.platform === 'darwin';
|
|
1469
|
+
|
|
1470
|
+
platform === 'Windows'
|
|
1471
|
+
|| globalThis.navigator?.platform === 'Win32'
|
|
1472
|
+
|| globalThis.process?.platform === 'win32';
|
|
1473
|
+
|
|
1474
|
+
platform === 'Linux'
|
|
1475
|
+
|| globalThis.navigator?.platform?.startsWith('Linux') === true
|
|
1476
|
+
|| globalThis.navigator?.userAgent?.includes(' Linux ') === true
|
|
1477
|
+
|| globalThis.process?.platform === 'linux';
|
|
1478
|
+
|
|
1479
|
+
platform === 'Android'
|
|
1480
|
+
|| globalThis.navigator?.platform === 'Android'
|
|
1481
|
+
|| globalThis.navigator?.userAgent?.includes(' Android ') === true
|
|
1482
|
+
|| globalThis.process?.platform === 'android';
|
|
1483
|
+
|
|
1484
|
+
const ESC = '\u001B[';
|
|
1485
|
+
|
|
1486
|
+
!isBrowser && process$1.env.TERM_PROGRAM === 'Apple_Terminal';
|
|
1487
|
+
const isWindows$3 = !isBrowser && process$1.platform === 'win32';
|
|
1488
|
+
|
|
1489
|
+
isBrowser ? () => {
|
|
1490
|
+
throw new Error('`process.cwd()` only works in Node.js, not the browser.');
|
|
1491
|
+
} : process$1.cwd;
|
|
1492
|
+
|
|
1493
|
+
const cursorUp = (count = 1) => ESC + count + 'A';
|
|
1494
|
+
|
|
1495
|
+
const cursorLeft = ESC + 'G';
|
|
1496
|
+
|
|
1497
|
+
const eraseLines = count => {
|
|
1498
|
+
let clear = '';
|
|
1499
|
+
|
|
1500
|
+
for (let i = 0; i < count; i++) {
|
|
1501
|
+
clear += eraseLine + (i < count - 1 ? cursorUp() : '');
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
if (count) {
|
|
1505
|
+
clear += cursorLeft;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
return clear;
|
|
1509
|
+
};
|
|
1510
|
+
const eraseLine = ESC + '2K';
|
|
1511
|
+
const eraseScreen = ESC + '2J';
|
|
1512
|
+
|
|
1513
|
+
const clearTerminal = isWindows$3
|
|
1514
|
+
? `${eraseScreen}${ESC}0f`
|
|
1515
|
+
// 1. Erases the screen (Only done in case `2` is not supported)
|
|
1516
|
+
// 2. Erases the whole screen including scrollback buffer
|
|
1517
|
+
// 3. Moves cursor to the top-left position
|
|
1518
|
+
// More info: https://www.real-world-systems.com/docs/ANSIcode.html
|
|
1519
|
+
: `${eraseScreen}${ESC}3J${ESC}H`;
|
|
1520
|
+
|
|
1521
|
+
/*
|
|
1522
|
+
* see also https://github.com/vadimdemedes/ink
|
|
1523
|
+
*/
|
|
1524
|
+
|
|
1525
|
+
|
|
1526
|
+
const createDynamicLog = ({
|
|
1527
|
+
stream = process.stdout,
|
|
1528
|
+
clearTerminalAllowed,
|
|
1529
|
+
onVerticalOverflow = () => {},
|
|
1530
|
+
onWriteFromOutside = () => {},
|
|
1531
|
+
} = {}) => {
|
|
1532
|
+
const { columns = 80, rows = 24 } = stream;
|
|
1533
|
+
const dynamicLog = {
|
|
1534
|
+
destroyed: false,
|
|
1535
|
+
onVerticalOverflow,
|
|
1536
|
+
onWriteFromOutside,
|
|
1537
|
+
};
|
|
1538
|
+
|
|
1539
|
+
let lastOutput = "";
|
|
1540
|
+
let lastOutputFromOutside = "";
|
|
1541
|
+
let clearAttemptResult;
|
|
1542
|
+
let writing = false;
|
|
1543
|
+
|
|
1544
|
+
const getErasePreviousOutput = () => {
|
|
1545
|
+
// nothing to clear
|
|
1546
|
+
if (!lastOutput) {
|
|
1547
|
+
return "";
|
|
1548
|
+
}
|
|
1549
|
+
if (clearAttemptResult !== undefined) {
|
|
1550
|
+
return "";
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
const logLines = lastOutput.split(/\r\n|\r|\n/);
|
|
1554
|
+
let visualLineCount = 0;
|
|
1555
|
+
for (const logLine of logLines) {
|
|
1556
|
+
const width = stringWidth(logLine);
|
|
1557
|
+
if (width === 0) {
|
|
1558
|
+
visualLineCount++;
|
|
1559
|
+
} else {
|
|
1560
|
+
visualLineCount += Math.ceil(width / columns);
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
if (visualLineCount > rows) {
|
|
1565
|
+
if (clearTerminalAllowed) {
|
|
1566
|
+
clearAttemptResult = true;
|
|
1567
|
+
return clearTerminal;
|
|
1568
|
+
}
|
|
1569
|
+
// the whole log cannot be cleared because it's vertically to long
|
|
1570
|
+
// (longer than terminal height)
|
|
1571
|
+
// readline.moveCursor cannot move cursor higher than screen height
|
|
1572
|
+
// it means we would only clear the visible part of the log
|
|
1573
|
+
// better keep the log untouched
|
|
1574
|
+
clearAttemptResult = false;
|
|
1575
|
+
dynamicLog.onVerticalOverflow();
|
|
1576
|
+
return "";
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
clearAttemptResult = true;
|
|
1580
|
+
return eraseLines(visualLineCount);
|
|
1581
|
+
};
|
|
1582
|
+
|
|
1583
|
+
const update = (string) => {
|
|
1584
|
+
if (dynamicLog.destroyed) {
|
|
1585
|
+
throw new Error("Cannot write log after destroy");
|
|
1586
|
+
}
|
|
1587
|
+
let stringToWrite = string;
|
|
1588
|
+
if (lastOutput) {
|
|
1589
|
+
if (lastOutputFromOutside) {
|
|
1590
|
+
// We don't want to clear logs written by other code,
|
|
1591
|
+
// it makes output unreadable and might erase precious information
|
|
1592
|
+
// To detect this we put a spy on the stream.
|
|
1593
|
+
// The spy is required only if we actually wrote something in the stream
|
|
1594
|
+
// something else than this code has written in the stream
|
|
1595
|
+
// so we just write without clearing (append instead of replacing)
|
|
1596
|
+
lastOutput = "";
|
|
1597
|
+
lastOutputFromOutside = "";
|
|
1598
|
+
} else {
|
|
1599
|
+
stringToWrite = `${getErasePreviousOutput()}${string}`;
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
writing = true;
|
|
1603
|
+
stream.write(stringToWrite);
|
|
1604
|
+
lastOutput = string;
|
|
1605
|
+
writing = false;
|
|
1606
|
+
clearAttemptResult = undefined;
|
|
1607
|
+
};
|
|
1608
|
+
|
|
1609
|
+
const clearDuringFunctionCall = (
|
|
1610
|
+
callback,
|
|
1611
|
+
ouputAfterCallback = lastOutput,
|
|
1612
|
+
) => {
|
|
1613
|
+
// 1. Erase the current log
|
|
1614
|
+
// 2. Call callback (expect to write something on stdout)
|
|
1615
|
+
// 3. Restore the current log
|
|
1616
|
+
// During step 2. we expect a "write from outside" so we uninstall
|
|
1617
|
+
// the stream spy during function call
|
|
1618
|
+
update("");
|
|
1619
|
+
|
|
1620
|
+
writing = true;
|
|
1621
|
+
callback();
|
|
1622
|
+
writing = false;
|
|
1623
|
+
|
|
1624
|
+
update(ouputAfterCallback);
|
|
1625
|
+
};
|
|
1626
|
+
|
|
1627
|
+
const writeFromOutsideEffect = (value) => {
|
|
1628
|
+
if (!lastOutput) {
|
|
1629
|
+
// we don't care if the log never wrote anything
|
|
1630
|
+
// or if last update() wrote an empty string
|
|
1631
|
+
return;
|
|
1632
|
+
}
|
|
1633
|
+
if (writing) {
|
|
1634
|
+
return;
|
|
1635
|
+
}
|
|
1636
|
+
lastOutputFromOutside = value;
|
|
1637
|
+
dynamicLog.onWriteFromOutside(value);
|
|
1638
|
+
};
|
|
1639
|
+
|
|
1640
|
+
let removeStreamSpy;
|
|
1641
|
+
if (stream === process.stdout) {
|
|
1642
|
+
const removeStdoutSpy = spyStreamOutput(
|
|
1643
|
+
process.stdout,
|
|
1644
|
+
writeFromOutsideEffect,
|
|
1645
|
+
);
|
|
1646
|
+
const removeStderrSpy = spyStreamOutput(
|
|
1647
|
+
process.stderr,
|
|
1648
|
+
writeFromOutsideEffect,
|
|
1649
|
+
);
|
|
1650
|
+
removeStreamSpy = () => {
|
|
1651
|
+
removeStdoutSpy();
|
|
1652
|
+
removeStderrSpy();
|
|
1653
|
+
};
|
|
1654
|
+
} else {
|
|
1655
|
+
removeStreamSpy = spyStreamOutput(stream, writeFromOutsideEffect);
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
const destroy = () => {
|
|
1659
|
+
dynamicLog.destroyed = true;
|
|
1660
|
+
if (removeStreamSpy) {
|
|
1661
|
+
removeStreamSpy();
|
|
1662
|
+
removeStreamSpy = null;
|
|
1663
|
+
lastOutput = "";
|
|
1664
|
+
lastOutputFromOutside = "";
|
|
1665
|
+
}
|
|
1666
|
+
};
|
|
1667
|
+
|
|
1668
|
+
Object.assign(dynamicLog, {
|
|
1669
|
+
update,
|
|
1670
|
+
destroy,
|
|
1671
|
+
stream,
|
|
1672
|
+
clearDuringFunctionCall,
|
|
1673
|
+
});
|
|
1674
|
+
return dynamicLog;
|
|
1675
|
+
};
|
|
1676
|
+
|
|
1677
|
+
// maybe https://github.com/gajus/output-interceptor/tree/v3.0.0 ?
|
|
1678
|
+
// the problem with listening data on stdout
|
|
1679
|
+
// is that node.js will later throw error if stream gets closed
|
|
1680
|
+
// while something listening data on it
|
|
1681
|
+
const spyStreamOutput = (stream, callback) => {
|
|
1682
|
+
const originalWrite = stream.write;
|
|
1683
|
+
|
|
1684
|
+
let output = "";
|
|
1685
|
+
let installed = true;
|
|
1686
|
+
|
|
1687
|
+
stream.write = function (...args /* chunk, encoding, callback */) {
|
|
1688
|
+
output += args;
|
|
1689
|
+
callback(output);
|
|
1690
|
+
return originalWrite.call(stream, ...args);
|
|
1691
|
+
};
|
|
1692
|
+
|
|
1693
|
+
const uninstall = () => {
|
|
1694
|
+
if (!installed) {
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
stream.write = originalWrite;
|
|
1698
|
+
installed = false;
|
|
1699
|
+
};
|
|
1700
|
+
|
|
1701
|
+
return () => {
|
|
1702
|
+
uninstall();
|
|
1703
|
+
return output;
|
|
1704
|
+
};
|
|
1705
|
+
};
|
|
1706
|
+
|
|
1707
|
+
const startSpinner = ({
|
|
1708
|
+
dynamicLog,
|
|
1709
|
+
frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
|
|
1710
|
+
fps = 20,
|
|
1711
|
+
keepProcessAlive = false,
|
|
1712
|
+
stopOnWriteFromOutside = true,
|
|
1713
|
+
stopOnVerticalOverflow = true,
|
|
1714
|
+
render = () => "",
|
|
1715
|
+
effect = () => {},
|
|
1716
|
+
animated = dynamicLog.stream.isTTY,
|
|
1717
|
+
}) => {
|
|
1718
|
+
let frameIndex = 0;
|
|
1719
|
+
let interval;
|
|
1720
|
+
let running = true;
|
|
1721
|
+
|
|
1722
|
+
const spinner = {
|
|
1723
|
+
message: undefined,
|
|
1724
|
+
};
|
|
1725
|
+
|
|
1726
|
+
const update = (message) => {
|
|
1727
|
+
spinner.message = running
|
|
1728
|
+
? `${frames[frameIndex]} ${message}\n`
|
|
1729
|
+
: `${message}\n`;
|
|
1730
|
+
return spinner.message;
|
|
1731
|
+
};
|
|
1732
|
+
spinner.update = update;
|
|
1733
|
+
|
|
1734
|
+
let cleanup;
|
|
1735
|
+
if (animated && ANSI.supported) {
|
|
1736
|
+
running = true;
|
|
1737
|
+
cleanup = effect();
|
|
1738
|
+
dynamicLog.update(update(render()));
|
|
1739
|
+
|
|
1740
|
+
interval = setInterval(() => {
|
|
1741
|
+
frameIndex = frameIndex === frames.length - 1 ? 0 : frameIndex + 1;
|
|
1742
|
+
dynamicLog.update(update(render()));
|
|
1743
|
+
}, 1000 / fps);
|
|
1744
|
+
if (!keepProcessAlive) {
|
|
1745
|
+
interval.unref();
|
|
1746
|
+
}
|
|
1747
|
+
} else {
|
|
1748
|
+
dynamicLog.update(update(render()));
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
const stop = (message) => {
|
|
1752
|
+
running = false;
|
|
1753
|
+
if (interval) {
|
|
1754
|
+
clearInterval(interval);
|
|
1755
|
+
interval = null;
|
|
1756
|
+
}
|
|
1757
|
+
if (cleanup) {
|
|
1758
|
+
cleanup();
|
|
1759
|
+
cleanup = null;
|
|
1760
|
+
}
|
|
1761
|
+
if (dynamicLog && message) {
|
|
1762
|
+
dynamicLog.update(update(message));
|
|
1763
|
+
dynamicLog = null;
|
|
1764
|
+
}
|
|
1765
|
+
};
|
|
1766
|
+
spinner.stop = stop;
|
|
1767
|
+
|
|
1768
|
+
if (stopOnVerticalOverflow) {
|
|
1769
|
+
dynamicLog.onVerticalOverflow = stop;
|
|
1770
|
+
}
|
|
1771
|
+
if (stopOnWriteFromOutside) {
|
|
1772
|
+
dynamicLog.onWriteFromOutside = stop;
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
return spinner;
|
|
1776
|
+
};
|
|
1777
|
+
|
|
1778
|
+
const createTaskLog = (
|
|
1779
|
+
label,
|
|
1780
|
+
{ disabled = false, animated = true, stopOnWriteFromOutside } = {},
|
|
1781
|
+
) => {
|
|
1782
|
+
if (disabled) {
|
|
1783
|
+
return {
|
|
1784
|
+
setRightText: () => {},
|
|
1785
|
+
done: () => {},
|
|
1786
|
+
happen: () => {},
|
|
1787
|
+
fail: () => {},
|
|
1788
|
+
};
|
|
1789
|
+
}
|
|
1790
|
+
const startMs = Date.now();
|
|
1791
|
+
const dynamicLog = createDynamicLog();
|
|
1792
|
+
let message = label;
|
|
1793
|
+
const taskSpinner = startSpinner({
|
|
1794
|
+
dynamicLog,
|
|
1795
|
+
render: () => message,
|
|
1796
|
+
stopOnWriteFromOutside,
|
|
1797
|
+
animated,
|
|
1798
|
+
});
|
|
1799
|
+
return {
|
|
1800
|
+
setRightText: (value) => {
|
|
1801
|
+
message = `${label} ${value}`;
|
|
1802
|
+
},
|
|
1803
|
+
done: () => {
|
|
1804
|
+
const msEllapsed = Date.now() - startMs;
|
|
1805
|
+
taskSpinner.stop(
|
|
1806
|
+
`${UNICODE.OK} ${label} (done in ${humanizeDuration(msEllapsed)})`,
|
|
1807
|
+
);
|
|
1808
|
+
},
|
|
1809
|
+
happen: (message) => {
|
|
1810
|
+
taskSpinner.stop(
|
|
1811
|
+
`${UNICODE.INFO} ${message} (at ${new Date().toLocaleTimeString()})`,
|
|
1812
|
+
);
|
|
1813
|
+
},
|
|
1814
|
+
fail: (message = `failed to ${label}`) => {
|
|
1815
|
+
taskSpinner.stop(`${UNICODE.FAILURE} ${message}`);
|
|
1816
|
+
},
|
|
1817
|
+
};
|
|
1818
|
+
};
|
|
1819
|
+
|
|
1764
1820
|
// consider switching to https://babeljs.io/docs/en/babel-code-frame
|
|
1765
1821
|
// https://github.com/postcss/postcss/blob/fd30d3df5abc0954a0ec642a3cdc644ab2aacf9c/lib/css-syntax-error.js#L43
|
|
1766
1822
|
// https://github.com/postcss/postcss/blob/fd30d3df5abc0954a0ec642a3cdc644ab2aacf9c/lib/terminal-highlight.js#L50
|