From 6b35db8535a159039cd2d0dca603f8351b0a9ae7 Mon Sep 17 00:00:00 2001 From: Max Altena Date: Thu, 20 Jun 2024 10:10:02 +0200 Subject: [PATCH] feat: :sparkles: Introduce loglevel to makeEnvPublic --- src/helpers/log.spec.ts | 14 +++++++++ src/helpers/log.ts | 49 ++++++++++++++++++++++++------- src/utils/make-env-public.spec.ts | 16 ++++++++++ src/utils/make-env-public.ts | 26 +++++++++++----- 4 files changed, 88 insertions(+), 17 deletions(-) diff --git a/src/helpers/log.spec.ts b/src/helpers/log.spec.ts index 3b271f36..a5be6f76 100644 --- a/src/helpers/log.spec.ts +++ b/src/helpers/log.spec.ts @@ -16,6 +16,20 @@ afterAll(() => { errorSpy.mockRestore(); }); +describe('silent', () => { + it('should not log an event message', () => { + error('foo', { logLevel: 'silent' }); + + expect(errorSpy).not.toHaveBeenCalled(); + }); + + it('should respect log level', () => { + event('foo', { logLevel: 'warn' }); + + expect(logSpy).not.toHaveBeenCalled(); + }); +}); + describe('error', () => { it('should log an error message', () => { error('foo'); diff --git a/src/helpers/log.ts b/src/helpers/log.ts index 05eaa3de..51abe8e0 100644 --- a/src/helpers/log.ts +++ b/src/helpers/log.ts @@ -1,11 +1,30 @@ import { bold, green, red, white, yellow } from '../lib/picocolors'; +export type Level = 'error' | 'warn' | 'info'; +export type LevelWithSilent = 'silent' | Level; + +export interface LogOptions { + /** + * Level of logging + * @default 'event' + */ + logLevel?: LevelWithSilent; +} + export const prefixes = { error: red(bold('⨯')), warn: yellow(bold('⚠')), info: white(bold(' ')), event: green(bold('✓')), -} as const; +} as const satisfies Record; + +export const prefixLevels = { + silent: Infinity, + error: 40, + warn: 30, + info: 20, + event: 10, +} as const satisfies Record; const suffix = '(next-runtime-env)'; @@ -15,7 +34,17 @@ const LOGGING_METHOD = { error: 'error', } as const; -function prefixedLog(prefixType: keyof typeof prefixes, message: string) { +function prefixedLog( + prefixType: keyof typeof prefixes, + message: string, + options?: LogOptions, +) { + const { logLevel = 'event' } = options || {}; + + if (prefixLevels[prefixType] < prefixLevels[logLevel]) { + return; + } + const consoleMethod: keyof typeof LOGGING_METHOD = prefixType in LOGGING_METHOD ? LOGGING_METHOD[prefixType as keyof typeof LOGGING_METHOD] @@ -27,18 +56,18 @@ function prefixedLog(prefixType: keyof typeof prefixes, message: string) { console[consoleMethod](` ${prefix}`, message, suffix); } -export function error(message: string) { - prefixedLog('error', message); +export function error(message: string, options?: LogOptions) { + prefixedLog('error', message, options); } -export function warn(message: string) { - prefixedLog('warn', message); +export function warn(message: string, options?: LogOptions) { + prefixedLog('warn', message, options); } -export function info(message: string) { - prefixedLog('info', message); +export function info(message: string, options?: LogOptions) { + prefixedLog('info', message, options); } -export function event(message: string) { - prefixedLog('event', message); +export function event(message: string, options?: LogOptions) { + prefixedLog('event', message, options); } diff --git a/src/utils/make-env-public.spec.ts b/src/utils/make-env-public.spec.ts index 423ffdab..03931e29 100644 --- a/src/utils/make-env-public.spec.ts +++ b/src/utils/make-env-public.spec.ts @@ -56,14 +56,17 @@ describe('makeEnvPublic()', () => { expect(eventMock).toHaveBeenCalledWith( `Prefixed environment variable 'FOO'`, + undefined, ); expect(eventMock).toHaveBeenCalledWith( `Prefixed environment variable 'BAR'`, + undefined, ); expect(eventMock).toHaveBeenCalledWith( `Prefixed environment variable 'BAZ'`, + undefined, ); }); @@ -72,6 +75,7 @@ describe('makeEnvPublic()', () => { expect(warnMock).toHaveBeenCalledWith( `Skipped prefixing environment variable 'FOO'. Variable not in process.env`, + undefined, ); }); @@ -82,6 +86,18 @@ describe('makeEnvPublic()', () => { expect(warnMock).toHaveBeenCalledWith( `Environment variable 'NEXT_PUBLIC_FOO' is already public`, + undefined, + ); + }); + + it('should not log anything when logLevel is set to silent', () => { + process.env.FOO = 'foo'; + + makeEnvPublic('FOO', { logLevel: 'silent' }); + + expect(eventMock).toHaveBeenCalledWith( + `Prefixed environment variable 'FOO'`, + { logLevel: 'silent' }, ); }); }); diff --git a/src/utils/make-env-public.ts b/src/utils/make-env-public.ts index 455a5cae..c93356e5 100644 --- a/src/utils/make-env-public.ts +++ b/src/utils/make-env-public.ts @@ -1,10 +1,13 @@ -import { event, warn } from '../helpers/log'; +import { event, LogOptions, warn } from '../helpers/log'; -function prefixKey(key: string) { +export interface MakeEnvPublicOptions extends LogOptions {} + +function prefixKey(key: string, options?: MakeEnvPublicOptions) { // Check if key is available in process.env. if (!process.env[key]) { warn( `Skipped prefixing environment variable '${key}'. Variable not in process.env`, + options, ); return; @@ -12,7 +15,7 @@ function prefixKey(key: string) { // Check if key is already public. if (/^NEXT_PUBLIC_/i.test(key)) { - warn(`Environment variable '${key}' is already public`); + warn(`Environment variable '${key}' is already public`, options); } const prefixedKey = `NEXT_PUBLIC_${key}`; @@ -20,7 +23,7 @@ function prefixKey(key: string) { process.env[prefixedKey] = process.env[key]; // eslint-disable-next-line no-console - event(`Prefixed environment variable '${key}'`); + event(`Prefixed environment variable '${key}'`, options); } /** @@ -34,12 +37,21 @@ function prefixKey(key: string) { * * // Make multiple variables public. * makeEnvPublic(['FOO', 'BAR', 'BAZ']); + * + * // Disable logging. + * makeEnvPublic('FOO', { logLevel: 'silent' }); + * + * // Disable logging in production + * makeEnvPublic('FOO', { logLevel: process.env.NODE_ENV === 'production' ? 'silent': 'info' }); * ``` */ -export function makeEnvPublic(key: string | string[]): void { +export function makeEnvPublic( + key: string | string[], + options?: MakeEnvPublicOptions, +): void { if (typeof key === 'string') { - prefixKey(key); + prefixKey(key, options); } else { - key.forEach(prefixKey); + key.forEach((value) => prefixKey(value, options)); } }