diff --git a/src/env.spec.ts b/src/env.spec.ts index c28403d5..92f09141 100644 --- a/src/env.spec.ts +++ b/src/env.spec.ts @@ -38,6 +38,14 @@ describe('env', () => { expect(getEnv(key, fallback)).toBe(fallback); }); + it('should fallback to given fallback if value is empty string', () => { + const key = 'key'; + const fallback = 'fallback'; + process.env[key] = ''; + + expect(getEnv(key, fallback)).toBe(fallback); + }); + it('should undefined when env does not exist', () => { expect(getBooleanEnv('not-existed')).toBe(undefined); }); @@ -62,6 +70,20 @@ describe('env', () => { expect(getBooleanEnv('not-existed', fallback)).toBe(fallback); }); + it('should fallback to given fallback', () => { + const fallback = false; + + expect(getBooleanEnv('not-existed', fallback)).toBe(fallback); + }); + + it('should fallback to given fallback if env is empty string', () => { + const fallback = false; + const key = 'key'; + process.env[key] = ''; + + expect(getBooleanEnv(key, fallback)).toBe(fallback); + }); + it('should throw error if env is not a json', () => { const key = 'key'; process.env[key] = 'NOT-JSON'; @@ -105,6 +127,13 @@ describe('env', () => { expect(() => getRequiredEnv(key)).toThrowError(); }); + it('should throw if env empty string', () => { + const key = 'key'; + process.env[key] = ''; + + expect(() => getRequiredEnv(key)).toThrowError(); + }); + it('should return value if present', () => { const key = 'key'; const value = 'value'; diff --git a/src/env.ts b/src/env.ts index 420fd6c5..076de517 100644 --- a/src/env.ts +++ b/src/env.ts @@ -1,22 +1,19 @@ -import { isBoolean, isNull } from './guards.js'; +import { isBoolean } from './guards.js'; +import { isNullOrEmpty } from './string.js'; import type { NodeEnv } from './types.js'; -import { fallback, required } from './values.js'; +import { required } from './values.js'; + +export type EnvKey = 'NODE_ENV'; /** * give NODE_ENV value or given fallback value */ -export function getEnv( - key: TKey, -): string | undefined; export function getEnv< TKey extends string = string, - TValue extends string | undefined = string, ->(key: TKey, defaultValue: TValue): TValue; -export function getEnv< - TKey extends string = string, - TValue extends string | undefined = string, + TValue extends string | null | undefined = string, >(key: TKey, defaultValue?: TValue): TValue | undefined { - return fallback(process.env[key] as TValue, defaultValue); + const value = process.env[key] as TValue; + return isNullOrEmpty(value) ? defaultValue : value; } /** @@ -29,12 +26,9 @@ export const getNodeEnv = ( /** * returns NODE_ENV value or given fallback otherwise throws */ -export const getRequiredEnv = < - TKey extends string = string, - TValue extends string = string, ->( +export const getRequiredEnv = ( envKey: TKey, -): TValue => required(getEnv(envKey) as TValue, envKey); +): string => required(getEnv(envKey, null), envKey); /** * parse environment to a boolean or throw error @@ -45,7 +39,7 @@ export function getBooleanEnv( defaultValue?: boolean, ): boolean | undefined { const value = getEnv(key); - if (isNull(value)) return defaultValue; + if (isNullOrEmpty(value)) return defaultValue; try { const boolean = JSON.parse(value); diff --git a/src/values.ts b/src/values.ts index 1c6b6a76..8b9ca202 100644 --- a/src/values.ts +++ b/src/values.ts @@ -2,9 +2,12 @@ import { isNull } from './guards.js'; import { isNullOrEmpty } from './string.js'; import type { Nullish } from './types.js'; -export const required = (value: Nullish | T, name: string = 'value'): T => { +export const required = ( + value: Nullish | T, + name: string = 'value', +): NonNullable => { if (isNull(value)) throw Error(`${name} is required`); - return value; + return value as NonNullable; }; export const fallback = (value: T, defaultValue: U): T | U =>