1 | import { relative } from "path";
|
2 | import { fileURLToPath } from "url";
|
3 | import { inspect } from "util";
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | export function writePretty(stream, level, timestamp, context, message) {
|
14 | stream.write(`${formatPretty(level, timestamp, context, message)}\n`);
|
15 | }
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | export function writeGithubActions(stream, level, timestamp, context, message) {
|
26 | if (level === "error") {
|
27 |
|
28 | const { relativePath, column, line } = getErrorLogCaller();
|
29 |
|
30 |
|
31 |
|
32 | stream.write(
|
33 | `::error file=${relativePath},line=${line},col=${column}::${formatPretty(
|
34 | undefined, // Always an error
|
35 | timestamp,
|
36 | context,
|
37 | message,
|
38 | )
|
39 | .replace(/\n/g, "%0A")
|
40 |
|
41 | // Removes ansi color codes from logs
|
42 | // eslint-disable-next-line no-control-regex
|
43 | .replace(/\u001b\[.*?m/g, "")}\n`,
|
44 | );
|
45 | } else {
|
46 | writePretty(stream, level, timestamp, context, message);
|
47 | }
|
48 | }
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 | export function formatPretty(level, timestamp, context, message) {
|
58 | let prefix = level
|
59 | ? `${formatDate(timestamp)} ${formatLevelAndType(level, context?.type)} `
|
60 | : "";
|
61 |
|
62 | if (message) {
|
63 | if (Array.isArray(message)) {
|
64 | return `${
|
65 | prefix + message.map((it) => formatMessagePretty(it)).join(", ")
|
66 | }`;
|
67 | }
|
68 | let keyCount = 0;
|
69 | if (context?.type) {
|
70 |
|
71 | keyCount = 1;
|
72 | }
|
73 |
|
74 | if (Object.keys(context).length > keyCount) {
|
75 | prefix += `${formatMessagePretty(context)} `;
|
76 | }
|
77 |
|
78 | return `${prefix + formatMessagePretty(message)}`;
|
79 | }
|
80 |
|
81 | return prefix;
|
82 | }
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 | function formatMessagePretty(value) {
|
89 | if (
|
90 | typeof value === "boolean" ||
|
91 | typeof value === "string" ||
|
92 | typeof value === "number"
|
93 | ) {
|
94 | return String(value);
|
95 | }
|
96 | return inspect(value, {
|
97 | colors: true,
|
98 | depth: null,
|
99 | });
|
100 | }
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 | function formatDate(date) {
|
107 | const h = date.getHours().toString(10).padStart(2, "0");
|
108 | const m = date.getMinutes().toString(10).padStart(2, "0");
|
109 | const s = date.getSeconds().toString(10).padStart(2, "0");
|
110 | const ms = date.getMilliseconds().toString(10).padStart(3, "0");
|
111 |
|
112 | return `${h}:${m}:${s}.${ms}`;
|
113 | }
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 | function formatLevelAndType(level, type) {
|
121 | const str =
|
122 | typeof type === "string" && type.length > 0 ? `${level}[${type}]` : level;
|
123 |
|
124 | return level === "error"
|
125 | ? `\x1b[31m${str}\x1b[39m`
|
126 | : `\x1b[34m${str}\x1b[39m`;
|
127 | }
|
128 |
|
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 | function getErrorLogCaller() {
|
139 | const err = {};
|
140 | Error.captureStackTrace(err);
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 | const stackLines = err.stack.split("\n").slice(1);
|
150 |
|
151 | let callerStackLine = stackLines[0].trim();
|
152 | for (const line of stackLines) {
|
153 | if (
|
154 | line.includes("getErrorLogCaller") ||
|
155 | line.includes("writeGithubActions") ||
|
156 | line.includes("wrapWriter") ||
|
157 | line.includes("Object.error")
|
158 | ) {
|
159 | continue;
|
160 | }
|
161 |
|
162 | callerStackLine = line.trim();
|
163 | break;
|
164 | }
|
165 |
|
166 | const rawLocation = callerStackLine.split(" ")[2];
|
167 |
|
168 | if (callerStackLine.length === 0 || (rawLocation?.length ?? 0) < 5) {
|
169 | return {
|
170 | relativePath: rawLocation,
|
171 | line: 1,
|
172 | column: 1,
|
173 | };
|
174 | }
|
175 |
|
176 | const rawLocationParts = rawLocation
|
177 | .substring(1, rawLocation.length - 1)
|
178 | .split(":");
|
179 |
|
180 | const rawFile = rawLocationParts
|
181 | .splice(0, rawLocationParts.length - 2)
|
182 | .join(":");
|
183 |
|
184 | return {
|
185 | relativePath: relative(process.cwd(), fileURLToPath(rawFile)),
|
186 | line: rawLocationParts[0],
|
187 | column: rawLocationParts[1],
|
188 | };
|
189 | }
|