refactor: refactor settings to a nested structure (#7244)

This commit is contained in:
Gal Zahavi
2025-08-27 18:39:45 -07:00
committed by GitHub
parent b8a7bfd136
commit f22263c9e8
41 changed files with 2852 additions and 1424 deletions

View File

@@ -64,7 +64,9 @@ describe('handleAutoUpdate', () => {
mockSettings = {
merged: {
disableAutoUpdate: false,
general: {
disableAutoUpdate: false,
},
},
} as LoadedSettings;
@@ -93,7 +95,7 @@ describe('handleAutoUpdate', () => {
});
it('should do nothing if update nag is disabled', () => {
mockSettings.merged.disableUpdateNag = true;
mockSettings.merged.general!.disableUpdateNag = true;
handleAutoUpdate(mockUpdateInfo, mockSettings, '/root', mockSpawn);
expect(mockGetInstallationInfo).not.toHaveBeenCalled();
expect(mockUpdateEventEmitter.emit).not.toHaveBeenCalled();
@@ -101,7 +103,7 @@ describe('handleAutoUpdate', () => {
});
it('should emit "update-received" but not update if auto-updates are disabled', () => {
mockSettings.merged.disableAutoUpdate = true;
mockSettings.merged.general!.disableAutoUpdate = true;
mockGetInstallationInfo.mockReturnValue({
updateCommand: 'npm i -g @google/gemini-cli@latest',
updateMessage: 'Please update manually.',

View File

@@ -23,13 +23,13 @@ export function handleAutoUpdate(
return;
}
if (settings.merged.disableUpdateNag) {
if (settings.merged.general?.disableUpdateNag) {
return;
}
const installationInfo = getInstallationInfo(
projectRoot,
settings.merged.disableAutoUpdate ?? false,
settings.merged.general?.disableAutoUpdate ?? false,
);
let combinedMessage = info.message;
@@ -41,7 +41,10 @@ export function handleAutoUpdate(
message: combinedMessage,
});
if (!installationInfo.updateCommand || settings.merged.disableAutoUpdate) {
if (
!installationInfo.updateCommand ||
settings.merged.general?.disableAutoUpdate
) {
return;
}
const isNightly = info.update.latest.includes('nightly');

View File

@@ -42,12 +42,7 @@ describe('SettingsUtils', () => {
const categories = getSettingsByCategory();
expect(categories).toHaveProperty('General');
expect(categories).toHaveProperty('Accessibility');
expect(categories).toHaveProperty('Checkpointing');
expect(categories).toHaveProperty('File Filtering');
expect(categories).toHaveProperty('UI');
expect(categories).toHaveProperty('Mode');
expect(categories).toHaveProperty('Updates');
});
it('should include key property in grouped settings', () => {
@@ -63,7 +58,7 @@ describe('SettingsUtils', () => {
describe('getSettingDefinition', () => {
it('should return definition for valid setting', () => {
const definition = getSettingDefinition('showMemoryUsage');
const definition = getSettingDefinition('ui.showMemoryUsage');
expect(definition).toBeDefined();
expect(definition?.label).toBe('Show Memory Usage');
});
@@ -76,13 +71,13 @@ describe('SettingsUtils', () => {
describe('requiresRestart', () => {
it('should return true for settings that require restart', () => {
expect(requiresRestart('autoConfigureMaxOldSpaceSize')).toBe(true);
expect(requiresRestart('checkpointing.enabled')).toBe(true);
expect(requiresRestart('advanced.autoConfigureMemory')).toBe(true);
expect(requiresRestart('general.checkpointing.enabled')).toBe(true);
});
it('should return false for settings that do not require restart', () => {
expect(requiresRestart('showMemoryUsage')).toBe(false);
expect(requiresRestart('hideTips')).toBe(false);
expect(requiresRestart('ui.showMemoryUsage')).toBe(false);
expect(requiresRestart('ui.hideTips')).toBe(false);
});
it('should return false for invalid settings', () => {
@@ -92,10 +87,10 @@ describe('SettingsUtils', () => {
describe('getDefaultValue', () => {
it('should return correct default values', () => {
expect(getDefaultValue('showMemoryUsage')).toBe(false);
expect(getDefaultValue('fileFiltering.enableRecursiveFileSearch')).toBe(
true,
);
expect(getDefaultValue('ui.showMemoryUsage')).toBe(false);
expect(
getDefaultValue('context.fileFiltering.enableRecursiveFileSearch'),
).toBe(true);
});
it('should return undefined for invalid settings', () => {
@@ -106,19 +101,19 @@ describe('SettingsUtils', () => {
describe('getRestartRequiredSettings', () => {
it('should return all settings that require restart', () => {
const restartSettings = getRestartRequiredSettings();
expect(restartSettings).toContain('autoConfigureMaxOldSpaceSize');
expect(restartSettings).toContain('checkpointing.enabled');
expect(restartSettings).not.toContain('showMemoryUsage');
expect(restartSettings).toContain('advanced.autoConfigureMemory');
expect(restartSettings).toContain('general.checkpointing.enabled');
expect(restartSettings).not.toContain('ui.showMemoryUsage');
});
});
describe('getEffectiveValue', () => {
it('should return value from settings when set', () => {
const settings = { showMemoryUsage: true };
const mergedSettings = { showMemoryUsage: false };
const settings = { ui: { showMemoryUsage: true } };
const mergedSettings = { ui: { showMemoryUsage: false } };
const value = getEffectiveValue(
'showMemoryUsage',
'ui.showMemoryUsage',
settings,
mergedSettings,
);
@@ -127,10 +122,10 @@ describe('SettingsUtils', () => {
it('should return value from merged settings when not set in current scope', () => {
const settings = {};
const mergedSettings = { showMemoryUsage: true };
const mergedSettings = { ui: { showMemoryUsage: true } };
const value = getEffectiveValue(
'showMemoryUsage',
'ui.showMemoryUsage',
settings,
mergedSettings,
);
@@ -142,7 +137,7 @@ describe('SettingsUtils', () => {
const mergedSettings = {};
const value = getEffectiveValue(
'showMemoryUsage',
'ui.showMemoryUsage',
settings,
mergedSettings,
);
@@ -151,14 +146,14 @@ describe('SettingsUtils', () => {
it('should handle nested settings correctly', () => {
const settings = {
accessibility: { disableLoadingPhrases: true },
ui: { accessibility: { disableLoadingPhrases: true } },
};
const mergedSettings = {
accessibility: { disableLoadingPhrases: false },
ui: { accessibility: { disableLoadingPhrases: false } },
};
const value = getEffectiveValue(
'accessibility.disableLoadingPhrases',
'ui.accessibility.disableLoadingPhrases',
settings,
mergedSettings,
);
@@ -181,9 +176,9 @@ describe('SettingsUtils', () => {
describe('getAllSettingKeys', () => {
it('should return all setting keys', () => {
const keys = getAllSettingKeys();
expect(keys).toContain('showMemoryUsage');
expect(keys).toContain('accessibility.disableLoadingPhrases');
expect(keys).toContain('checkpointing.enabled');
expect(keys).toContain('ui.showMemoryUsage');
expect(keys).toContain('ui.accessibility.disableLoadingPhrases');
expect(keys).toContain('general.checkpointing.enabled');
});
});
@@ -209,10 +204,10 @@ describe('SettingsUtils', () => {
describe('isValidSettingKey', () => {
it('should return true for valid setting keys', () => {
expect(isValidSettingKey('showMemoryUsage')).toBe(true);
expect(isValidSettingKey('accessibility.disableLoadingPhrases')).toBe(
true,
);
expect(isValidSettingKey('ui.showMemoryUsage')).toBe(true);
expect(
isValidSettingKey('ui.accessibility.disableLoadingPhrases'),
).toBe(true);
});
it('should return false for invalid setting keys', () => {
@@ -223,10 +218,10 @@ describe('SettingsUtils', () => {
describe('getSettingCategory', () => {
it('should return correct category for valid settings', () => {
expect(getSettingCategory('showMemoryUsage')).toBe('UI');
expect(getSettingCategory('accessibility.disableLoadingPhrases')).toBe(
'Accessibility',
);
expect(getSettingCategory('ui.showMemoryUsage')).toBe('UI');
expect(
getSettingCategory('ui.accessibility.disableLoadingPhrases'),
).toBe('UI');
});
it('should return undefined for invalid settings', () => {
@@ -236,18 +231,20 @@ describe('SettingsUtils', () => {
describe('shouldShowInDialog', () => {
it('should return true for settings marked to show in dialog', () => {
expect(shouldShowInDialog('showMemoryUsage')).toBe(true);
expect(shouldShowInDialog('vimMode')).toBe(true);
expect(shouldShowInDialog('hideWindowTitle')).toBe(true);
expect(shouldShowInDialog('usageStatisticsEnabled')).toBe(false);
expect(shouldShowInDialog('ui.showMemoryUsage')).toBe(true);
expect(shouldShowInDialog('general.vimMode')).toBe(true);
expect(shouldShowInDialog('ui.hideWindowTitle')).toBe(true);
expect(shouldShowInDialog('privacy.usageStatisticsEnabled')).toBe(
false,
);
});
it('should return false for settings marked to hide from dialog', () => {
expect(shouldShowInDialog('selectedAuthType')).toBe(false);
expect(shouldShowInDialog('coreTools')).toBe(false);
expect(shouldShowInDialog('customThemes')).toBe(false);
expect(shouldShowInDialog('theme')).toBe(false); // Changed to false
expect(shouldShowInDialog('preferredEditor')).toBe(false); // Changed to false
expect(shouldShowInDialog('security.auth.selectedType')).toBe(false);
expect(shouldShowInDialog('tools.core')).toBe(false);
expect(shouldShowInDialog('ui.customThemes')).toBe(false);
expect(shouldShowInDialog('ui.theme')).toBe(false); // Changed to false
expect(shouldShowInDialog('general.preferredEditor')).toBe(false); // Changed to false
});
it('should return true for invalid settings (default behavior)', () => {
@@ -263,10 +260,10 @@ describe('SettingsUtils', () => {
expect(categories['UI']).toBeDefined();
const uiSettings = categories['UI'];
const uiKeys = uiSettings.map((s) => s.key);
expect(uiKeys).toContain('showMemoryUsage');
expect(uiKeys).toContain('hideWindowTitle');
expect(uiKeys).not.toContain('customThemes'); // This is marked false
expect(uiKeys).not.toContain('theme'); // This is now marked false
expect(uiKeys).toContain('ui.showMemoryUsage');
expect(uiKeys).toContain('ui.hideWindowTitle');
expect(uiKeys).not.toContain('ui.customThemes'); // This is marked false
expect(uiKeys).not.toContain('ui.theme'); // This is now marked false
});
it('should not include Advanced category settings', () => {
@@ -282,15 +279,15 @@ describe('SettingsUtils', () => {
const allSettings = Object.values(categories).flat();
const allKeys = allSettings.map((s) => s.key);
expect(allKeys).toContain('vimMode');
expect(allKeys).toContain('ideMode');
expect(allKeys).toContain('disableAutoUpdate');
expect(allKeys).toContain('showMemoryUsage');
expect(allKeys).not.toContain('usageStatisticsEnabled');
expect(allKeys).not.toContain('selectedAuthType');
expect(allKeys).not.toContain('coreTools');
expect(allKeys).not.toContain('theme'); // Now hidden
expect(allKeys).not.toContain('preferredEditor'); // Now hidden
expect(allKeys).toContain('general.vimMode');
expect(allKeys).toContain('ide.enabled');
expect(allKeys).toContain('general.disableAutoUpdate');
expect(allKeys).toContain('ui.showMemoryUsage');
expect(allKeys).not.toContain('privacy.usageStatisticsEnabled');
expect(allKeys).not.toContain('security.auth.selectedType');
expect(allKeys).not.toContain('tools.core');
expect(allKeys).not.toContain('ui.theme'); // Now hidden
expect(allKeys).not.toContain('general.preferredEditor'); // Now hidden
});
});
@@ -299,12 +296,12 @@ describe('SettingsUtils', () => {
const booleanSettings = getDialogSettingsByType('boolean');
const keys = booleanSettings.map((s) => s.key);
expect(keys).toContain('showMemoryUsage');
expect(keys).toContain('vimMode');
expect(keys).toContain('hideWindowTitle');
expect(keys).not.toContain('usageStatisticsEnabled');
expect(keys).not.toContain('selectedAuthType'); // Advanced setting
expect(keys).not.toContain('useExternalAuth'); // Advanced setting
expect(keys).toContain('ui.showMemoryUsage');
expect(keys).toContain('general.vimMode');
expect(keys).toContain('ui.hideWindowTitle');
expect(keys).not.toContain('privacy.usageStatisticsEnabled');
expect(keys).not.toContain('security.auth.selectedType'); // Advanced setting
expect(keys).not.toContain('security.auth.useExternal'); // Advanced setting
});
it('should return only string dialog settings', () => {
@@ -312,9 +309,9 @@ describe('SettingsUtils', () => {
const keys = stringSettings.map((s) => s.key);
// Note: theme and preferredEditor are now hidden from dialog
expect(keys).not.toContain('theme'); // Now marked false
expect(keys).not.toContain('preferredEditor'); // Now marked false
expect(keys).not.toContain('selectedAuthType'); // Advanced setting
expect(keys).not.toContain('ui.theme'); // Now marked false
expect(keys).not.toContain('general.preferredEditor'); // Now marked false
expect(keys).not.toContain('security.auth.selectedType'); // Advanced setting
// Most string settings are now hidden, so let's just check they exclude advanced ones
expect(keys.every((key) => !key.startsWith('tool'))).toBe(true); // No tool-related settings
@@ -326,24 +323,28 @@ describe('SettingsUtils', () => {
const dialogKeys = getDialogSettingKeys();
// Should include settings marked for dialog
expect(dialogKeys).toContain('showMemoryUsage');
expect(dialogKeys).toContain('vimMode');
expect(dialogKeys).toContain('hideWindowTitle');
expect(dialogKeys).not.toContain('usageStatisticsEnabled');
expect(dialogKeys).toContain('ideMode');
expect(dialogKeys).toContain('disableAutoUpdate');
expect(dialogKeys).toContain('ui.showMemoryUsage');
expect(dialogKeys).toContain('general.vimMode');
expect(dialogKeys).toContain('ui.hideWindowTitle');
expect(dialogKeys).not.toContain('privacy.usageStatisticsEnabled');
expect(dialogKeys).toContain('ide.enabled');
expect(dialogKeys).toContain('general.disableAutoUpdate');
// Should include nested settings marked for dialog
expect(dialogKeys).toContain('fileFiltering.respectGitIgnore');
expect(dialogKeys).toContain('fileFiltering.respectGeminiIgnore');
expect(dialogKeys).toContain('fileFiltering.enableRecursiveFileSearch');
expect(dialogKeys).toContain('context.fileFiltering.respectGitIgnore');
expect(dialogKeys).toContain(
'context.fileFiltering.respectGeminiIgnore',
);
expect(dialogKeys).toContain(
'context.fileFiltering.enableRecursiveFileSearch',
);
// Should NOT include settings marked as hidden
expect(dialogKeys).not.toContain('theme'); // Hidden
expect(dialogKeys).not.toContain('customThemes'); // Hidden
expect(dialogKeys).not.toContain('preferredEditor'); // Hidden
expect(dialogKeys).not.toContain('selectedAuthType'); // Advanced
expect(dialogKeys).not.toContain('coreTools'); // Advanced
expect(dialogKeys).not.toContain('ui.theme'); // Hidden
expect(dialogKeys).not.toContain('ui.customThemes'); // Hidden
expect(dialogKeys).not.toContain('general.preferredEditor'); // Hidden
expect(dialogKeys).not.toContain('security.auth.selectedType'); // Advanced
expect(dialogKeys).not.toContain('tools.core'); // Advanced
expect(dialogKeys).not.toContain('mcpServers'); // Advanced
expect(dialogKeys).not.toContain('telemetry'); // Advanced
});
@@ -358,7 +359,7 @@ describe('SettingsUtils', () => {
it('should handle nested settings display correctly', () => {
// Test the specific issue with fileFiltering.respectGitIgnore
const key = 'fileFiltering.respectGitIgnore';
const key = 'context.fileFiltering.respectGitIgnore';
const initialSettings = {};
const pendingSettings = {};
@@ -411,11 +412,11 @@ describe('SettingsUtils', () => {
describe('Business Logic Utilities', () => {
describe('getSettingValue', () => {
it('should return value from settings when set', () => {
const settings = { showMemoryUsage: true };
const mergedSettings = { showMemoryUsage: false };
const settings = { ui: { showMemoryUsage: true } };
const mergedSettings = { ui: { showMemoryUsage: false } };
const value = getSettingValue(
'showMemoryUsage',
'ui.showMemoryUsage',
settings,
mergedSettings,
);
@@ -424,10 +425,10 @@ describe('SettingsUtils', () => {
it('should return value from merged settings when not set in current scope', () => {
const settings = {};
const mergedSettings = { showMemoryUsage: true };
const mergedSettings = { ui: { showMemoryUsage: true } };
const value = getSettingValue(
'showMemoryUsage',
'ui.showMemoryUsage',
settings,
mergedSettings,
);
@@ -449,51 +450,68 @@ describe('SettingsUtils', () => {
describe('isSettingModified', () => {
it('should return true when value differs from default', () => {
expect(isSettingModified('showMemoryUsage', true)).toBe(true);
expect(isSettingModified('ui.showMemoryUsage', true)).toBe(true);
expect(
isSettingModified('fileFiltering.enableRecursiveFileSearch', false),
isSettingModified(
'context.fileFiltering.enableRecursiveFileSearch',
false,
),
).toBe(true);
});
it('should return false when value matches default', () => {
expect(isSettingModified('showMemoryUsage', false)).toBe(false);
expect(isSettingModified('ui.showMemoryUsage', false)).toBe(false);
expect(
isSettingModified('fileFiltering.enableRecursiveFileSearch', true),
isSettingModified(
'context.fileFiltering.enableRecursiveFileSearch',
true,
),
).toBe(false);
});
});
describe('settingExistsInScope', () => {
it('should return true for top-level settings that exist', () => {
const settings = { showMemoryUsage: true };
expect(settingExistsInScope('showMemoryUsage', settings)).toBe(true);
const settings = { ui: { showMemoryUsage: true } };
expect(settingExistsInScope('ui.showMemoryUsage', settings)).toBe(true);
});
it('should return false for top-level settings that do not exist', () => {
const settings = {};
expect(settingExistsInScope('showMemoryUsage', settings)).toBe(false);
expect(settingExistsInScope('ui.showMemoryUsage', settings)).toBe(
false,
);
});
it('should return true for nested settings that exist', () => {
const settings = {
accessibility: { disableLoadingPhrases: true },
ui: { accessibility: { disableLoadingPhrases: true } },
};
expect(
settingExistsInScope('accessibility.disableLoadingPhrases', settings),
settingExistsInScope(
'ui.accessibility.disableLoadingPhrases',
settings,
),
).toBe(true);
});
it('should return false for nested settings that do not exist', () => {
const settings = {};
expect(
settingExistsInScope('accessibility.disableLoadingPhrases', settings),
settingExistsInScope(
'ui.accessibility.disableLoadingPhrases',
settings,
),
).toBe(false);
});
it('should return false when parent exists but child does not', () => {
const settings = { accessibility: {} };
const settings = { ui: { accessibility: {} } };
expect(
settingExistsInScope('accessibility.disableLoadingPhrases', settings),
settingExistsInScope(
'ui.accessibility.disableLoadingPhrases',
settings,
),
).toBe(false);
});
});
@@ -502,41 +520,41 @@ describe('SettingsUtils', () => {
it('should set top-level setting value', () => {
const pendingSettings = {};
const result = setPendingSettingValue(
'showMemoryUsage',
'ui.showMemoryUsage',
true,
pendingSettings,
);
expect(result.showMemoryUsage).toBe(true);
expect(result.ui?.showMemoryUsage).toBe(true);
});
it('should set nested setting value', () => {
const pendingSettings = {};
const result = setPendingSettingValue(
'accessibility.disableLoadingPhrases',
'ui.accessibility.disableLoadingPhrases',
true,
pendingSettings,
);
expect(result.accessibility?.disableLoadingPhrases).toBe(true);
expect(result.ui?.accessibility?.disableLoadingPhrases).toBe(true);
});
it('should preserve existing nested settings', () => {
const pendingSettings = {
accessibility: { disableLoadingPhrases: false },
ui: { accessibility: { disableLoadingPhrases: false } },
};
const result = setPendingSettingValue(
'accessibility.disableLoadingPhrases',
'ui.accessibility.disableLoadingPhrases',
true,
pendingSettings,
);
expect(result.accessibility?.disableLoadingPhrases).toBe(true);
expect(result.ui?.accessibility?.disableLoadingPhrases).toBe(true);
});
it('should not mutate original settings', () => {
const pendingSettings = {};
setPendingSettingValue('showMemoryUsage', true, pendingSettings);
setPendingSettingValue('ui.showMemoryUsage', true, pendingSettings);
expect(pendingSettings).toEqual({});
});
@@ -545,16 +563,16 @@ describe('SettingsUtils', () => {
describe('hasRestartRequiredSettings', () => {
it('should return true when modified settings require restart', () => {
const modifiedSettings = new Set<string>([
'autoConfigureMaxOldSpaceSize',
'showMemoryUsage',
'advanced.autoConfigureMemory',
'ui.showMemoryUsage',
]);
expect(hasRestartRequiredSettings(modifiedSettings)).toBe(true);
});
it('should return false when no modified settings require restart', () => {
const modifiedSettings = new Set<string>([
'showMemoryUsage',
'hideTips',
'ui.showMemoryUsage',
'ui.hideTips',
]);
expect(hasRestartRequiredSettings(modifiedSettings)).toBe(false);
});
@@ -568,15 +586,15 @@ describe('SettingsUtils', () => {
describe('getRestartRequiredFromModified', () => {
it('should return only settings that require restart', () => {
const modifiedSettings = new Set<string>([
'autoConfigureMaxOldSpaceSize',
'showMemoryUsage',
'checkpointing.enabled',
'advanced.autoConfigureMemory',
'ui.showMemoryUsage',
'general.checkpointing.enabled',
]);
const result = getRestartRequiredFromModified(modifiedSettings);
expect(result).toContain('autoConfigureMaxOldSpaceSize');
expect(result).toContain('checkpointing.enabled');
expect(result).not.toContain('showMemoryUsage');
expect(result).toContain('advanced.autoConfigureMemory');
expect(result).toContain('general.checkpointing.enabled');
expect(result).not.toContain('ui.showMemoryUsage');
});
it('should return empty array when no settings require restart', () => {
@@ -592,12 +610,12 @@ describe('SettingsUtils', () => {
describe('getDisplayValue', () => {
it('should show value without * when setting matches default', () => {
const settings = { showMemoryUsage: false }; // false matches default, so no *
const mergedSettings = { showMemoryUsage: false };
const settings = { ui: { showMemoryUsage: false } }; // false matches default, so no *
const mergedSettings = { ui: { showMemoryUsage: false } };
const modifiedSettings = new Set<string>();
const result = getDisplayValue(
'showMemoryUsage',
'ui.showMemoryUsage',
settings,
mergedSettings,
modifiedSettings,
@@ -607,11 +625,11 @@ describe('SettingsUtils', () => {
it('should show default value when setting is not in scope', () => {
const settings = {}; // no setting in scope
const mergedSettings = { showMemoryUsage: false };
const mergedSettings = { ui: { showMemoryUsage: false } };
const modifiedSettings = new Set<string>();
const result = getDisplayValue(
'showMemoryUsage',
'ui.showMemoryUsage',
settings,
mergedSettings,
modifiedSettings,
@@ -620,12 +638,12 @@ describe('SettingsUtils', () => {
});
it('should show value with * when changed from default', () => {
const settings = { showMemoryUsage: true }; // true is different from default (false)
const mergedSettings = { showMemoryUsage: true };
const settings = { ui: { showMemoryUsage: true } }; // true is different from default (false)
const mergedSettings = { ui: { showMemoryUsage: true } };
const modifiedSettings = new Set<string>();
const result = getDisplayValue(
'showMemoryUsage',
'ui.showMemoryUsage',
settings,
mergedSettings,
modifiedSettings,
@@ -635,11 +653,11 @@ describe('SettingsUtils', () => {
it('should show default value without * when setting does not exist in scope', () => {
const settings = {}; // setting doesn't exist in scope, show default
const mergedSettings = { showMemoryUsage: false };
const mergedSettings = { ui: { showMemoryUsage: false } };
const modifiedSettings = new Set<string>();
const result = getDisplayValue(
'showMemoryUsage',
'ui.showMemoryUsage',
settings,
mergedSettings,
modifiedSettings,
@@ -649,12 +667,12 @@ describe('SettingsUtils', () => {
it('should show value with * when user changes from default', () => {
const settings = {}; // setting doesn't exist in scope originally
const mergedSettings = { showMemoryUsage: false };
const modifiedSettings = new Set<string>(['showMemoryUsage']);
const pendingSettings = { showMemoryUsage: true }; // user changed to true
const mergedSettings = { ui: { showMemoryUsage: false } };
const modifiedSettings = new Set<string>(['ui.showMemoryUsage']);
const pendingSettings = { ui: { showMemoryUsage: true } }; // user changed to true
const result = getDisplayValue(
'showMemoryUsage',
'ui.showMemoryUsage',
settings,
mergedSettings,
modifiedSettings,
@@ -668,14 +686,14 @@ describe('SettingsUtils', () => {
it('should return true when setting does not exist in scope', () => {
const settings = {}; // setting doesn't exist
const result = isDefaultValue('showMemoryUsage', settings);
const result = isDefaultValue('ui.showMemoryUsage', settings);
expect(result).toBe(true);
});
it('should return false when setting exists in scope', () => {
const settings = { showMemoryUsage: true }; // setting exists
const settings = { ui: { showMemoryUsage: true } }; // setting exists
const result = isDefaultValue('showMemoryUsage', settings);
const result = isDefaultValue('ui.showMemoryUsage', settings);
expect(result).toBe(false);
});
@@ -683,17 +701,19 @@ describe('SettingsUtils', () => {
const settings = {}; // nested setting doesn't exist
const result = isDefaultValue(
'accessibility.disableLoadingPhrases',
'ui.accessibility.disableLoadingPhrases',
settings,
);
expect(result).toBe(true);
});
it('should return false when nested setting exists in scope', () => {
const settings = { accessibility: { disableLoadingPhrases: true } }; // nested setting exists
const settings = {
ui: { accessibility: { disableLoadingPhrases: true } },
}; // nested setting exists
const result = isDefaultValue(
'accessibility.disableLoadingPhrases',
'ui.accessibility.disableLoadingPhrases',
settings,
);
expect(result).toBe(false);
@@ -702,11 +722,11 @@ describe('SettingsUtils', () => {
describe('isValueInherited', () => {
it('should return false for top-level settings that exist in scope', () => {
const settings = { showMemoryUsage: true };
const mergedSettings = { showMemoryUsage: true };
const settings = { ui: { showMemoryUsage: true } };
const mergedSettings = { ui: { showMemoryUsage: true } };
const result = isValueInherited(
'showMemoryUsage',
'ui.showMemoryUsage',
settings,
mergedSettings,
);
@@ -715,10 +735,10 @@ describe('SettingsUtils', () => {
it('should return true for top-level settings that do not exist in scope', () => {
const settings = {};
const mergedSettings = { showMemoryUsage: true };
const mergedSettings = { ui: { showMemoryUsage: true } };
const result = isValueInherited(
'showMemoryUsage',
'ui.showMemoryUsage',
settings,
mergedSettings,
);
@@ -727,14 +747,14 @@ describe('SettingsUtils', () => {
it('should return false for nested settings that exist in scope', () => {
const settings = {
accessibility: { disableLoadingPhrases: true },
ui: { accessibility: { disableLoadingPhrases: true } },
};
const mergedSettings = {
accessibility: { disableLoadingPhrases: true },
ui: { accessibility: { disableLoadingPhrases: true } },
};
const result = isValueInherited(
'accessibility.disableLoadingPhrases',
'ui.accessibility.disableLoadingPhrases',
settings,
mergedSettings,
);
@@ -744,11 +764,11 @@ describe('SettingsUtils', () => {
it('should return true for nested settings that do not exist in scope', () => {
const settings = {};
const mergedSettings = {
accessibility: { disableLoadingPhrases: true },
ui: { accessibility: { disableLoadingPhrases: true } },
};
const result = isValueInherited(
'accessibility.disableLoadingPhrases',
'ui.accessibility.disableLoadingPhrases',
settings,
mergedSettings,
);
@@ -758,11 +778,11 @@ describe('SettingsUtils', () => {
describe('getEffectiveDisplayValue', () => {
it('should return value from settings when available', () => {
const settings = { showMemoryUsage: true };
const mergedSettings = { showMemoryUsage: false };
const settings = { ui: { showMemoryUsage: true } };
const mergedSettings = { ui: { showMemoryUsage: false } };
const result = getEffectiveDisplayValue(
'showMemoryUsage',
'ui.showMemoryUsage',
settings,
mergedSettings,
);
@@ -771,10 +791,10 @@ describe('SettingsUtils', () => {
it('should return value from merged settings when not in scope', () => {
const settings = {};
const mergedSettings = { showMemoryUsage: true };
const mergedSettings = { ui: { showMemoryUsage: true } };
const result = getEffectiveDisplayValue(
'showMemoryUsage',
'ui.showMemoryUsage',
settings,
mergedSettings,
);
@@ -786,7 +806,7 @@ describe('SettingsUtils', () => {
const mergedSettings = {};
const result = getEffectiveDisplayValue(
'showMemoryUsage',
'ui.showMemoryUsage',
settings,
mergedSettings,
);

View File

@@ -399,22 +399,7 @@ export function saveModifiedSettings(
const isDefaultValue = value === getDefaultValue(settingKey);
if (existsInOriginalFile || !isDefaultValue) {
// This is tricky because setValue only works on top-level keys.
// We need to set the whole parent object.
const [parentKey] = path;
if (parentKey) {
const newParentValue = setPendingSettingValueAny(
settingKey,
value,
loadedSettings.forScope(scope).settings,
)[parentKey as keyof Settings];
loadedSettings.setValue(
scope,
parentKey as keyof Settings,
newParentValue,
);
}
loadedSettings.setValue(scope, settingKey, value);
}
});
}