diff --git a/__tests__/load-config-sync.test.ts b/__tests__/load-config-sync.test.ts index bbf1dd9..48ebbf8 100644 --- a/__tests__/load-config-sync.test.ts +++ b/__tests__/load-config-sync.test.ts @@ -376,11 +376,13 @@ describe('loadConfig', () => { const variableName = 'VARIABLE_NAME'; const variableValue = 'The value of this environment variable.'; - it('returns the formatted value.', () => { + beforeEach(() => { process.env[variableName] = variableValue; // @ts-ignore fs._setFiles({[filePath]: Buffer.from(fileContent, 'utf8')}); + }); + it('returns the formatted value.', () => { // eslint-disable-next-line unicorn/consistent-function-scoping const formatter = (value: string): number => value.length; @@ -399,11 +401,49 @@ describe('loadConfig', () => { expect(config.variableProperty).toEqual(formatter(variableValue)); }); - it('throws if the formatter throws.', () => { - process.env[variableName] = variableValue; - // @ts-ignore - fs._setFiles({[filePath]: Buffer.from(fileContent, 'utf8')}); + it('returns the formatted value if explicitly required.', () => { + // eslint-disable-next-line unicorn/consistent-function-scoping + const formatter = (value: string): number => value.length; + + const config = loadConfigSync({ + fileProperty: { + filePath, + format: formatter, + required: true, + }, + variableProperty: { + format: formatter, + required: true, + variableName, + }, + }); + + expect(config.fileProperty).toEqual(formatter(fileContent)); + expect(config.variableProperty).toEqual(formatter(variableValue)); + }); + + it('returns the formatted value if not required.', () => { + // eslint-disable-next-line unicorn/consistent-function-scoping + const formatter = (value: string): number => value.length; + + const config = loadConfigSync({ + fileProperty: { + filePath, + format: formatter, + required: false, + }, + variableProperty: { + format: formatter, + required: false, + variableName, + }, + }); + expect(config.fileProperty).toEqual(formatter(fileContent)); + expect(config.variableProperty).toEqual(formatter(variableValue)); + }); + + it('throws if the formatter throws.', () => { // eslint-disable-next-line unicorn/consistent-function-scoping const formatter = (value: string): number => { const integer = Number.parseInt(value, 10); diff --git a/__tests__/load-config.test.ts b/__tests__/load-config.test.ts index a2c19a2..978ba1f 100644 --- a/__tests__/load-config.test.ts +++ b/__tests__/load-config.test.ts @@ -376,11 +376,13 @@ describe('loadConfig', () => { const variableName = 'VARIABLE_NAME'; const variableValue = 'The value of this environment variable.'; - it('returns the formatted value.', async () => { + beforeEach(() => { process.env[variableName] = variableValue; // @ts-ignore fs._setFiles({[filePath]: Buffer.from(fileContent, 'utf8')}); + }); + it('returns the formatted value.', async () => { // eslint-disable-next-line unicorn/consistent-function-scoping const formatter = (value: string): string => value.toLowerCase(); @@ -399,11 +401,49 @@ describe('loadConfig', () => { expect(config.variableProperty).toEqual(formatter(variableValue)); }); - it('rejects if the formatter throws.', async () => { - process.env[variableName] = variableValue; - // @ts-ignore - fs._setFiles({[filePath]: Buffer.from(fileContent, 'utf8')}); + it('returns the formatted value if explicitly required.', async () => { + // eslint-disable-next-line unicorn/consistent-function-scoping + const formatter = (value: string): number => value.length; + const config = await loadConfig({ + fileProperty: { + filePath, + format: formatter, + required: true, + }, + variableProperty: { + format: formatter, + required: true, + variableName, + }, + }); + + expect(config.fileProperty).toEqual(formatter(fileContent)); + expect(config.variableProperty).toEqual(formatter(variableValue)); + }); + + it('returns the formatted value if not required.', async () => { + // eslint-disable-next-line unicorn/consistent-function-scoping + const formatter = (value: string): number => value.length; + + const config = await loadConfig({ + fileProperty: { + filePath, + format: formatter, + required: false, + }, + variableProperty: { + format: formatter, + required: false, + variableName, + }, + }); + + expect(config.fileProperty).toEqual(formatter(fileContent)); + expect(config.variableProperty).toEqual(formatter(variableValue)); + }); + + it('rejects if the formatter throws.', async () => { // eslint-disable-next-line unicorn/consistent-function-scoping const formatter = (value: string): number => { const integer = Number.parseInt(value, 10); diff --git a/src/format-property.ts b/src/format-property.ts index cb07f1b..309ccc5 100644 --- a/src/format-property.ts +++ b/src/format-property.ts @@ -1,9 +1,4 @@ -import { - FormattableConfig, - PropertyFormatter, - PropertyResult, - RequirableConfig, -} from './types'; +import {BaseConfig, PropertyFormatter, PropertyResult} from './types'; function tryToFormat( value: string, @@ -18,13 +13,9 @@ function tryToFormat( export default function something( propertyResult: PropertyResult, - propertyConfig: FormattableConfig | RequirableConfig, + propertyConfig: BaseConfig, ): PropertyResult { - const { - defaultValue, - format, - required = true, - } = propertyConfig as FormattableConfig; + const {defaultValue, format, required = true} = propertyConfig; const hasDefaultValue = typeof defaultValue !== 'undefined'; const hasError = propertyResult.error !== false; const hasFormat = typeof format !== 'undefined'; diff --git a/src/types.ts b/src/types.ts index d55ccae..32c0b85 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,7 +1,7 @@ /** * Configuration for a property that can be formatted. */ -export interface FormattableConfig { +export interface BaseConfig { /** * The default value of this property. */ @@ -16,50 +16,35 @@ export interface FormattableConfig { * Whether this property is required. * @defaultValue true */ - required?: true; + required?: boolean; } /** - * Configuration for a property that can be required. + * Configuration for a property loaded from an environment variable. */ -export interface RequirableConfig { +export interface EnvironmentConfig extends BaseConfig { /** - * Whether this property is required. - * @defaultValue true + * The name of the environment variable. */ - required?: boolean; + variableName: string; } /** - * The result loading a property. - * @internal + * Configuration for a property loaded from a secret. */ -export interface PropertyResult { +export interface FileConfig extends BaseConfig { /** - * The error that was thrown, or false if there is none. + * The encoding of the file containing the secret. + * @defaultValue 'utf8' */ - error: false | Error; + encoding?: BufferEncoding; /** - * The value that was loaded, or undefined if it could not be loaded. + * The path to the file containing the secret. */ - value: undefined | Value; + filePath: string; } -/** - * Configuration for a property loaded from an environment variable. - */ -export type EnvironmentConfig = - | (BaseEnvironmentConfig & FormattableConfig) - | (BaseEnvironmentConfig & RequirableConfig); - -/** - * Configuration for a property loaded from a secret. - */ -export type FileConfig = - | (BaseFileConfig & FormattableConfig) - | (BaseFileConfig & RequirableConfig); - /** * The configuration for loading a specific property. */ @@ -74,45 +59,35 @@ export type PropertyConfig = export type PropertyFormatter = (raw: string) => Value; /** - * Unwrap a property config to its resultant value. + * The result loading a property. + * @internal */ -export type UnwrapPropertyConfig< - PConfig extends PropertyConfig -> = PConfig extends string - ? string - : PConfig extends {required: false} - ? UnwrapResult | void - : UnwrapResult; +export interface PropertyResult { + /** + * The error that was thrown, or false if there is none. + */ + error: false | Error; -/** - * Base configuration for a property loaded from an environment variable. - */ -interface BaseEnvironmentConfig { /** - * The name of the environment variable. + * The value that was loaded, or undefined if it could not be loaded. */ - variableName: string; + value: undefined | Value; } /** - * Base configuration for a property loaded from a secret. + * Unwrap a property config to its resultant value. */ -interface BaseFileConfig { - /** - * The encoding of the file containing the secret. - * @defaultValue 'utf8' - */ - encoding?: BufferEncoding; - - /** - * The path to the file containing the secret. - */ - filePath: string; -} +export type UnwrapPropertyConfig< + PConfig extends PropertyConfig +> = PConfig extends string + ? string + : PConfig extends {required: false} + ? UnwrapResult | undefined + : UnwrapResult; /** * Unwrap a result to its value. */ type UnwrapResult< PConfig extends PropertyConfig -> = PConfig extends FormattableConfig ? Value : string; +> = PConfig extends BaseConfig ? Value : string;