1 | /*
|
---|
2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
---|
3 | Author Tobias Koppers @sokra
|
---|
4 | */
|
---|
5 |
|
---|
6 | "use strict";
|
---|
7 |
|
---|
8 | const { LogType } = require("./Logger");
|
---|
9 |
|
---|
10 | /** @typedef {import("../../declarations/WebpackOptions").FilterItemTypes} FilterItemTypes */
|
---|
11 | /** @typedef {import("../../declarations/WebpackOptions").FilterTypes} FilterTypes */
|
---|
12 | /** @typedef {import("./Logger").LogTypeEnum} LogTypeEnum */
|
---|
13 |
|
---|
14 | /** @typedef {function(string): boolean} FilterFunction */
|
---|
15 |
|
---|
16 | /**
|
---|
17 | * @typedef {Object} LoggerConsole
|
---|
18 | * @property {function(): void} clear
|
---|
19 | * @property {function(): void} trace
|
---|
20 | * @property {(...args: any[]) => void} info
|
---|
21 | * @property {(...args: any[]) => void} log
|
---|
22 | * @property {(...args: any[]) => void} warn
|
---|
23 | * @property {(...args: any[]) => void} error
|
---|
24 | * @property {(...args: any[]) => void=} debug
|
---|
25 | * @property {(...args: any[]) => void=} group
|
---|
26 | * @property {(...args: any[]) => void=} groupCollapsed
|
---|
27 | * @property {(...args: any[]) => void=} groupEnd
|
---|
28 | * @property {(...args: any[]) => void=} status
|
---|
29 | * @property {(...args: any[]) => void=} profile
|
---|
30 | * @property {(...args: any[]) => void=} profileEnd
|
---|
31 | * @property {(...args: any[]) => void=} logTime
|
---|
32 | */
|
---|
33 |
|
---|
34 | /**
|
---|
35 | * @typedef {Object} LoggerOptions
|
---|
36 | * @property {false|true|"none"|"error"|"warn"|"info"|"log"|"verbose"} level loglevel
|
---|
37 | * @property {FilterTypes|boolean} debug filter for debug logging
|
---|
38 | * @property {LoggerConsole} console the console to log to
|
---|
39 | */
|
---|
40 |
|
---|
41 | /**
|
---|
42 | * @param {FilterItemTypes} item an input item
|
---|
43 | * @returns {FilterFunction} filter function
|
---|
44 | */
|
---|
45 | const filterToFunction = item => {
|
---|
46 | if (typeof item === "string") {
|
---|
47 | const regExp = new RegExp(
|
---|
48 | `[\\\\/]${item.replace(
|
---|
49 | // eslint-disable-next-line no-useless-escape
|
---|
50 | /[-[\]{}()*+?.\\^$|]/g,
|
---|
51 | "\\$&"
|
---|
52 | )}([\\\\/]|$|!|\\?)`
|
---|
53 | );
|
---|
54 | return ident => regExp.test(ident);
|
---|
55 | }
|
---|
56 | if (item && typeof item === "object" && typeof item.test === "function") {
|
---|
57 | return ident => item.test(ident);
|
---|
58 | }
|
---|
59 | if (typeof item === "function") {
|
---|
60 | return item;
|
---|
61 | }
|
---|
62 | if (typeof item === "boolean") {
|
---|
63 | return () => item;
|
---|
64 | }
|
---|
65 | };
|
---|
66 |
|
---|
67 | /**
|
---|
68 | * @enum {number}
|
---|
69 | */
|
---|
70 | const LogLevel = {
|
---|
71 | none: 6,
|
---|
72 | false: 6,
|
---|
73 | error: 5,
|
---|
74 | warn: 4,
|
---|
75 | info: 3,
|
---|
76 | log: 2,
|
---|
77 | true: 2,
|
---|
78 | verbose: 1
|
---|
79 | };
|
---|
80 |
|
---|
81 | /**
|
---|
82 | * @param {LoggerOptions} options options object
|
---|
83 | * @returns {function(string, LogTypeEnum, any[]): void} logging function
|
---|
84 | */
|
---|
85 | module.exports = ({ level = "info", debug = false, console }) => {
|
---|
86 | const debugFilters =
|
---|
87 | typeof debug === "boolean"
|
---|
88 | ? [() => debug]
|
---|
89 | : /** @type {FilterItemTypes[]} */ ([])
|
---|
90 | .concat(debug)
|
---|
91 | .map(filterToFunction);
|
---|
92 | /** @type {number} */
|
---|
93 | const loglevel = LogLevel[`${level}`] || 0;
|
---|
94 |
|
---|
95 | /**
|
---|
96 | * @param {string} name name of the logger
|
---|
97 | * @param {LogTypeEnum} type type of the log entry
|
---|
98 | * @param {any[]} args arguments of the log entry
|
---|
99 | * @returns {void}
|
---|
100 | */
|
---|
101 | const logger = (name, type, args) => {
|
---|
102 | const labeledArgs = () => {
|
---|
103 | if (Array.isArray(args)) {
|
---|
104 | if (args.length > 0 && typeof args[0] === "string") {
|
---|
105 | return [`[${name}] ${args[0]}`, ...args.slice(1)];
|
---|
106 | } else {
|
---|
107 | return [`[${name}]`, ...args];
|
---|
108 | }
|
---|
109 | } else {
|
---|
110 | return [];
|
---|
111 | }
|
---|
112 | };
|
---|
113 | const debug = debugFilters.some(f => f(name));
|
---|
114 | switch (type) {
|
---|
115 | case LogType.debug:
|
---|
116 | if (!debug) return;
|
---|
117 | // eslint-disable-next-line node/no-unsupported-features/node-builtins
|
---|
118 | if (typeof console.debug === "function") {
|
---|
119 | // eslint-disable-next-line node/no-unsupported-features/node-builtins
|
---|
120 | console.debug(...labeledArgs());
|
---|
121 | } else {
|
---|
122 | console.log(...labeledArgs());
|
---|
123 | }
|
---|
124 | break;
|
---|
125 | case LogType.log:
|
---|
126 | if (!debug && loglevel > LogLevel.log) return;
|
---|
127 | console.log(...labeledArgs());
|
---|
128 | break;
|
---|
129 | case LogType.info:
|
---|
130 | if (!debug && loglevel > LogLevel.info) return;
|
---|
131 | console.info(...labeledArgs());
|
---|
132 | break;
|
---|
133 | case LogType.warn:
|
---|
134 | if (!debug && loglevel > LogLevel.warn) return;
|
---|
135 | console.warn(...labeledArgs());
|
---|
136 | break;
|
---|
137 | case LogType.error:
|
---|
138 | if (!debug && loglevel > LogLevel.error) return;
|
---|
139 | console.error(...labeledArgs());
|
---|
140 | break;
|
---|
141 | case LogType.trace:
|
---|
142 | if (!debug) return;
|
---|
143 | console.trace();
|
---|
144 | break;
|
---|
145 | case LogType.groupCollapsed:
|
---|
146 | if (!debug && loglevel > LogLevel.log) return;
|
---|
147 | if (!debug && loglevel > LogLevel.verbose) {
|
---|
148 | // eslint-disable-next-line node/no-unsupported-features/node-builtins
|
---|
149 | if (typeof console.groupCollapsed === "function") {
|
---|
150 | // eslint-disable-next-line node/no-unsupported-features/node-builtins
|
---|
151 | console.groupCollapsed(...labeledArgs());
|
---|
152 | } else {
|
---|
153 | console.log(...labeledArgs());
|
---|
154 | }
|
---|
155 | break;
|
---|
156 | }
|
---|
157 | // falls through
|
---|
158 | case LogType.group:
|
---|
159 | if (!debug && loglevel > LogLevel.log) return;
|
---|
160 | // eslint-disable-next-line node/no-unsupported-features/node-builtins
|
---|
161 | if (typeof console.group === "function") {
|
---|
162 | // eslint-disable-next-line node/no-unsupported-features/node-builtins
|
---|
163 | console.group(...labeledArgs());
|
---|
164 | } else {
|
---|
165 | console.log(...labeledArgs());
|
---|
166 | }
|
---|
167 | break;
|
---|
168 | case LogType.groupEnd:
|
---|
169 | if (!debug && loglevel > LogLevel.log) return;
|
---|
170 | // eslint-disable-next-line node/no-unsupported-features/node-builtins
|
---|
171 | if (typeof console.groupEnd === "function") {
|
---|
172 | // eslint-disable-next-line node/no-unsupported-features/node-builtins
|
---|
173 | console.groupEnd();
|
---|
174 | }
|
---|
175 | break;
|
---|
176 | case LogType.time: {
|
---|
177 | if (!debug && loglevel > LogLevel.log) return;
|
---|
178 | const ms = args[1] * 1000 + args[2] / 1000000;
|
---|
179 | const msg = `[${name}] ${args[0]}: ${ms} ms`;
|
---|
180 | if (typeof console.logTime === "function") {
|
---|
181 | console.logTime(msg);
|
---|
182 | } else {
|
---|
183 | console.log(msg);
|
---|
184 | }
|
---|
185 | break;
|
---|
186 | }
|
---|
187 | case LogType.profile:
|
---|
188 | // eslint-disable-next-line node/no-unsupported-features/node-builtins
|
---|
189 | if (typeof console.profile === "function") {
|
---|
190 | // eslint-disable-next-line node/no-unsupported-features/node-builtins
|
---|
191 | console.profile(...labeledArgs());
|
---|
192 | }
|
---|
193 | break;
|
---|
194 | case LogType.profileEnd:
|
---|
195 | // eslint-disable-next-line node/no-unsupported-features/node-builtins
|
---|
196 | if (typeof console.profileEnd === "function") {
|
---|
197 | // eslint-disable-next-line node/no-unsupported-features/node-builtins
|
---|
198 | console.profileEnd(...labeledArgs());
|
---|
199 | }
|
---|
200 | break;
|
---|
201 | case LogType.clear:
|
---|
202 | if (!debug && loglevel > LogLevel.log) return;
|
---|
203 | // eslint-disable-next-line node/no-unsupported-features/node-builtins
|
---|
204 | if (typeof console.clear === "function") {
|
---|
205 | // eslint-disable-next-line node/no-unsupported-features/node-builtins
|
---|
206 | console.clear();
|
---|
207 | }
|
---|
208 | break;
|
---|
209 | case LogType.status:
|
---|
210 | if (!debug && loglevel > LogLevel.info) return;
|
---|
211 | if (typeof console.status === "function") {
|
---|
212 | if (args.length === 0) {
|
---|
213 | console.status();
|
---|
214 | } else {
|
---|
215 | console.status(...labeledArgs());
|
---|
216 | }
|
---|
217 | } else {
|
---|
218 | if (args.length !== 0) {
|
---|
219 | console.info(...labeledArgs());
|
---|
220 | }
|
---|
221 | }
|
---|
222 | break;
|
---|
223 | default:
|
---|
224 | throw new Error(`Unexpected LogType ${type}`);
|
---|
225 | }
|
---|
226 | };
|
---|
227 | return logger;
|
---|
228 | };
|
---|