feat(cli): support boolean and number casting for env vars in settings.json (#26118)

This commit is contained in:
Coco Sheng
2026-04-28 13:32:51 -04:00
committed by GitHub
parent 4b8d5e7624
commit c841070582
4 changed files with 280 additions and 22 deletions
+43 -16
View File
@@ -673,7 +673,9 @@ function _doLoadSettings(workspaceDir: string): LoadedSettings {
const storage = new Storage(workspaceDir);
const workspaceSettingsPath = storage.getWorkspaceSettingsPath();
const load = (filePath: string): { settings: Settings; rawJson?: string } => {
const load = (
filePath: string,
): { settings: Settings; rawSettings: Settings; rawJson?: string } => {
try {
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath, 'utf-8');
@@ -689,14 +691,19 @@ function _doLoadSettings(workspaceDir: string): LoadedSettings {
path: filePath,
severity: 'error',
});
return { settings: {} };
return { settings: {}, rawSettings: {} };
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const settingsObject = rawSettings as Record<string, unknown>;
// Validate settings structure with Zod
const validationResult = validateSettings(settingsObject);
// Expand environment variables
const expandedSettings = resolveEnvVarsInObject(
settingsObject as Settings,
);
// Validate settings structure with Zod after environment variable expansion
const validationResult = validateSettings(expandedSettings);
if (!validationResult.success && validationResult.error) {
const errorMessage = formatValidationError(
validationResult.error,
@@ -707,9 +714,22 @@ function _doLoadSettings(workspaceDir: string): LoadedSettings {
path: filePath,
severity: 'warning',
});
return {
settings: expandedSettings,
rawSettings: settingsObject as Settings,
rawJson: content,
};
}
return { settings: settingsObject as Settings, rawJson: content };
// Return the successfully cast and validated data
return {
// Since we've successfully validated expandedSettings against settingsZodSchema,
// it's safe to cast the resulting data to the Settings type.
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
settings: (validationResult.data as Settings) ?? expandedSettings,
rawSettings: settingsObject as Settings,
rawJson: content,
};
}
} catch (error: unknown) {
settingsErrors.push({
@@ -718,33 +738,40 @@ function _doLoadSettings(workspaceDir: string): LoadedSettings {
severity: 'error',
});
}
return { settings: {} };
return { settings: {}, rawSettings: {} };
};
const systemResult = load(systemSettingsPath);
const systemDefaultsResult = load(systemDefaultsPath);
const userResult = load(USER_SETTINGS_PATH);
let workspaceResult: { settings: Settings; rawJson?: string } = {
let workspaceResult: {
settings: Settings;
rawSettings: Settings;
rawJson?: string;
} = {
settings: {} as Settings,
rawSettings: {} as Settings,
rawJson: undefined,
};
if (!storage.isWorkspaceHomeDir()) {
workspaceResult = load(workspaceSettingsPath);
}
const systemOriginalSettings = structuredClone(systemResult.settings);
const systemOriginalSettings = structuredClone(systemResult.rawSettings);
const systemDefaultsOriginalSettings = structuredClone(
systemDefaultsResult.settings,
systemDefaultsResult.rawSettings,
);
const userOriginalSettings = structuredClone(userResult.rawSettings);
const workspaceOriginalSettings = structuredClone(
workspaceResult.rawSettings,
);
const userOriginalSettings = structuredClone(userResult.settings);
const workspaceOriginalSettings = structuredClone(workspaceResult.settings);
// Environment variables for runtime use
systemSettings = resolveEnvVarsInObject(systemResult.settings);
systemDefaultSettings = resolveEnvVarsInObject(systemDefaultsResult.settings);
userSettings = resolveEnvVarsInObject(userResult.settings);
workspaceSettings = resolveEnvVarsInObject(workspaceResult.settings);
// Environment variables for runtime use are already resolved and validated in load()
systemSettings = systemResult.settings;
systemDefaultSettings = systemDefaultsResult.settings;
userSettings = userResult.settings;
workspaceSettings = workspaceResult.settings;
// Support legacy theme names
if (userSettings.ui?.theme === 'VS') {