diff --git a/.chronus/changes/fix-file-type-interpolation-2026-2-27-10-9-43.md b/.chronus/changes/fix-file-type-interpolation-2026-2-27-10-9-43.md new file mode 100644 index 00000000000..081e574e862 --- /dev/null +++ b/.chronus/changes/fix-file-type-interpolation-2026-2-27-10-9-43.md @@ -0,0 +1,12 @@ +--- +changeKind: fix +packages: + - "@typespec/compiler" +--- + +Do not interpolate non primitive values in config automatically + ```yaml + file-type: ["json", "yaml"] + output-file: "openapi.{file-type}" + ``` + Will not be interpolated as `openapi.json,yaml` but keep the placeholder `{file-type}` intact for the emitter to handle. diff --git a/packages/compiler/src/config/config-interpolation.ts b/packages/compiler/src/config/config-interpolation.ts index d96d8c4dd15..705cf2bce24 100644 --- a/packages/compiler/src/config/config-interpolation.ts +++ b/packages/compiler/src/config/config-interpolation.ts @@ -114,8 +114,13 @@ export function resolveValues>( resolvingValues.delete(keyPath); return value; } - const replaced = value.replace(VariableInterpolationRegex, (_, expression) => { - return (resolveExpression(expression) as string) ?? `{${expression}}`; + const replaced = value.replace(VariableInterpolationRegex, (match, expression) => { + const resolved = resolveExpression(expression); + return typeof resolved === "string" || + typeof resolved === "number" || + typeof resolved === "boolean" + ? String(resolved) + : match; }); resolvingValues.delete(keyPath); return replaced; diff --git a/packages/compiler/test/config/config-interpolation.test.ts b/packages/compiler/test/config/config-interpolation.test.ts index 6a639444ce7..f8c5d711252 100644 --- a/packages/compiler/test/config/config-interpolation.test.ts +++ b/packages/compiler/test/config/config-interpolation.test.ts @@ -133,6 +133,32 @@ describe("compiler: config interpolation", () => { }, ]); }); + + it("does not interpolate variables that resolve to non-string values", () => { + const [resolved, diagnostics] = resolveValues({ + "output-file": "openapi.{file-type}", + "file-type": ["yaml", "json"] as any, + }); + expectDiagnosticEmpty(diagnostics); + deepStrictEqual(resolved, { + "output-file": "openapi.{file-type}", + "file-type": ["yaml", "json"], + }); + }); + + it("interpolates number and boolean values", () => { + const [resolved, diagnostics] = resolveValues({ + path: "v{version}/debug-{debug}", + version: 3 as any, + debug: true as any, + }); + expectDiagnosticEmpty(diagnostics); + deepStrictEqual(resolved, { + path: "v3/debug-true", + version: 3, + debug: true, + }); + }); }); describe("expandConfigVariables", () => {