Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"@commitlint/cli": "^19.8.1",
"@commitlint/config-conventional": "^19.8.1",
"@hyperse/eslint-config-hyperse": "^1.4.5",
"@hyperse/ts-node": "^1.0.3",
"commitizen": "^4.3.1",
"cz-conventional-changelog": "^3.3.0",
"eslint": "^9.29.0",
Expand Down
7 changes: 4 additions & 3 deletions packages/logger-plugin-console/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@
"package.json"
],
"scripts": {
"console": "yarn node --import=@hyperse/ts-node/register ./tests/console.ts",
"build:client": "tsup --config ./tsup.config.ts",
"build": "rimraf dist && tsc -p ./tsconfig.build.json && yarn build:client && npm run minify",
"build": "rimraf dist && tsc -p ./tsconfig.build.json && yarn build:client",
"?build-release": "When https://github.com/atlassian/changesets/issues/432 has a solution we can remove this trick",
"build-release": "yarn build && rimraf ./_release && yarn pack && mkdir ./_release && tar zxvf ./package.tgz --directory ./_release && rm ./package.tgz",
"minify": "node ../../scripts/minify.mjs --dest=dist",
"clean": "rimraf --no-glob ./dist ./_release ./coverage ./tsconfig.tsbuildinfo",
"lint": "eslint .",
"test": "run-s test-unit",
Expand All @@ -44,7 +44,8 @@
"typecheck": "tsc --project ./tsconfig.json --noEmit"
},
"dependencies": {
"@hyperse/logger": "workspace:*"
"@hyperse/logger": "workspace:*",
"picocolors": "^1.1.1"
},
"devDependencies": {
"@hyperse/eslint-config-hyperse": "^1.4.5",
Expand Down
35 changes: 35 additions & 0 deletions packages/logger-plugin-console/src/constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { LogLevel } from '@hyperse/logger';
import type { Color } from './types/type-color.js';
import type { ConsoleOptions } from './types/type-options.js';

export const defaultLevelColor: Record<LogLevel, Color[]> = {
[LogLevel.Error]: ['red'],
[LogLevel.Warn]: ['yellow'],
[LogLevel.Info]: ['green'],
[LogLevel.Debug]: ['blue'],
[LogLevel.Verbose]: ['magenta'],
};

export const defaultPrefixColor: Color[] = ['bold', 'magenta'];
export const defaultLoggerNameColor: Color[] = ['bold', 'cyan'];
export const defaultPluginNameColor: Color[] = ['bold', 'cyan'];

export const defaultConfig: Required<ConsoleOptions> = {
disable: false,
showTimestamp: true,
showLoggerName: false,
capitalizeLoggerName: false,
showPluginName: false,
capitalizePluginName: false,
showPrefix: true,
showLevelName: true,
capitalizeLevelName: true,
showDate: false,
use24HourClock: true,
showArrow: false,
noColor: false,
levelColor: defaultLevelColor,
prefixColor: defaultPrefixColor,
loggerNameColor: defaultLoggerNameColor,
pluginNameColor: defaultPluginNameColor,
};
45 changes: 45 additions & 0 deletions packages/logger-plugin-console/src/create-console-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { definePlugin } from '@hyperse/logger';
import { assertMessage } from './helpers/helper-assert-message.js';
import { formatMessage } from './helpers/helper-format-message.js';
import { isLoggable } from './helpers/helper-is-loggable.js';
import { mergeConsoleOptions } from './helpers/helper-merge-optons.js';
import type { ConsoleOptions } from './types/type-options.js';
import type {
ConsolePluginContext,
ConsolePluginMessage,
} from './types/type-plugin.js';

export const createConsolePlugin = (options?: ConsoleOptions) => {
const newOptions = mergeConsoleOptions(options);
return definePlugin<ConsolePluginContext, ConsolePluginMessage | string>({
pluginName: 'hps-logger-plugin-console',
execute: async ({ ctx, level, message, pipe, exitPipe }) => {
await pipe(
() => {
const { disable } = newOptions;
if (disable || !isLoggable(ctx, level)) {
return exitPipe('level is too low');
}
return {
inputMessage: assertMessage(message),
};
},
({ inputMessage }) => {
const formatOptions = {
ctx,
level,
inputMessage,
options: newOptions,
};
const outputMessage = formatMessage(formatOptions);
return {
outputMessage,
};
},
({ outputMessage }) => {
console.log(outputMessage);
}
)();
},
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { LoggerMessageObject } from '@hyperse/logger';

export const assertMessage = <T extends LoggerMessageObject>(
message: T | string
): T => {
if (typeof message === 'string') {
const newMessage = {
message: message,
name: undefined,
stack: undefined,
};
return newMessage as T;
}
return message;
};
37 changes: 37 additions & 0 deletions packages/logger-plugin-console/src/helpers/helper-color-applier.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Picocolors from 'picocolors';
import type { Color } from '../types/type-color.js';

/**
* Terminal output formatting with ANSI colors
* @param colors The colors for the console output
* @param noColor Removes colors from the console output
* @returns
*/
export function terminalColor(colors: readonly Color[], noColor?: boolean) {
if (noColor || !colors.length) {
// Pure text output.
return (x: string) => x;
}
return (x: string) => {
let out: string = x;
for (let i = 0; i < colors.length; i++) {
out = Picocolors[colors[i]](out);
}
return out;
};
}

export const getColorApplier = (
colorType: 'COLOR' | 'DECORATION',
levelColors: readonly Color[],
noColor: boolean
) => {
const colors = levelColors.filter((colorName) => {
const isDecoration =
colorName === 'strikethrough' || colorName === 'underline';

return colorType === 'DECORATION' ? isDecoration : !isDecoration;
});

return terminalColor(colors, noColor);
};
145 changes: 145 additions & 0 deletions packages/logger-plugin-console/src/helpers/helper-format-message.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import type { LoggerPluginContext, LogLevel } from '@hyperse/logger';
import type { ConsoleOptions } from '../types/type-options.js';
import type {
ConsolePluginContext,
ConsolePluginMessage,
} from '../types/type-plugin.js';
import { getColorApplier, terminalColor } from './helper-color-applier.js';
import { formatStack } from './helper-format-stack.js';
import { normalizeLevelData } from './helper-normalize-level.js';
import { strTimePad } from './helper-str-pad.js';

export const formatMessage = (formatOptions: {
ctx: LoggerPluginContext<ConsolePluginContext>;
level: LogLevel;
inputMessage: ConsolePluginMessage;
options: Required<ConsoleOptions>;
}) => {
const { ctx, level, inputMessage, options } = formatOptions;
const { name: loggerName, pluginName } = ctx;
const { message, name: messageName, stack, prefix } = inputMessage;
const {
showLoggerName,
capitalizeLoggerName,
showPluginName,
capitalizePluginName,
showPrefix,
showLevelName,
capitalizeLevelName,
showDate,
showTimestamp,
use24HourClock,
showArrow,
noColor,
prefixColor,
loggerNameColor,
pluginNameColor,
} = options;

const time = new Date();
let output = '';
const levelData = normalizeLevelData(level, options);

const color = getColorApplier('COLOR', levelData.color, noColor);
const decorate = getColorApplier('DECORATION', levelData.color, noColor);
const context: string[] = [];

// date and timestamp
if (showDate || showTimestamp) {
output += '[';
if (showDate) {
output += color(
' ' +
decorate(
`${time.getFullYear()}-${time.getMonth() + 1}-${time.getDate()}`
) +
' '
);
}

if (showDate && showTimestamp) {
output += '|';
}

if (showTimestamp) {
const hours = time.getHours();

output += color(
' ' +
decorate(
`${strTimePad(
use24HourClock || !(hours >= 13 || hours === 0)
? hours
: Math.abs(hours - 12)
)}:${strTimePad(time.getMinutes())}:${strTimePad(time.getSeconds())}`
) +
' ' +
(use24HourClock ? '' : decorate(hours >= 13 ? 'PM' : 'AM') + ' ')
);
}

output += '] ';
}

// level name
if (showLevelName) {
output +=
'[ ' +
color(
capitalizeLevelName ? levelData.name.toUpperCase() : levelData.name
) +
' ] ';
}

// prefix
if (showPrefix && prefix) {
const ctxColor = getColorApplier('COLOR', prefixColor, noColor);
context.push(' ' + ctxColor(prefix.toUpperCase()) + ' ');
}

// logger name
if (showLoggerName && loggerName) {
const ctxColor = getColorApplier('COLOR', loggerNameColor, noColor);
context.push(
' ' +
ctxColor(capitalizeLoggerName ? loggerName.toUpperCase() : loggerName) +
' '
);
}

// plugin name
if (showPluginName && pluginName) {
const ctxColor = getColorApplier('COLOR', pluginNameColor, noColor);
context.push(
' ' +
ctxColor(capitalizePluginName ? pluginName.toUpperCase() : pluginName) +
' '
);
}

// level context
if (context.length) {
output += '[' + context.join(':') + '] ';
}

// arrow
if (showArrow) {
output += ` ${terminalColor(['bold'])('>>')} `;
}

// message name
if (messageName) {
output += `${messageName} `;
}

// message
if (message) {
output += `${message} `;
}

// stack
if (stack) {
output += `${formatStack(stack)}`;
}
return output;
};
18 changes: 18 additions & 0 deletions packages/logger-plugin-console/src/helpers/helper-format-stack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { terminalColor } from './helper-color-applier.js';

function parseStack(stack: string) {
if (!stack || typeof stack !== 'string') {
return [];
}
const lines = stack
.split('\n')
.splice(1)
.map((l) => l.trim().replace('file://', ''));

return lines;
}

export const formatStack = (stack: string) =>
`\n${parseStack(stack)
.map((line) => ` ${terminalColor(['red'])(line)}`)
.join('\n')}`;
Loading