diff --git a/src/string.test.ts b/src/string.test.ts index 790147a..850a0d5 100644 --- a/src/string.test.ts +++ b/src/string.test.ts @@ -1,5 +1,5 @@ import { NotDefinedConfigError, ListValueConfigError } from './error'; -import { getString } from './string'; +import { getString, getStringArray } from './string'; describe('getString', () => { let env: Record; @@ -99,3 +99,110 @@ describe('getString', () => { }); }); }); + +describe('getStringArray', () => { + let env: Record; + beforeEach(() => { + env = Object.assign({}, process.env); + }); + Object.assign({}, process.env); + afterEach(() => { + process.env = env; + }); + describe('environment variable is set', () => { + it('returns the environment variable as an array of strings', () => { + process.env.TEST_STRING_ARRAY = 'foo,bar,baz'; + const value = getStringArray('TEST_STRING_ARRAY'); + expect(value).toEqual(['foo', 'bar', 'baz']); + }); + describe('allow undefined', () => { + it('returns the environment variable as an array of strings', () => { + process.env.TEST_STRING_ARRAY = 'foo,bar,baz'; + const value = getStringArray('TEST_STRING_ARRAY', { + allowUndefined: true, + }); + expect(value).toEqual(['foo', 'bar', 'baz']); + }); + }); + describe('default is set', () => { + it('returns the environment variable as an array of strings', () => { + process.env.TEST_STRING_ARRAY = 'foo,bar,baz'; + const value = getStringArray('TEST_STRING_ARRAY', { default: ['bar'] }); + expect(value).toEqual(['foo', 'bar', 'baz']); + }); + }); + describe('allow list is defined', () => { + describe('environmental variable is in allow list', () => { + it('return the environmental variable as an array of strings', () => { + process.env.TEST_STRING_ARRAY = 'foo,bar,baz'; + const value = getStringArray('TEST_STRING_ARRAY', { + allowList: ['foo', 'bar', 'baz'], + }); + expect(value).toEqual(['foo', 'bar', 'baz']); + }); + }); + describe('environmental variable is NOT in allow list', () => { + it('throws an error', () => { + process.env.TEST_STRING_ARRAY = 'foo,bar,baz'; + expect(() => { + getStringArray('TEST_STRING_ARRAY', { allowList: ['foo', 'baz'] }); + }).toThrow( + new ListValueConfigError('TEST_STRING_ARRAY', 'bar', [ + 'foo', + 'baz', + ]), + ); + }); + }); + }); + }); + describe('environment variable is set to an empty string', () => { + it('throws an error', () => { + process.env.TEST_STRING_ARRAY = ''; + expect(() => { + getStringArray('TEST_STRING_ARRAY'); + }).toThrow(new NotDefinedConfigError('TEST_STRING_ARRAY')); + }); + + describe('allow undefined', () => { + it('returns an empty array', () => { + process.env.TEST_STRING_ARRAY = ''; + const value = getStringArray('TEST_STRING_ARRAY', { + allowUndefined: true, + }); + expect(value).toEqual([]); + }); + }); + + describe('default is set', () => { + it('returns the default', () => { + process.env.TEST_STRING_ARRAY = ''; + const value = getStringArray('TEST_STRING_ARRAY', { default: ['bar'] }); + expect(value).toEqual(['bar']); + }); + }); + }); + describe('environment variable is not set', () => { + it('throws an error', () => { + expect(() => { + getStringArray('TEST_STRING_ARRAY'); + }).toThrow(new NotDefinedConfigError('TEST_STRING_ARRAY')); + }); + + describe('allow undefined', () => { + it('returns an empty array', () => { + const value = getStringArray('TEST_STRING_ARRAY', { + allowUndefined: true, + }); + expect(value).toEqual([]); + }); + }); + + describe('default is set', () => { + it('returns the default', () => { + const value = getStringArray('TEST_STRING_ARRAY', { default: ['bar'] }); + expect(value).toEqual(['bar']); + }); + }); + }); +}); diff --git a/src/string.ts b/src/string.ts index 50dec15..4de61fb 100644 --- a/src/string.ts +++ b/src/string.ts @@ -78,6 +78,88 @@ export function getString(name: string, options: GetStringOptions = {}) { throw error; } +type GetStringArrayOptionsAllow = { + allowList?: string[]; +}; + +type GetStringArrayOptionsAllowUndefined = { + allowUndefined: true; + default?: undefined; +} & GetStringArrayOptionsAllow; +type GetStringArrayOptionsNoDefault = { + allowUndefined?: false; + default?: undefined; +} & GetStringArrayOptionsAllow; +type GetStringArrayOptionsDefault = { + allowUndefined?: false; + default: string[]; +} & GetStringArrayOptionsAllow; + +export type GetStringArrayOptions = + | GetStringArrayOptionsAllowUndefined + | GetStringArrayOptionsNoDefault + | GetStringArrayOptionsDefault; + +/** + * Returns an environmental variable as a `string` array. Optionally the value + * can be validated by an `allowList`. + */ +export function getStringArray( + name: string, + options: { + allowList?: string[]; + allowUndefined: true; + default?: undefined; + }, +): string[]; +/** + * Returns an environmental variable as a `string` array or, if undefined, + * throws an error. Optionally the values can be validated by an `allowList`. + */ +export function getStringArray( + name: string, + options?: { + allowList?: string[]; + allowUndefined?: false; + default?: undefined; + }, +): string[]; +/** + * Returns an environmental variable as a `string` array or, if undefined, the + * provided default value. Optionally the values can be validated by an `allowList`. + */ +export function getStringArray( + name: string, + options: { + allowList?: string[]; + allowUndefined?: false; + default: string[]; + }, +): string[]; +export function getStringArray( + name: string, + options: GetStringArrayOptions = {}, +) { + const { allowList, allowUndefined, default: defaultValue } = options; + const value = process.env[name]; + if (value !== undefined && value !== '') { + const valueList = value.split(','); + valueList.forEach((value) => validateList(name, value, allowList)); + return valueList; + } + if (defaultValue !== undefined) { + return defaultValue; + } + if (allowUndefined) { + return []; + } + const error = new NotDefinedConfigError(name); + if (Error.captureStackTrace) { + Error.captureStackTrace(error, getString); + } + throw error; +} + const validateList = (name: string, value: string, list?: string[]): void => { if (list !== undefined && !list.includes(value)) { const error = new ListValueConfigError(name, value, list);