core.cjs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. 'use strict';
  2. const LogLevels = {
  3. silent: Number.NEGATIVE_INFINITY,
  4. fatal: 0,
  5. error: 0,
  6. warn: 1,
  7. log: 2,
  8. info: 3,
  9. success: 3,
  10. fail: 3,
  11. ready: 3,
  12. start: 3,
  13. box: 3,
  14. debug: 4,
  15. trace: 5,
  16. verbose: Number.POSITIVE_INFINITY
  17. };
  18. const LogTypes = {
  19. // Silent
  20. silent: {
  21. level: -1
  22. },
  23. // Level 0
  24. fatal: {
  25. level: LogLevels.fatal
  26. },
  27. error: {
  28. level: LogLevels.error
  29. },
  30. // Level 1
  31. warn: {
  32. level: LogLevels.warn
  33. },
  34. // Level 2
  35. log: {
  36. level: LogLevels.log
  37. },
  38. // Level 3
  39. info: {
  40. level: LogLevels.info
  41. },
  42. success: {
  43. level: LogLevels.success
  44. },
  45. fail: {
  46. level: LogLevels.fail
  47. },
  48. ready: {
  49. level: LogLevels.info
  50. },
  51. start: {
  52. level: LogLevels.info
  53. },
  54. box: {
  55. level: LogLevels.info
  56. },
  57. // Level 4
  58. debug: {
  59. level: LogLevels.debug
  60. },
  61. // Level 5
  62. trace: {
  63. level: LogLevels.trace
  64. },
  65. // Verbose
  66. verbose: {
  67. level: LogLevels.verbose
  68. }
  69. };
  70. function isPlainObject$1(value) {
  71. if (value === null || typeof value !== "object") {
  72. return false;
  73. }
  74. const prototype = Object.getPrototypeOf(value);
  75. if (prototype !== null && prototype !== Object.prototype && Object.getPrototypeOf(prototype) !== null) {
  76. return false;
  77. }
  78. if (Symbol.iterator in value) {
  79. return false;
  80. }
  81. if (Symbol.toStringTag in value) {
  82. return Object.prototype.toString.call(value) === "[object Module]";
  83. }
  84. return true;
  85. }
  86. function _defu(baseObject, defaults, namespace = ".", merger) {
  87. if (!isPlainObject$1(defaults)) {
  88. return _defu(baseObject, {}, namespace, merger);
  89. }
  90. const object = Object.assign({}, defaults);
  91. for (const key in baseObject) {
  92. if (key === "__proto__" || key === "constructor") {
  93. continue;
  94. }
  95. const value = baseObject[key];
  96. if (value === null || value === void 0) {
  97. continue;
  98. }
  99. if (merger && merger(object, key, value, namespace)) {
  100. continue;
  101. }
  102. if (Array.isArray(value) && Array.isArray(object[key])) {
  103. object[key] = [...value, ...object[key]];
  104. } else if (isPlainObject$1(value) && isPlainObject$1(object[key])) {
  105. object[key] = _defu(
  106. value,
  107. object[key],
  108. (namespace ? `${namespace}.` : "") + key.toString(),
  109. merger
  110. );
  111. } else {
  112. object[key] = value;
  113. }
  114. }
  115. return object;
  116. }
  117. function createDefu(merger) {
  118. return (...arguments_) => (
  119. // eslint-disable-next-line unicorn/no-array-reduce
  120. arguments_.reduce((p, c) => _defu(p, c, "", merger), {})
  121. );
  122. }
  123. const defu = createDefu();
  124. function isPlainObject(obj) {
  125. return Object.prototype.toString.call(obj) === "[object Object]";
  126. }
  127. function isLogObj(arg) {
  128. if (!isPlainObject(arg)) {
  129. return false;
  130. }
  131. if (!arg.message && !arg.args) {
  132. return false;
  133. }
  134. if (arg.stack) {
  135. return false;
  136. }
  137. return true;
  138. }
  139. let paused = false;
  140. const queue = [];
  141. class Consola {
  142. options;
  143. _lastLog;
  144. _mockFn;
  145. /**
  146. * Creates an instance of Consola with specified options or defaults.
  147. *
  148. * @param {Partial<ConsolaOptions>} [options={}] - Configuration options for the Consola instance.
  149. */
  150. constructor(options = {}) {
  151. const types = options.types || LogTypes;
  152. this.options = defu(
  153. {
  154. ...options,
  155. defaults: { ...options.defaults },
  156. level: _normalizeLogLevel(options.level, types),
  157. reporters: [...options.reporters || []]
  158. },
  159. {
  160. types: LogTypes,
  161. throttle: 1e3,
  162. throttleMin: 5,
  163. formatOptions: {
  164. date: true,
  165. colors: false,
  166. compact: true
  167. }
  168. }
  169. );
  170. for (const type in types) {
  171. const defaults = {
  172. type,
  173. ...this.options.defaults,
  174. ...types[type]
  175. };
  176. this[type] = this._wrapLogFn(defaults);
  177. this[type].raw = this._wrapLogFn(
  178. defaults,
  179. true
  180. );
  181. }
  182. if (this.options.mockFn) {
  183. this.mockTypes();
  184. }
  185. this._lastLog = {};
  186. }
  187. /**
  188. * Gets the current log level of the Consola instance.
  189. *
  190. * @returns {number} The current log level.
  191. */
  192. get level() {
  193. return this.options.level;
  194. }
  195. /**
  196. * Sets the minimum log level that will be output by the instance.
  197. *
  198. * @param {number} level - The new log level to set.
  199. */
  200. set level(level) {
  201. this.options.level = _normalizeLogLevel(
  202. level,
  203. this.options.types,
  204. this.options.level
  205. );
  206. }
  207. /**
  208. * Displays a prompt to the user and returns the response.
  209. * Throw an error if `prompt` is not supported by the current configuration.
  210. *
  211. * @template T
  212. * @param {string} message - The message to display in the prompt.
  213. * @param {T} [opts] - Optional options for the prompt. See {@link PromptOptions}.
  214. * @returns {promise<T>} A promise that infer with the prompt options. See {@link PromptOptions}.
  215. */
  216. prompt(message, opts) {
  217. if (!this.options.prompt) {
  218. throw new Error("prompt is not supported!");
  219. }
  220. return this.options.prompt(message, opts);
  221. }
  222. /**
  223. * Creates a new instance of Consola, inheriting options from the current instance, with possible overrides.
  224. *
  225. * @param {Partial<ConsolaOptions>} options - Optional overrides for the new instance. See {@link ConsolaOptions}.
  226. * @returns {ConsolaInstance} A new Consola instance. See {@link ConsolaInstance}.
  227. */
  228. create(options) {
  229. const instance = new Consola({
  230. ...this.options,
  231. ...options
  232. });
  233. if (this._mockFn) {
  234. instance.mockTypes(this._mockFn);
  235. }
  236. return instance;
  237. }
  238. /**
  239. * Creates a new Consola instance with the specified default log object properties.
  240. *
  241. * @param {InputLogObject} defaults - Default properties to include in any log from the new instance. See {@link InputLogObject}.
  242. * @returns {ConsolaInstance} A new Consola instance. See {@link ConsolaInstance}.
  243. */
  244. withDefaults(defaults) {
  245. return this.create({
  246. ...this.options,
  247. defaults: {
  248. ...this.options.defaults,
  249. ...defaults
  250. }
  251. });
  252. }
  253. /**
  254. * Creates a new Consola instance with a specified tag, which will be included in every log.
  255. *
  256. * @param {string} tag - The tag to include in each log of the new instance.
  257. * @returns {ConsolaInstance} A new Consola instance. See {@link ConsolaInstance}.
  258. */
  259. withTag(tag) {
  260. return this.withDefaults({
  261. tag: this.options.defaults.tag ? this.options.defaults.tag + ":" + tag : tag
  262. });
  263. }
  264. /**
  265. * Adds a custom reporter to the Consola instance.
  266. * Reporters will be called for each log message, depending on their implementation and log level.
  267. *
  268. * @param {ConsolaReporter} reporter - The reporter to add. See {@link ConsolaReporter}.
  269. * @returns {Consola} The current Consola instance.
  270. */
  271. addReporter(reporter) {
  272. this.options.reporters.push(reporter);
  273. return this;
  274. }
  275. /**
  276. * Removes a custom reporter from the Consola instance.
  277. * If no reporter is specified, all reporters will be removed.
  278. *
  279. * @param {ConsolaReporter} reporter - The reporter to remove. See {@link ConsolaReporter}.
  280. * @returns {Consola} The current Consola instance.
  281. */
  282. removeReporter(reporter) {
  283. if (reporter) {
  284. const i = this.options.reporters.indexOf(reporter);
  285. if (i !== -1) {
  286. return this.options.reporters.splice(i, 1);
  287. }
  288. } else {
  289. this.options.reporters.splice(0);
  290. }
  291. return this;
  292. }
  293. /**
  294. * Replaces all reporters of the Consola instance with the specified array of reporters.
  295. *
  296. * @param {ConsolaReporter[]} reporters - The new reporters to set. See {@link ConsolaReporter}.
  297. * @returns {Consola} The current Consola instance.
  298. */
  299. setReporters(reporters) {
  300. this.options.reporters = Array.isArray(reporters) ? reporters : [reporters];
  301. return this;
  302. }
  303. wrapAll() {
  304. this.wrapConsole();
  305. this.wrapStd();
  306. }
  307. restoreAll() {
  308. this.restoreConsole();
  309. this.restoreStd();
  310. }
  311. /**
  312. * Overrides console methods with Consola logging methods for consistent logging.
  313. */
  314. wrapConsole() {
  315. for (const type in this.options.types) {
  316. if (!console["__" + type]) {
  317. console["__" + type] = console[type];
  318. }
  319. console[type] = this[type].raw;
  320. }
  321. }
  322. /**
  323. * Restores the original console methods, removing Consola overrides.
  324. */
  325. restoreConsole() {
  326. for (const type in this.options.types) {
  327. if (console["__" + type]) {
  328. console[type] = console["__" + type];
  329. delete console["__" + type];
  330. }
  331. }
  332. }
  333. /**
  334. * Overrides standard output and error streams to redirect them through Consola.
  335. */
  336. wrapStd() {
  337. this._wrapStream(this.options.stdout, "log");
  338. this._wrapStream(this.options.stderr, "log");
  339. }
  340. _wrapStream(stream, type) {
  341. if (!stream) {
  342. return;
  343. }
  344. if (!stream.__write) {
  345. stream.__write = stream.write;
  346. }
  347. stream.write = (data) => {
  348. this[type].raw(String(data).trim());
  349. };
  350. }
  351. /**
  352. * Restores the original standard output and error streams, removing the Consola redirection.
  353. */
  354. restoreStd() {
  355. this._restoreStream(this.options.stdout);
  356. this._restoreStream(this.options.stderr);
  357. }
  358. _restoreStream(stream) {
  359. if (!stream) {
  360. return;
  361. }
  362. if (stream.__write) {
  363. stream.write = stream.__write;
  364. delete stream.__write;
  365. }
  366. }
  367. /**
  368. * Pauses logging, queues incoming logs until resumed.
  369. */
  370. pauseLogs() {
  371. paused = true;
  372. }
  373. /**
  374. * Resumes logging, processing any queued logs.
  375. */
  376. resumeLogs() {
  377. paused = false;
  378. const _queue = queue.splice(0);
  379. for (const item of _queue) {
  380. item[0]._logFn(item[1], item[2]);
  381. }
  382. }
  383. /**
  384. * Replaces logging methods with mocks if a mock function is provided.
  385. *
  386. * @param {ConsolaOptions["mockFn"]} mockFn - The function to use for mocking logging methods. See {@link ConsolaOptions["mockFn"]}.
  387. */
  388. mockTypes(mockFn) {
  389. const _mockFn = mockFn || this.options.mockFn;
  390. this._mockFn = _mockFn;
  391. if (typeof _mockFn !== "function") {
  392. return;
  393. }
  394. for (const type in this.options.types) {
  395. this[type] = _mockFn(type, this.options.types[type]) || this[type];
  396. this[type].raw = this[type];
  397. }
  398. }
  399. _wrapLogFn(defaults, isRaw) {
  400. return (...args) => {
  401. if (paused) {
  402. queue.push([this, defaults, args, isRaw]);
  403. return;
  404. }
  405. return this._logFn(defaults, args, isRaw);
  406. };
  407. }
  408. _logFn(defaults, args, isRaw) {
  409. if ((defaults.level || 0) > this.level) {
  410. return false;
  411. }
  412. const logObj = {
  413. date: /* @__PURE__ */ new Date(),
  414. args: [],
  415. ...defaults,
  416. level: _normalizeLogLevel(defaults.level, this.options.types)
  417. };
  418. if (!isRaw && args.length === 1 && isLogObj(args[0])) {
  419. Object.assign(logObj, args[0]);
  420. } else {
  421. logObj.args = [...args];
  422. }
  423. if (logObj.message) {
  424. logObj.args.unshift(logObj.message);
  425. delete logObj.message;
  426. }
  427. if (logObj.additional) {
  428. if (!Array.isArray(logObj.additional)) {
  429. logObj.additional = logObj.additional.split("\n");
  430. }
  431. logObj.args.push("\n" + logObj.additional.join("\n"));
  432. delete logObj.additional;
  433. }
  434. logObj.type = typeof logObj.type === "string" ? logObj.type.toLowerCase() : "log";
  435. logObj.tag = typeof logObj.tag === "string" ? logObj.tag : "";
  436. const resolveLog = (newLog = false) => {
  437. const repeated = (this._lastLog.count || 0) - this.options.throttleMin;
  438. if (this._lastLog.object && repeated > 0) {
  439. const args2 = [...this._lastLog.object.args];
  440. if (repeated > 1) {
  441. args2.push(`(repeated ${repeated} times)`);
  442. }
  443. this._log({ ...this._lastLog.object, args: args2 });
  444. this._lastLog.count = 1;
  445. }
  446. if (newLog) {
  447. this._lastLog.object = logObj;
  448. this._log(logObj);
  449. }
  450. };
  451. clearTimeout(this._lastLog.timeout);
  452. const diffTime = this._lastLog.time && logObj.date ? logObj.date.getTime() - this._lastLog.time.getTime() : 0;
  453. this._lastLog.time = logObj.date;
  454. if (diffTime < this.options.throttle) {
  455. try {
  456. const serializedLog = JSON.stringify([
  457. logObj.type,
  458. logObj.tag,
  459. logObj.args
  460. ]);
  461. const isSameLog = this._lastLog.serialized === serializedLog;
  462. this._lastLog.serialized = serializedLog;
  463. if (isSameLog) {
  464. this._lastLog.count = (this._lastLog.count || 0) + 1;
  465. if (this._lastLog.count > this.options.throttleMin) {
  466. this._lastLog.timeout = setTimeout(
  467. resolveLog,
  468. this.options.throttle
  469. );
  470. return;
  471. }
  472. }
  473. } catch {
  474. }
  475. }
  476. resolveLog(true);
  477. }
  478. _log(logObj) {
  479. for (const reporter of this.options.reporters) {
  480. reporter.log(logObj, {
  481. options: this.options
  482. });
  483. }
  484. }
  485. }
  486. function _normalizeLogLevel(input, types = {}, defaultLevel = 3) {
  487. if (input === void 0) {
  488. return defaultLevel;
  489. }
  490. if (typeof input === "number") {
  491. return input;
  492. }
  493. if (types[input] && types[input].level !== void 0) {
  494. return types[input].level;
  495. }
  496. return defaultLevel;
  497. }
  498. Consola.prototype.add = Consola.prototype.addReporter;
  499. Consola.prototype.remove = Consola.prototype.removeReporter;
  500. Consola.prototype.clear = Consola.prototype.removeReporter;
  501. Consola.prototype.withScope = Consola.prototype.withTag;
  502. Consola.prototype.mock = Consola.prototype.mockTypes;
  503. Consola.prototype.pause = Consola.prototype.pauseLogs;
  504. Consola.prototype.resume = Consola.prototype.resumeLogs;
  505. function createConsola(options = {}) {
  506. return new Consola(options);
  507. }
  508. exports.Consola = Consola;
  509. exports.LogLevels = LogLevels;
  510. exports.LogTypes = LogTypes;
  511. exports.createConsola = createConsola;