feat(cli): support default values for environment variables (#24469)

This commit is contained in:
ruomeng
2026-04-02 10:38:45 -04:00
committed by GitHub
parent 44c8b43328
commit 7b6ab50138
3 changed files with 93 additions and 46 deletions
+34 -14
View File
@@ -6,33 +6,53 @@
/**
* Resolves environment variables in a string.
* Replaces $VAR_NAME and ${VAR_NAME} with their corresponding environment variable values.
* If the environment variable is not defined, the original placeholder is preserved.
* Replaces $VAR_NAME, ${VAR_NAME}, and ${VAR_NAME:-DEFAULT_VALUE} with their corresponding
* environment variable values. If the environment variable is not defined and no default
* value is provided, the original placeholder is preserved.
*
* @param value - The string that may contain environment variable placeholders
* @param customEnv - Optional record of environment variables to use before process.env
* @returns The string with environment variables resolved
*
* @example
* resolveEnvVarsInString("Token: $API_KEY") // Returns "Token: secret-123"
* resolveEnvVarsInString("URL: ${BASE_URL}/api") // Returns "URL: https://api.example.com/api"
* resolveEnvVarsInString("URL: ${MISSING_VAR:-https://default.com}") // Returns "URL: https://default.com"
* resolveEnvVarsInString("Missing: $UNDEFINED_VAR") // Returns "Missing: $UNDEFINED_VAR"
*/
export function resolveEnvVarsInString(
value: string,
customEnv?: Record<string, string>,
): string {
const envVarRegex = /\$(?:(\w+)|{([^}]+)})/g; // Find $VAR_NAME or ${VAR_NAME}
return value.replace(envVarRegex, (match, varName1, varName2) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const varName = varName1 || varName2;
if (customEnv && typeof customEnv[varName] === 'string') {
return customEnv[varName];
}
if (process && process.env && typeof process.env[varName] === 'string') {
return process.env[varName];
}
return match;
});
// Regex matches $VAR_NAME, ${VAR_NAME}, and ${VAR_NAME:-DEFAULT_VALUE}
const envVarRegex = /\$(?:(\w+)|{([^}]+?)(?::-([^}]*))?})/g;
return value.replace(
envVarRegex,
(
match: string,
varName1?: string,
varName2?: string,
defaultValue?: string,
): string => {
const varName: string = varName1 || varName2 || '';
if (!varName) {
return match;
}
if (customEnv && typeof customEnv[varName] === 'string') {
return customEnv[varName];
}
if (process && process.env && typeof process.env[varName] === 'string') {
return process.env[varName];
}
if (defaultValue !== undefined) {
return defaultValue;
}
return match;
},
);
}
/**