| | import { dim } from '../../lib/picocolors' |
| | import { |
| | consoleAsyncStorage, |
| | type ConsoleStore, |
| | } from '../app-render/console-async-storage.external' |
| | import { workUnitAsyncStorage } from '../app-render/work-unit-async-storage.external' |
| | import { getServerReact, getClientReact } from '../runtime-reacts.external' |
| |
|
| | |
| | const DIMMED_STYLE = 'dimmed' |
| | const HIDDEN_STYLE = 'hidden' |
| |
|
| | type LogStyle = typeof DIMMED_STYLE | typeof HIDDEN_STYLE |
| |
|
| | let currentAbortedLogsStyle: LogStyle = 'dimmed' |
| | export function setAbortedLogsStyle(style: LogStyle) { |
| | currentAbortedLogsStyle = style |
| | } |
| |
|
| | type InterceptableConsoleMethod = |
| | | 'error' |
| | | 'assert' |
| | | 'debug' |
| | | 'dir' |
| | | 'dirxml' |
| | | 'group' |
| | | 'groupCollapsed' |
| | | 'groupEnd' |
| | | 'info' |
| | | 'log' |
| | | 'table' |
| | | 'trace' |
| | | 'warn' |
| |
|
| | const isColorSupported = dim('test') !== 'test' |
| |
|
| | |
| | const dimStyle = 'color: color(from currentColor xyz x y z / 0.5);' |
| | const reactBadgeFormat = '\x1b[0m\x1b[7m%c%s\x1b[0m%c ' |
| |
|
| | function dimmedConsoleArgs(...inputArgs: any[]): any[] { |
| | if (!isColorSupported) { |
| | return inputArgs |
| | } |
| |
|
| | const newArgs = inputArgs.slice(0) |
| | let template = '' |
| | let argumentsPointer = 0 |
| | if (typeof inputArgs[0] === 'string') { |
| | const originalTemplateString = inputArgs[0] |
| | |
| | newArgs.splice(argumentsPointer, 1) |
| | argumentsPointer += 1 |
| |
|
| | let i = 0 |
| | if (originalTemplateString.startsWith(reactBadgeFormat)) { |
| | i = reactBadgeFormat.length |
| | |
| | |
| | argumentsPointer += 3 |
| | template += reactBadgeFormat |
| | |
| | template += '\x1b[2m%c' |
| | |
| | newArgs.splice(argumentsPointer - 1, 0, dimStyle) |
| | |
| | newArgs[0] += `;${dimStyle}` |
| | } |
| |
|
| | for (i; i < originalTemplateString.length; i++) { |
| | const currentChar = originalTemplateString[i] |
| | if (currentChar !== '%') { |
| | template += currentChar |
| | continue |
| | } |
| |
|
| | const nextChar = originalTemplateString[i + 1] |
| | ++i |
| |
|
| | switch (nextChar) { |
| | case 'f': |
| | case 'O': |
| | case 'o': |
| | case 'd': |
| | case 's': |
| | case 'i': |
| | case 'c': |
| | ++argumentsPointer |
| | template += `%${nextChar}` |
| | break |
| | default: |
| | template += `%${nextChar}` |
| | } |
| | } |
| | } |
| |
|
| | for ( |
| | argumentsPointer; |
| | argumentsPointer < inputArgs.length; |
| | ++argumentsPointer |
| | ) { |
| | const arg = inputArgs[argumentsPointer] |
| | const argType = typeof arg |
| | if (argumentsPointer > 0) { |
| | template += ' ' |
| | } |
| | switch (argType) { |
| | case 'boolean': |
| | case 'string': |
| | template += '%s' |
| | break |
| | case 'bigint': |
| | template += '%s' |
| | break |
| | case 'number': |
| | if (arg % 0) { |
| | template += '%f' |
| | } else { |
| | template += '%d' |
| | } |
| | break |
| | case 'object': |
| | template += '%O' |
| | break |
| | case 'symbol': |
| | case 'undefined': |
| | case 'function': |
| | template += '%s' |
| | break |
| | default: |
| | |
| | template += '%s' |
| | } |
| | } |
| |
|
| | template += '\x1b[22m' |
| |
|
| | return [dim(`%c${template}`), dimStyle, ...newArgs] |
| | } |
| |
|
| | function convertToDimmedArgs( |
| | methodName: InterceptableConsoleMethod, |
| | args: any[] |
| | ): any[] { |
| | switch (methodName) { |
| | case 'dir': |
| | case 'dirxml': |
| | case 'group': |
| | case 'groupCollapsed': |
| | case 'groupEnd': |
| | case 'table': { |
| | |
| | return args |
| | } |
| | case 'assert': { |
| | |
| | return [args[0]].concat(...dimmedConsoleArgs(args[1], ...args.slice(2))) |
| | } |
| | case 'error': |
| | case 'debug': |
| | case 'info': |
| | case 'log': |
| | case 'trace': |
| | case 'warn': |
| | return dimmedConsoleArgs(args[0], ...args.slice(1)) |
| | default: |
| | return methodName satisfies never |
| | } |
| | } |
| |
|
| | |
| | function patchConsoleMethod(methodName: InterceptableConsoleMethod): void { |
| | const descriptor = Object.getOwnPropertyDescriptor(console, methodName) |
| | if ( |
| | descriptor && |
| | (descriptor.configurable || descriptor.writable) && |
| | typeof descriptor.value === 'function' |
| | ) { |
| | const originalMethod = descriptor.value |
| | const originalName = Object.getOwnPropertyDescriptor(originalMethod, 'name') |
| | const wrapperMethod = function (this: typeof console, ...args: any[]) { |
| | const consoleStore = consoleAsyncStorage.getStore() |
| |
|
| | |
| | |
| | |
| | |
| | |
| | const signal = |
| | getClientReact()?.cacheSignal() ?? getServerReact()?.cacheSignal() |
| | if (signal) { |
| | |
| | |
| | if (signal.aborted) { |
| | if (currentAbortedLogsStyle === HIDDEN_STYLE) { |
| | return |
| | } |
| | return applyWithDimming.call( |
| | this, |
| | consoleStore, |
| | originalMethod, |
| | methodName, |
| | args |
| | ) |
| | } else if (consoleStore?.dim === true) { |
| | return applyWithDimming.call( |
| | this, |
| | consoleStore, |
| | originalMethod, |
| | methodName, |
| | args |
| | ) |
| | } else { |
| | return originalMethod.apply(this, args) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | const workUnitStore = workUnitAsyncStorage.getStore() |
| | switch (workUnitStore?.type) { |
| | case 'prerender': |
| | case 'prerender-runtime': |
| | |
| | |
| | |
| | case 'prerender-client': |
| | |
| | const renderSignal = workUnitStore.renderSignal |
| | if (renderSignal.aborted) { |
| | if (currentAbortedLogsStyle === HIDDEN_STYLE) { |
| | return |
| | } |
| | return applyWithDimming.call( |
| | this, |
| | consoleStore, |
| | originalMethod, |
| | methodName, |
| | args |
| | ) |
| | } |
| | |
| | case 'prerender-legacy': |
| | case 'prerender-ppr': |
| | case 'cache': |
| | case 'unstable-cache': |
| | case 'private-cache': |
| | case 'request': |
| | case undefined: |
| | if (consoleStore?.dim === true) { |
| | return applyWithDimming.call( |
| | this, |
| | consoleStore, |
| | originalMethod, |
| | methodName, |
| | args |
| | ) |
| | } else { |
| | return originalMethod.apply(this, args) |
| | } |
| | default: |
| | workUnitStore satisfies never |
| | } |
| | } |
| | if (originalName) { |
| | Object.defineProperty(wrapperMethod, 'name', originalName) |
| | } |
| | Object.defineProperty(console, methodName, { |
| | value: wrapperMethod, |
| | }) |
| | } |
| | } |
| |
|
| | function applyWithDimming<F extends (this: Console, ...args: any[]) => any>( |
| | this: Console, |
| | consoleStore: undefined | ConsoleStore, |
| | method: F, |
| | methodName: InterceptableConsoleMethod, |
| | args: Parameters<F> |
| | ): ReturnType<F> { |
| | if (consoleStore?.dim === true) { |
| | return method.apply(this, convertToDimmedArgs(methodName, args)) |
| | } else { |
| | return consoleAsyncStorage.run( |
| | DIMMED_STORE, |
| | method.bind(this, ...convertToDimmedArgs(methodName, args)) |
| | ) |
| | } |
| | } |
| |
|
| | const DIMMED_STORE = { dim: true } |
| |
|
| | patchConsoleMethod('error') |
| | patchConsoleMethod('assert') |
| | patchConsoleMethod('debug') |
| | patchConsoleMethod('dir') |
| | patchConsoleMethod('dirxml') |
| | patchConsoleMethod('group') |
| | patchConsoleMethod('groupCollapsed') |
| | patchConsoleMethod('groupEnd') |
| | patchConsoleMethod('info') |
| | patchConsoleMethod('log') |
| | patchConsoleMethod('table') |
| | patchConsoleMethod('trace') |
| | patchConsoleMethod('warn') |
| |
|