diff --git a/packages/core/package.json b/packages/core/package.json index 1b796ae..b6d9dbb 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -85,10 +85,6 @@ "require": "./lib/browser-storage/index.cjs", "import": "./lib/browser-storage/index.mjs" }, - "./lib/browser-storage/load": { - "require": "./lib/browser-storage/load.cjs", - "import": "./lib/browser-storage/load.mjs" - }, "./lib/browser-storage/mock": { "require": "./lib/browser-storage/mock.cjs", "import": "./lib/browser-storage/mock.mjs" @@ -105,10 +101,6 @@ "require": "./lib/builder/functions.cjs", "import": "./lib/builder/functions.mjs" }, - "./lib/cache": { - "require": "./lib/cache.cjs", - "import": "./lib/cache.mjs" - }, "./lib/icon/list": { "require": "./lib/icon/list.cjs", "import": "./lib/icon/list.mjs" diff --git a/packages/core/src/api/icons.ts b/packages/core/src/api/icons.ts index e6b5aae..3bf4dcb 100644 --- a/packages/core/src/api/icons.ts +++ b/packages/core/src/api/icons.ts @@ -12,7 +12,7 @@ import { getStorage, addIconSet } from '../storage/storage'; import { listToIcons } from '../icon/list'; import { allowSimpleNames, getIconData } from '../storage/functions'; import { sendAPIQuery } from './query'; -import { cache } from '../cache'; +import { storeInBrowserStorage } from '../browser-storage/store'; // Empty abort callback for loadIcons() function emptyCallback(): void { @@ -207,9 +207,10 @@ function loadNewIcons(provider: string, prefix: string, icons: string[]): void { }); // Cache API response - if (cache.store) { - cache.store(provider, data as IconifyJSON); - } + storeInBrowserStorage( + provider, + data as IconifyJSON + ); } catch (err) { console.error(err); } diff --git a/packages/core/src/browser-storage/data.ts b/packages/core/src/browser-storage/data.ts index 6bdc09c..b5cb0d5 100644 --- a/packages/core/src/browser-storage/data.ts +++ b/packages/core/src/browser-storage/data.ts @@ -2,6 +2,7 @@ import type { BrowserStorageConfig, BrowserStorageCount, BrowserStorageEmptyList, + BrowserStorageStatus, } from './types'; /** @@ -31,8 +32,8 @@ export const browserStorageEmptyItems: BrowserStorageEmptyList = { /** * Flag to check if storage has been loaded */ -export let browserStorageLoaded = false; +export let browserStorageStatus: BrowserStorageStatus = false; -export function setBrowserStorageStatus(loaded: boolean) { - browserStorageLoaded = loaded; +export function setBrowserStorageStatus(status: BrowserStorageStatus) { + browserStorageStatus = status; } diff --git a/packages/core/src/browser-storage/destroy.ts b/packages/core/src/browser-storage/destroy.ts deleted file mode 100644 index 93e494f..0000000 --- a/packages/core/src/browser-storage/destroy.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { browserCachePrefix } from './config'; -import { getBrowserStorageItemsCount } from './count'; - -/** - * Destroy old cache - */ -export function destroyBrowserStorage(storage: typeof localStorage): void { - try { - const total = getBrowserStorageItemsCount(storage); - for (let i = 0; i < total; i++) { - storage.removeItem(browserCachePrefix + i.toString()); - } - } catch (err) { - // - } -} diff --git a/packages/core/src/browser-storage/index.ts b/packages/core/src/browser-storage/index.ts index abe1513..cd4684b 100644 --- a/packages/core/src/browser-storage/index.ts +++ b/packages/core/src/browser-storage/index.ts @@ -1,11 +1,137 @@ -import { cache } from '../cache'; -import { loadBrowserStorageCache } from './load'; -import { storeInBrowserStorage } from './store'; +import { addIconSet, getStorage } from '../storage/storage'; +import { + browserCachePrefix, + browserCacheVersion, + browserCacheVersionKey, + browserStorageCacheExpiration, + browserStorageHour, +} from './config'; +import { + getBrowserStorageItemsCount, + setBrowserStorageItemsCount, +} from './count'; +import { + browserStorageConfig, + browserStorageEmptyItems, + browserStorageStatus, + setBrowserStorageStatus, +} from './data'; +import { getBrowserStorage } from './global'; +import type { BrowserStorageConfig, BrowserStorageItem } from './types'; /** - * Init browser storage + * Load icons from cache */ export function initBrowserStorage() { - cache.store = storeInBrowserStorage; - loadBrowserStorageCache(); + if (browserStorageStatus === true) { + return; + } + setBrowserStorageStatus('loading'); + + // Minimum time + const minTime = + Math.floor(Date.now() / browserStorageHour) - + browserStorageCacheExpiration; + + // Load data from storage + function load(key: keyof BrowserStorageConfig): void { + const func = getBrowserStorage(key); + if (!func) { + return; + } + + // Get one item from storage + const getItem = (index: number): boolean => { + const name = browserCachePrefix + index.toString(); + const item = func.getItem(name); + + if (typeof item !== 'string') { + // Does not exist + return false; + } + + // Get item, validate it + let valid = true; + try { + // Parse, check time stamp + const data = JSON.parse(item) as BrowserStorageItem; + if ( + typeof data !== 'object' || + typeof data.cached !== 'number' || + data.cached < minTime || + typeof data.provider !== 'string' || + typeof data.data !== 'object' || + typeof data.data.prefix !== 'string' + ) { + valid = false; + } else { + // Add icon set + const provider = data.provider; + const prefix = data.data.prefix; + const storage = getStorage(provider, prefix); + valid = addIconSet(storage, data.data).length > 0; + } + } catch (err) { + valid = false; + } + + if (!valid) { + func.removeItem(name); + } + return valid; + }; + + try { + // Get version + const version = func.getItem(browserCacheVersionKey); + if (version !== browserCacheVersion) { + if (version) { + // Version is set, but invalid - remove old entries + try { + const total = getBrowserStorageItemsCount(func); + for (let i = 0; i < total; i++) { + func.removeItem(browserCachePrefix + i.toString()); + } + } catch (err) { + // + } + } + + // Empty data + try { + func.setItem(browserCacheVersionKey, browserCacheVersion); + } catch (err) { + // + } + setBrowserStorageItemsCount(func, key, 0); + return; + } + + // Get number of stored items + let total = getBrowserStorageItemsCount(func); + for (let i = total - 1; i >= 0; i--) { + if (!getItem(i)) { + // Remove item + if (i === total - 1) { + // Last item - reduce country + total--; + } else { + // Mark as empty + browserStorageEmptyItems[key].push(i); + } + } + } + + // Update total + setBrowserStorageItemsCount(func, key, total); + } catch (err) { + // + } + } + + for (const key in browserStorageConfig) { + load(key as keyof BrowserStorageConfig); + } + + setBrowserStorageStatus(true); } diff --git a/packages/core/src/browser-storage/load.ts b/packages/core/src/browser-storage/load.ts deleted file mode 100644 index ed642aa..0000000 --- a/packages/core/src/browser-storage/load.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { addIconSet, getStorage } from '../storage/storage'; -import { - browserCachePrefix, - browserCacheVersion, - browserCacheVersionKey, - browserStorageCacheExpiration, - browserStorageHour, -} from './config'; -import { - getBrowserStorageItemsCount, - setBrowserStorageItemsCount, -} from './count'; -import { - browserStorageConfig, - browserStorageEmptyItems, - browserStorageLoaded, - setBrowserStorageStatus, -} from './data'; -import { getBrowserStorage } from './global'; -import type { BrowserStorageConfig, BrowserStorageItem } from './types'; - -/** - * Destroy old cache - */ -function destroyBrowserStorage(storage: typeof localStorage): void { - try { - const total = getBrowserStorageItemsCount(storage); - for (let i = 0; i < total; i++) { - storage.removeItem(browserCachePrefix + i.toString()); - } - } catch (err) { - // - } -} - -/** - * Initialize storage - */ -function initBrowserStorage( - storage: typeof localStorage, - key: keyof BrowserStorageConfig -): void { - try { - storage.setItem(browserCacheVersionKey, browserCacheVersion); - } catch (err) { - // - } - setBrowserStorageItemsCount(storage, key, 0); -} - -/** - * Load icons from cache - */ -export function loadBrowserStorageCache() { - if (browserStorageLoaded) { - return; - } - setBrowserStorageStatus(true); - - // Minimum time - const minTime = - Math.floor(Date.now() / browserStorageHour) - - browserStorageCacheExpiration; - - // Load data from storage - function load(key: keyof BrowserStorageConfig): void { - const func = getBrowserStorage(key); - if (!func) { - return; - } - - // Get one item from storage - const getItem = (index: number): boolean => { - const name = browserCachePrefix + index.toString(); - const item = func.getItem(name); - - if (typeof item !== 'string') { - // Does not exist - return false; - } - - // Get item, validate it - let valid = true; - try { - // Parse, check time stamp - const data = JSON.parse(item) as BrowserStorageItem; - if ( - typeof data !== 'object' || - typeof data.cached !== 'number' || - data.cached < minTime || - typeof data.provider !== 'string' || - typeof data.data !== 'object' || - typeof data.data.prefix !== 'string' - ) { - valid = false; - } else { - // Add icon set - const provider = data.provider; - const prefix = data.data.prefix; - const storage = getStorage(provider, prefix); - valid = addIconSet(storage, data.data).length > 0; - } - } catch (err) { - valid = false; - } - - if (!valid) { - func.removeItem(name); - } - return valid; - }; - - try { - // Get version - const version = func.getItem(browserCacheVersionKey); - if (version !== browserCacheVersion) { - if (version) { - // Version is set, but invalid - remove old entries - destroyBrowserStorage(func); - } - // Empty data - initBrowserStorage(func, key); - return; - } - - // Get number of stored items - let total = getBrowserStorageItemsCount(func); - for (let i = total - 1; i >= 0; i--) { - if (!getItem(i)) { - // Remove item - if (i === total - 1) { - // Last item - reduce country - total--; - } else { - // Mark as empty - browserStorageEmptyItems[key].push(i); - } - } - } - - // Update total - setBrowserStorageItemsCount(func, key, total); - } catch (err) { - // - } - } - - for (const key in browserStorageConfig) { - load(key as keyof BrowserStorageConfig); - } -} diff --git a/packages/core/src/browser-storage/store.ts b/packages/core/src/browser-storage/store.ts index a3bd469..45e0b1e 100644 --- a/packages/core/src/browser-storage/store.ts +++ b/packages/core/src/browser-storage/store.ts @@ -1,26 +1,22 @@ import type { IconifyJSON } from '@iconify/types'; -import type { CacheIcons } from '../cache'; import { browserCachePrefix, browserStorageHour } from './config'; import { setBrowserStorageItemsCount } from './count'; import { browserStorageConfig, browserStorageEmptyItems, browserStorageItemsCount, - browserStorageLoaded, + browserStorageStatus, } from './data'; import { getBrowserStorage } from './global'; -import { loadBrowserStorageCache } from './load'; +import { initBrowserStorage } from './index'; import type { BrowserStorageConfig, BrowserStorageItem } from './types'; /** * Function to cache icons */ -export const storeInBrowserStorage: CacheIcons = ( - provider: string, - data: IconifyJSON -): void => { - if (!browserStorageLoaded) { - loadBrowserStorageCache(); +export function storeInBrowserStorage(provider: string, data: IconifyJSON) { + if (!browserStorageStatus) { + initBrowserStorage(); } function store(key: keyof BrowserStorageConfig): boolean { @@ -75,4 +71,4 @@ export const storeInBrowserStorage: CacheIcons = ( if (!store('local')) { store('session'); } -}; +} diff --git a/packages/core/src/browser-storage/types.ts b/packages/core/src/browser-storage/types.ts index f56182a..896944b 100644 --- a/packages/core/src/browser-storage/types.ts +++ b/packages/core/src/browser-storage/types.ts @@ -21,3 +21,6 @@ export interface BrowserStorageItem { provider: string; data: IconifyJSON; } + +// Status: not loaded, loading, loaded +export type BrowserStorageStatus = false | 'loading' | true; diff --git a/packages/core/src/cache.ts b/packages/core/src/cache.ts deleted file mode 100644 index aeaf3b1..0000000 --- a/packages/core/src/cache.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { IconifyJSON } from '@iconify/types'; - -/** - * Function to cache loaded icons set - */ -export type CacheIcons = (provider: string, data: IconifyJSON) => void; - -/** - * Module - */ -interface CacheModule { - store?: CacheIcons; -} - -export const cache: CacheModule = {}; diff --git a/packages/core/tests/cache/basic-test.ts b/packages/core/tests/cache/basic-test.ts index 7d83208..15c286f 100644 --- a/packages/core/tests/cache/basic-test.ts +++ b/packages/core/tests/cache/basic-test.ts @@ -1,4 +1,4 @@ -import { loadBrowserStorageCache } from '../../lib/browser-storage/load'; +import { initBrowserStorage } from '../../lib/browser-storage'; import { browserStorageItemsCount, browserStorageConfig, @@ -28,7 +28,7 @@ describe('Testing mocked localStorage', () => { }); // Attempt to load - loadBrowserStorageCache(); + initBrowserStorage(); // Everything should be disabled expect(browserStorageConfig).toEqual({ @@ -59,7 +59,7 @@ describe('Testing mocked localStorage', () => { }); // Attempt to load - loadBrowserStorageCache(); + initBrowserStorage(); // sessionStorage should be disabled expect(browserStorageConfig).toEqual({ @@ -118,7 +118,7 @@ describe('Testing mocked localStorage', () => { }); // Attempt to load - loadBrowserStorageCache(); + initBrowserStorage(); // Everything should be disabled because read-only mock throws errors expect(browserStorageConfig).toEqual({ @@ -172,7 +172,7 @@ describe('Testing mocked localStorage', () => { }); // Attempt to load - loadBrowserStorageCache(); + initBrowserStorage(); // sessionStorage should be disabled expect(browserStorageConfig).toEqual({ @@ -204,7 +204,7 @@ describe('Testing mocked localStorage', () => { }); // Attempt to load - loadBrowserStorageCache(); + initBrowserStorage(); // Everything should be working expect(browserStorageConfig).toEqual({ diff --git a/packages/core/tests/cache/loading-test.ts b/packages/core/tests/cache/loading-test.ts index e795544..be9b92d 100644 --- a/packages/core/tests/cache/loading-test.ts +++ b/packages/core/tests/cache/loading-test.ts @@ -1,6 +1,6 @@ import type { IconifyJSON } from '@iconify/types'; import type { BrowserStorageItem } from '../../lib/browser-storage/types'; -import { loadBrowserStorageCache } from '../../lib/browser-storage/load'; +import { initBrowserStorage } from '../../lib/browser-storage'; import { browserStorageItemsCount, browserStorageConfig, @@ -52,7 +52,7 @@ describe('Testing loading from localStorage', () => { expect(iconExists(icons, 'foo')).toBe(false); // Load localStorage - loadBrowserStorageCache(); + initBrowserStorage(); // Icon should exist now expect(iconExists(icons, 'foo')).toBe(true); @@ -109,7 +109,7 @@ describe('Testing loading from localStorage', () => { expect(iconExists(icons2, 'foo')).toBe(false); // Load localStorage - loadBrowserStorageCache(); + initBrowserStorage(); // Icon should exist now expect(iconExists(icons, 'foo')).toBe(true); @@ -166,7 +166,7 @@ describe('Testing loading from localStorage', () => { expect(iconExists(icons, 'foo')).toBe(false); // Load localStorage - loadBrowserStorageCache(); + initBrowserStorage(); // Icon should not have loaded expect(iconExists(icons, 'foo')).toBe(false); @@ -220,7 +220,7 @@ describe('Testing loading from localStorage', () => { expect(iconExists(icons, 'foo')).toBe(false); // Load localStorage - loadBrowserStorageCache(); + initBrowserStorage(); // Icon should not have loaded expect(iconExists(icons, 'foo')).toBe(false); @@ -272,7 +272,7 @@ describe('Testing loading from localStorage', () => { expect(iconExists(icons, 'foo')).toBe(false); // Load localStorage - loadBrowserStorageCache(); + initBrowserStorage(); // Icon should not have loaded expect(iconExists(icons, 'foo')).toBe(false); @@ -324,7 +324,7 @@ describe('Testing loading from localStorage', () => { expect(iconExists(icons, 'foo')).toBe(false); // Load localStorage - loadBrowserStorageCache(); + initBrowserStorage(); // Icon should exist now expect(iconExists(icons, 'foo')).toBe(true); @@ -392,7 +392,7 @@ describe('Testing loading from localStorage', () => { expect(iconExists(icons, 'foo4')).toBe(false); // Load localStorage - loadBrowserStorageCache(); + initBrowserStorage(); // Icons should exist now expect(iconExists(icons, 'foo1')).toBe(true); @@ -476,7 +476,7 @@ describe('Testing loading from localStorage', () => { } // Load localStorage - loadBrowserStorageCache(); + initBrowserStorage(); // Icons should exist now, except for number 4 for (let i = 0; i < 6; i++) { diff --git a/packages/core/tests/cache/saving-test.ts b/packages/core/tests/cache/saving-test.ts index 070b0cd..b985b47 100644 --- a/packages/core/tests/cache/saving-test.ts +++ b/packages/core/tests/cache/saving-test.ts @@ -1,7 +1,7 @@ import type { IconifyJSON } from '@iconify/types'; import type { BrowserStorageItem } from '../../lib/browser-storage/types'; import { storeInBrowserStorage } from '../../lib/browser-storage/store'; -import { loadBrowserStorageCache } from '../../lib/browser-storage/load'; +import { initBrowserStorage } from '../../lib/browser-storage'; import { browserStorageItemsCount, browserStorageConfig, @@ -188,7 +188,7 @@ describe('Testing saving to localStorage', () => { }); // Load data - loadBrowserStorageCache(); + initBrowserStorage(); // Check data expect(browserStorageConfig).toEqual({ @@ -281,7 +281,7 @@ describe('Testing saving to localStorage', () => { }); // Load data - loadBrowserStorageCache(); + initBrowserStorage(); // Check data expect(browserStorageConfig).toEqual({ @@ -399,7 +399,7 @@ describe('Testing saving to localStorage', () => { expect(iconExists(icons, 'foo1')).toBe(false); // Load cache - loadBrowserStorageCache(); + initBrowserStorage(); expect(browserStorageConfig).toEqual({ local: true, @@ -516,7 +516,7 @@ describe('Testing saving to localStorage', () => { }); // Load data - loadBrowserStorageCache(); + initBrowserStorage(); // Check data expect(browserStorageConfig).toEqual({ @@ -631,7 +631,7 @@ describe('Testing saving to localStorage', () => { }); // Load data - loadBrowserStorageCache(); + initBrowserStorage(); // Check data expect(browserStorageConfig).toEqual({