diff --git a/src/features/settings/composables/__tests__/useSettings.test.js b/src/features/settings/composables/__tests__/useSettings.test.js new file mode 100644 index 0000000..dc62d69 --- /dev/null +++ b/src/features/settings/composables/__tests__/useSettings.test.js @@ -0,0 +1,94 @@ +/* +Copyright 2026 Seekra + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { useSettingsConfigCacheStore } from '../../stores/settingsConfigCacheStore'; +import { useSettingsStore } from '../../stores/settingsStore'; +import { useSettings } from '../useSettings'; +import { createTestingPinia } from '@pinia/testing'; +import { setActivePinia } from 'pinia'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; + +const settingDefaultValue = 42; +const settingPath = ['test', 'number']; + +describe('useSettings', () => { + describe('getSetting', () => { + test('returns stored value', () => { + const { getSetting } = useSettings(); + const settings = useSettingsStore(); + + const key = 'setting'; + const value = 42; + + settings.set(key, value); + + expect(getSetting(key)).toBe(value); + }); + + test('returns default value', () => { + const { getSetting } = useSettings(); + expect(getSetting(settingPath)).toBe(settingDefaultValue); + }); + + test('returns stored value instead of default value', () => { + const { getSetting } = useSettings(); + const settings = useSettingsStore(); + + const value = 43; + + expect(getSetting(settingPath)).toBe(settingDefaultValue); + + settings.set(settingPath, value); + expect(getSetting(settingPath)).toBe(value); + }); + + test('returns undefined if there is no value', () => { + const { getSetting } = useSettings(); + expect(getSetting(['test', 'bool'])).toBeUndefined(); + }); + }); +}); + +beforeEach(() => { + setActivePinia( + createTestingPinia({ + createSpy: vi.fn, + stubActions: false + }) + ); + const settingsConfigCache = useSettingsConfigCacheStore(); + settingsConfigCache.set({ + contents: [ + { + name: 'test', + i18n: '', + content: [ + { + type: 'number', + i18n: '', + name: 'number', + default: settingDefaultValue + }, + { + type: 'bool', + i18n: '', + name: 'bool' + } + ] + } + ] + }); +}); diff --git a/src/features/settings/composables/useSettings.js b/src/features/settings/composables/useSettings.js new file mode 100644 index 0000000..cd8cc29 --- /dev/null +++ b/src/features/settings/composables/useSettings.js @@ -0,0 +1,44 @@ +/* +Copyright 2026 Seekra + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { useSettingsConfigCacheStore } from '../stores/settingsConfigCacheStore'; +import { useSettingsStore } from '../stores/settingsStore'; +import { getSettingRecursively } from '../utils/getSetting'; +import { loadSettingsConfig } from '../utils/settingsParser'; + +/** + * Provides access to the stored settings. + */ +export const useSettings = function useSettings () { + /** + * Returns the value of a specific setting. + * @param {string[]} key - The settings key. + * @return The value of the setting. + */ + const getSetting = function getSetting (key) { + const settingsStore = useSettingsStore(); + + const settings = useSettingsConfigCacheStore().get(); + return ( + settingsStore.get(key) ?? + getSettingRecursively( + key, settings.contents ?? [] + )?.default + ); + }; + + return { getSetting }; +}; diff --git a/src/features/settings/stores/settingsConfigCacheStore.js b/src/features/settings/stores/settingsConfigCacheStore.js new file mode 100644 index 0000000..9ed923f --- /dev/null +++ b/src/features/settings/stores/settingsConfigCacheStore.js @@ -0,0 +1,31 @@ +/* +Copyright 2026 Seekra + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { defineStore } from 'pinia'; + +export const useSettingsConfigCacheStore = defineStore('settingsConfigCache', () => { + let settingsConfig = undefined; + + const set = function set (value) { + settingsConfig = value; + }; + + const get = function get () { + return settingsConfig; + }; + + return { set, get }; +}); diff --git a/src/features/settings/utils/settingsParser.js b/src/features/settings/utils/settingsParser.js index 2b7e658..1dd9626 100644 --- a/src/features/settings/utils/settingsParser.js +++ b/src/features/settings/utils/settingsParser.js @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { useSettingsConfigCacheStore } from '../stores/settingsConfigCacheStore'; import { validateSettingsConfig } from './settingsValidator.js'; /** @@ -21,10 +22,12 @@ import { validateSettingsConfig } from './settingsValidator.js'; * @returns {Promise} */ export async function loadSettingsConfig() { + const settingsConfigCache = useSettingsConfigCacheStore(); let raw; try { raw = (await import('../settings.json')).default; + settingsConfigCache.set(raw); } catch (e) { throw new Error(`[settings] Failed to load settings.json: ${e.message}`); }