From 00cf26902c7d6e47ae4cc958f4590d11be4f31c3 Mon Sep 17 00:00:00 2001 From: Rasmus Gustafsson Date: Fri, 26 Jul 2024 05:16:37 +0300 Subject: [PATCH] feat: add support for adding and overriding logs --- src/formatters.ts | 15 +++---- src/index.ts | 42 ++++++++++++++----- test/logs.test.ts | 72 +++++++++++++++++++++++++++++--- test/{setup.ts => test-mocks.ts} | 2 +- test/types.test.ts | 4 +- 5 files changed, 108 insertions(+), 27 deletions(-) rename test/{setup.ts => test-mocks.ts} (94%) diff --git a/src/formatters.ts b/src/formatters.ts index 356689e..897689c 100644 --- a/src/formatters.ts +++ b/src/formatters.ts @@ -9,13 +9,14 @@ export const textFormatter: Formatter = (logParts) => { const logMessageParts = [ capitalize(events.map(({ message }) => message).join(' and ')), - ' because ', + events.length > 0 && ' because ', explanations.map(({ message }) => message).join(' and '), - '.', - '\n', - '\n', - 'Possible solutions:\n', - solutions.map(({ message }, solutionIndex) => `${solutionIndex + 1}) ${message}`) + explanations.length > 0 && '.', + solutions.length > 0 && explanations.length > 0 && '\n', + solutions.length > 0 && explanations.length > 0 && '\n', + solutions.length > 0 && 'Possible solutions:\n', + solutions.length > 0 && + solutions.map(({ message }, solutionIndex) => `${solutionIndex + 1}) ${message}`).join('\n') ] - return logMessageParts.join('') + return logMessageParts.filter(Boolean).join('') } diff --git a/src/index.ts b/src/index.ts index 3b100ff..7885c66 100644 --- a/src/index.ts +++ b/src/index.ts @@ -95,24 +95,44 @@ export function createHumanLogs( // ...[params]: CombineParams extends never ? [] : [CombineParams] params: CombineParams ) { - const matchingParts = logs.filter(({ name }) => logParts.includes(name)) + let localLogParts = [...logParts] + let localParams: CombineParams = { + ...params + } - // Then template all of the parts - const templatedParts = matchingParts.map((part) => { - return { - ...part, - params: params as LogObject['params'], - message: replaceTemplateParams(part.message, params as LogObject['params']) - } - }) + const getTemplatedParts = () => + logs + .filter(({ name }) => localLogParts.includes(name)) + .map((part) => ({ + ...part, + // params: params as LogObject['params'], + params: localParams, + message: replaceTemplateParams(part.message, localParams) + })) return { get parts() { - return templatedParts + return getTemplatedParts() + }, + add>( + logParts: AddLogNames, + params: CombineParams + ) { + localLogParts.push(...logParts) + localParams = { ...localParams, ...params } + return this + }, + override>( + logParts: AddLogNames, + params: CombineParams + ) { + localLogParts = logParts + localParams = { ...localParams, ...params } + return this }, toString() { const formatter = options.formatter ?? textFormatter - return formatter(templatedParts) + return formatter(getTemplatedParts()) } } } diff --git a/test/logs.test.ts b/test/logs.test.ts index dc790ad..6198f01 100644 --- a/test/logs.test.ts +++ b/test/logs.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { mockErrors } from './setup' +import { mockErrors } from './test-mocks' describe('formatters', () => { it('default formatter', () => { @@ -22,10 +22,70 @@ describe('formatters', () => { }) }) -describe.skip('chaining', () => { - const error = mockErrors(['fetch_posts_failed', 'missing_params', 'provide_fallback'], { - paramName: 'image', - paramType: 'Image', - postId: 'abcd-123' +describe('chaining', () => { + it('add > no params', () => { + const error = mockErrors(['fetch_posts_failed', 'missing_params', 'provide_fallback'], { + paramName: 'image', + paramType: 'Image', + postId: 'abcd-123' + }).add(['check_statuspage'], {}) + + expect(error.toString()).toBe( + [ + 'Fetching posts failed because the Image `image` is missing for post with ID `abcd-123`, and no fallback was provided.', + '', + 'Possible solutions:', + '1) add a fallback to your parameter definition like this: ', + '', + 'url(`image`, { fallback: `https://useflytrap.com` })', + '2) you can check the status of our services on our status page' + ].join('\n') + ) + }) + + it('add > with params', () => { + const error = mockErrors(['fetch_posts_failed', 'missing_params', 'provide_fallback'], { + paramName: 'image', + paramType: 'Image', + postId: 'abcd-123' + }).add(['unsupported_blocktype'], { + blockType: 'Video' + }) + + expect(error.toString()).toBe( + [ + 'Fetching posts failed because the Image `image` is missing for post with ID `abcd-123`, and no fallback was provided and unsupported block type `Video` is included on this page.', + '', + 'Possible solutions:', + '1) add a fallback to your parameter definition like this: ', + '', + 'url(`image`, { fallback: `https://useflytrap.com` })' + ].join('\n') + ) + }) + + it('override > no params', () => { + const error = mockErrors(['fetch_posts_failed', 'missing_params', 'provide_fallback'], { + paramName: 'image', + paramType: 'Image', + postId: 'abcd-123' + }).override(['check_statuspage'], {}) + + expect(error.toString()).toBe( + [ + 'Possible solutions:', + '1) you can check the status of our services on our status page' + ].join('\n') + ) + }) + + it('override > with params', () => { + const error = mockErrors(['check_statuspage'], {}).override(['unsupported_blocktype'], { + blockType: 'Image' + }) + + expect(error.toString()).toBe( + ['unsupported block type `Image` is included on this page.'].join('\n') + ) }) }) diff --git a/test/setup.ts b/test/test-mocks.ts similarity index 94% rename from test/setup.ts rename to test/test-mocks.ts index d7ef7b5..6f980f7 100644 --- a/test/setup.ts +++ b/test/test-mocks.ts @@ -23,7 +23,7 @@ export const mockErrors = createHumanLogs([ ), explanation( 'unsupported_blocktype', - 'unsupported block type `{blockType} is included on this page.`', + 'unsupported block type `{blockType}` is included on this page', { params: { blockType: '' } } diff --git a/test/types.test.ts b/test/types.test.ts index 8b4fb26..109a4d2 100644 --- a/test/types.test.ts +++ b/test/types.test.ts @@ -1,5 +1,5 @@ -import { describe, expectTypeOf, it } from 'vitest' -import { mockErrors } from './setup' +import { describe, it } from 'vitest' +import { mockErrors } from './test-mocks' describe('basic type tests', () => { it('only valid keys', () => {