From 6f87d1c03ba53cc406ef14e1b0b175fe64c1c9a0 Mon Sep 17 00:00:00 2001 From: notable-equivalent <193968300+notable-equivalent@users.noreply.github.com> Date: Fri, 19 Jun 2026 15:51:24 -0400 Subject: [PATCH 1/3] Expand undefined environment variables to empty --- Extension/src/common.ts | 14 +++++++++----- .../SingleRootProject/tests/common.test.ts | 12 ++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Extension/src/common.ts b/Extension/src/common.ts index c84f94290..972dc5384 100644 --- a/Extension/src/common.ts +++ b/Extension/src/common.ts @@ -400,13 +400,11 @@ export function resolveVariables(input: string | undefined, additionalEnvironmen while (!cycleCache.has(ret)) { cycleCache.add(ret); ret = ret.replace(regexp(), (match: string, ignored1: string, varType: string, ignored2: string, name: string) => { - // Historically, if the variable didn't have anything before the "." or ":" - // it was assumed to be an environment variable - if (!varType) { - varType = "env"; - } let newValue: string | undefined; switch (varType) { + // Historically, if the variable didn't have anything before the "." or ":" + // it was assumed to be an environment variable + case undefined: case "env": { if (additionalEnvironment) { const v: string | string[] | undefined = additionalEnvironment[name]; @@ -425,6 +423,12 @@ export function resolveVariables(input: string | undefined, additionalEnvironmen if (newValue === undefined) { newValue = process.env[name]; } + + // If the environment variable is not set, we return an empty string. Only do + // this for ${env:X} variables, not ${X} variables. + if (newValue === undefined && varType !== undefined) { + newValue = ""; + } break; } case "config": { diff --git a/Extension/test/scenarios/SingleRootProject/tests/common.test.ts b/Extension/test/scenarios/SingleRootProject/tests/common.test.ts index e04c88ea2..62cbfa396 100644 --- a/Extension/test/scenarios/SingleRootProject/tests/common.test.ts +++ b/Extension/test/scenarios/SingleRootProject/tests/common.test.ts @@ -199,6 +199,18 @@ suite("resolveVariables", () => { .shouldLookupSymbol("Root"); }); + test("${env:UNDEFINED_ENV_VAR} expands to empty", () => { + resolveVariablesWithInput("${env:UNDEFINED_ENV_VAR}") + .withEnvironment({}) + .shouldResolveTo(""); + }); + + test("${UNDEFINED_ENV_VAR} left unexpanded", () => { + resolveVariablesWithInput("${UNDEFINED_ENV_VAR}") + .withEnvironment({}) + .shouldResolveTo("${UNDEFINED_ENV_VAR}"); + }); + test("escapeForSquiggles:", () => { const testEscapeForSquigglesScenario: any = (input: string, expectedOutput: string) => { const result: string = escapeForSquiggles(input); From 2681541608b3d08a0f4c2c7134260105877a47f7 Mon Sep 17 00:00:00 2001 From: notable-equivalent <193968300+notable-equivalent@users.noreply.github.com> Date: Fri, 19 Jun 2026 16:15:34 -0400 Subject: [PATCH 2/3] Use unique env var name Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../SingleRootProject/tests/common.test.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Extension/test/scenarios/SingleRootProject/tests/common.test.ts b/Extension/test/scenarios/SingleRootProject/tests/common.test.ts index 62cbfa396..3c9e625a6 100644 --- a/Extension/test/scenarios/SingleRootProject/tests/common.test.ts +++ b/Extension/test/scenarios/SingleRootProject/tests/common.test.ts @@ -199,16 +199,21 @@ suite("resolveVariables", () => { .shouldLookupSymbol("Root"); }); - test("${env:UNDEFINED_ENV_VAR} expands to empty", () => { - resolveVariablesWithInput("${env:UNDEFINED_ENV_VAR}") + test("${env:X} expands to empty when unset", () => { + const processKey: string = `cpptoolstests_unset_${Date.now()}`; + delete process.env[processKey]; + resolveVariablesWithInput("${env:" + processKey + "}") .withEnvironment({}) .shouldResolveTo(""); }); - test("${UNDEFINED_ENV_VAR} left unexpanded", () => { - resolveVariablesWithInput("${UNDEFINED_ENV_VAR}") + test("${X} left unexpanded when unset", () => { + const processKey: string = `cpptoolstests_unset_${Date.now()}`; + delete process.env[processKey]; + const token: string = "${" + processKey + "}"; + resolveVariablesWithInput(token) .withEnvironment({}) - .shouldResolveTo("${UNDEFINED_ENV_VAR}"); + .shouldResolveTo(token); }); test("escapeForSquiggles:", () => { From 9757de6f8d0b04ca0f53b3d040197ab7519e36cd Mon Sep 17 00:00:00 2001 From: notable-equivalent <193968300+notable-equivalent@users.noreply.github.com> Date: Fri, 19 Jun 2026 16:21:18 -0400 Subject: [PATCH 3/3] Marked optional capturing groups as potentially undefined --- Extension/src/common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/src/common.ts b/Extension/src/common.ts index 972dc5384..60a8ff72e 100644 --- a/Extension/src/common.ts +++ b/Extension/src/common.ts @@ -399,7 +399,7 @@ export function resolveVariables(input: string | undefined, additionalEnvironmen const cycleCache = new Set(); while (!cycleCache.has(ret)) { cycleCache.add(ret); - ret = ret.replace(regexp(), (match: string, ignored1: string, varType: string, ignored2: string, name: string) => { + ret = ret.replace(regexp(), (match: string, ignored1: string | undefined, varType: string | undefined, ignored2: string | undefined, name: string) => { let newValue: string | undefined; switch (varType) { // Historically, if the variable didn't have anything before the "." or ":"