diff --git a/packages/config-loader/src/lib/transform/include.test.ts b/packages/config-loader/src/lib/transform/include.test.ts index 81c6cfb63b..12f59feb84 100644 --- a/packages/config-loader/src/lib/transform/include.test.ts +++ b/packages/config-loader/src/lib/transform/include.test.ts @@ -29,23 +29,21 @@ const env = jest.fn(async (name: string) => { } as { [name: string]: string })[name]; }); -const substitute = jest.fn( - async ( - value: JsonValue, - ): Promise<{ applied: boolean; value?: JsonValue }> => { - if (typeof value !== 'string') { - return { applied: false }; - } - if (value.includes(substituteMe)) { - return { - applied: true, - value: value.replace(substituteMe, mySubstitution), - }; - } - +const substitute = async ( + value: JsonValue, +): Promise<{ applied: boolean; value?: JsonValue }> => { + if (typeof value !== 'string') { return { applied: false }; - }, -); + } + if (value.includes(substituteMe)) { + return { + applied: true, + value: value.replace(substituteMe, mySubstitution), + }; + } + + return { applied: false }; +}; const readFile = jest.fn(async (path: string) => { const content = ({ diff --git a/packages/config-loader/src/lib/transform/include.ts b/packages/config-loader/src/lib/transform/include.ts index bffc2e0184..2b5ccf23b6 100644 --- a/packages/config-loader/src/lib/transform/include.ts +++ b/packages/config-loader/src/lib/transform/include.ts @@ -55,12 +55,18 @@ export function createIncludeTransform( } const rawIncludedValue = input[includeKey]; - const substituteResults = await substitute(rawIncludedValue!, baseDir); + if (typeof rawIncludedValue !== 'string') { + throw new Error(`${includeKey} include value is not a string`); + } + + const substituteResults = await substitute(rawIncludedValue, baseDir); const includeValue = substituteResults.applied ? substituteResults.value : rawIncludedValue; - if (typeof includeValue !== 'string') { - throw new Error(`${includeKey} include value is not a string`); + + // The second string check is needed for Typescript to know this is a string. + if (includeValue === undefined || typeof includeValue !== 'string') { + throw new Error(`${includeKey} substitution value was undefined`); } switch (includeKey) { diff --git a/packages/config-loader/src/lib/transform/substitution.test.ts b/packages/config-loader/src/lib/transform/substitution.test.ts index ef557431dd..d07e88cfdd 100644 --- a/packages/config-loader/src/lib/transform/substitution.test.ts +++ b/packages/config-loader/src/lib/transform/substitution.test.ts @@ -56,6 +56,12 @@ describe('substituteTransform', () => { applied: true, value: undefined, }); + await expect( + substituteTransform('empty substitute ${}', '/'), + ).resolves.toEqual({ + applied: true, + value: undefined, + }); await expect( substituteTransform('foo ${MISSING} ${SECRET}', '/'), ).resolves.toEqual({ applied: true, value: undefined }); @@ -65,5 +71,11 @@ describe('substituteTransform', () => { await expect( substituteTransform('foo ${SECRET} $$${ESCAPE_ME}', '/'), ).resolves.toEqual({ applied: true, value: 'foo my-secret $${ESCAPE_ME}' }); + await expect( + substituteTransform('foo $${ESCAPE_ME} $$${ESCAPE_ME_TOO} $${}', '/'), + ).resolves.toEqual({ + applied: true, + value: 'foo ${ESCAPE_ME} $${ESCAPE_ME_TOO} ${}', + }); }); }); diff --git a/packages/config-loader/src/lib/transform/substitution.ts b/packages/config-loader/src/lib/transform/substitution.ts index 482f1221a9..56695fa431 100644 --- a/packages/config-loader/src/lib/transform/substitution.ts +++ b/packages/config-loader/src/lib/transform/substitution.ts @@ -28,15 +28,16 @@ export function createSubstitutionTransform(env: EnvFunc): TransformFunc { return { applied: false }; } - const parts: (string | undefined)[] = input.split(/(? part === undefined)) { return { applied: true, value: undefined }; }