Skip to content

Commit

Permalink
fix(env): ignore empty string on env fallback
Browse files Browse the repository at this point in the history
BREAKING CHANGE: getEnv functions will ignore empty strings.
  • Loading branch information
ASafaeirad committed Nov 9, 2022
1 parent ddd0e69 commit 7817b57
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 19 deletions.
29 changes: 29 additions & 0 deletions src/env.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
Expand All @@ -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';
Expand Down Expand Up @@ -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';
Expand Down
28 changes: 11 additions & 17 deletions src/env.ts
Original file line number Diff line number Diff line change
@@ -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<TKey extends string = string>(
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;
}

/**
Expand All @@ -29,12 +26,9 @@ export const getNodeEnv = <T extends string = never>(
/**
* returns NODE_ENV value or given fallback otherwise throws
*/
export const getRequiredEnv = <
TKey extends string = string,
TValue extends string = string,
>(
export const getRequiredEnv = <TKey extends string = string>(
envKey: TKey,
): TValue => required(getEnv(envKey) as TValue, envKey);
): string => required(getEnv(envKey, null), envKey);

/**
* parse environment to a boolean or throw error
Expand All @@ -45,7 +39,7 @@ export function getBooleanEnv<TKey extends string = string>(
defaultValue?: boolean,
): boolean | undefined {
const value = getEnv(key);
if (isNull(value)) return defaultValue;
if (isNullOrEmpty(value)) return defaultValue;

try {
const boolean = JSON.parse(value);
Expand Down
7 changes: 5 additions & 2 deletions src/values.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import { isNull } from './guards.js';
import { isNullOrEmpty } from './string.js';
import type { Nullish } from './types.js';

export const required = <T>(value: Nullish | T, name: string = 'value'): T => {
export const required = <T>(
value: Nullish | T,
name: string = 'value',
): NonNullable<T> => {
if (isNull(value)) throw Error(`${name} is required`);
return value;
return value as NonNullable<T>;
};

export const fallback = <T, U = T>(value: T, defaultValue: U): T | U =>
Expand Down

0 comments on commit 7817b57

Please sign in to comment.