2
0
mirror of https://github.com/iconify/iconify.git synced 2025-01-06 07:20:40 +00:00

Remove getIconFromStorage, change getIconData to return null if icon is marked as missing

This commit is contained in:
Vjacheslav Trushkin 2022-04-29 22:59:34 +03:00
parent 5967e3c469
commit 2c2a9647fa
13 changed files with 153 additions and 116 deletions

View File

@ -8,9 +8,9 @@ import type { SortedIcons } from '../icon/sort';
import { sortIcons } from '../icon/sort';
import { storeCallback, updateCallbacks } from './callbacks';
import { getAPIModule } from './modules';
import { getStorage, addIconSet, getIconFromStorage } from '../storage/storage';
import { getStorage, addIconSet } from '../storage/storage';
import { listToIcons } from '../icon/list';
import { allowSimpleNames } from '../storage/functions';
import { allowSimpleNames, getIconData } from '../storage/functions';
import { sendAPIQuery } from './query';
import { cache } from '../cache';
@ -364,10 +364,11 @@ export const loadIcon = (
const iconObj = typeof icon === 'string' ? stringToIcon(icon) : icon;
loadIcons([iconObj || icon], (loaded) => {
if (loaded.length && iconObj) {
const storage = getStorage(iconObj.provider, iconObj.prefix);
const data = getIconFromStorage(storage, iconObj.name);
const data = getIconData(iconObj);
if (data) {
fulfill(data);
fulfill({
...data,
});
return;
}
}

View File

@ -27,7 +27,7 @@ const detectFetch = (): FetchType | null => {
if (typeof callback === 'function') {
return callback;
}
} catch (err) {
} catch {
//
}

View File

@ -89,7 +89,7 @@ function getGlobal(key: keyof StorageConfig): typeof localStorage | null {
) {
return _window[attr];
}
} catch (err) {
} catch {
//
}
@ -110,9 +110,10 @@ function setCount(
storage.setItem(countKey, value.toString());
count[key] = value;
return true;
} catch (err) {
return false;
} catch {
//
}
return false;
}
/**
@ -141,7 +142,7 @@ function initCache(
): void {
try {
storage.setItem(versionKey, cacheVersion);
} catch (err) {
} catch {
//
}
setCount(storage, key, 0);
@ -158,7 +159,7 @@ function destroyCache(storage: typeof localStorage): void {
for (let i = 0; i < total; i++) {
storage.removeItem(cachePrefix + i.toString());
}
} catch (err) {
} catch {
//
}
}
@ -213,7 +214,7 @@ export const loadCache: LoadIconsCache = (): void => {
const storage = getStorage(provider, prefix);
valid = addIconSet(storage, data.data).length > 0;
}
} catch (err) {
} catch {
valid = false;
}
@ -253,7 +254,7 @@ export const loadCache: LoadIconsCache = (): void => {
// Update total
setCount(func, key, total);
} catch (err) {
} catch {
//
}
}
@ -302,7 +303,7 @@ export const storeCache: CacheIcons = (
data,
};
func.setItem(cachePrefix + index.toString(), JSON.stringify(item));
} catch (err) {
} catch {
return false;
}
return true;

View File

@ -4,12 +4,7 @@ import { parseIconSet } from '@iconify/utils/lib/icon-set/parse';
import { quicklyValidateIconSet } from '@iconify/utils/lib/icon-set/validate-basic';
import type { IconifyIconName } from '@iconify/utils/lib/icon/name';
import { stringToIcon, validateIcon } from '@iconify/utils/lib/icon/name';
import {
getStorage,
getIconFromStorage,
addIconToStorage,
addIconSet,
} from './storage';
import { getStorage, addIconToStorage, addIconSet } from './storage';
/**
* Interface for exported storage functions
@ -65,15 +60,26 @@ export function allowSimpleNames(allow?: boolean): boolean {
/**
* Get icon data
*
* Returns:
* - Required<IconifyIcon> on success, object directly from storage so don't modify it
* - null if icon is marked as missing (returned in `not_found` property from API, so don't bother sending API requests)
* - undefined if icon is missing
*/
export function getIconData(
name: string | IconifyIconName
): FullIconifyIcon | null {
): FullIconifyIcon | null | undefined {
const icon =
typeof name === 'string' ? stringToIcon(name, true, simpleNames) : name;
return icon
? getIconFromStorage(getStorage(icon.provider, icon.prefix), icon.name)
: null;
if (!icon) {
return;
}
const storage = getStorage(icon.provider, icon.prefix);
const iconName = icon.name;
return (
storage.icons[iconName] || (storage.missing[iconName] ? null : void 0)
);
}
/**
@ -143,9 +149,8 @@ export function addCollection(data: IconifyJSON, provider?: string): boolean {
* Check if icon exists
*/
export function iconExists(name: string): boolean {
return getIconData(name) !== null;
return !!getIconData(name);
}
/**
* Get icon
*/

View File

@ -47,7 +47,7 @@ try {
if (w && w._iconifyStorage.version === storageVersion) {
storage = w._iconifyStorage.storage;
}
} catch (err) {
} catch {
//
}
@ -63,7 +63,7 @@ export function shareStorage(): void {
storage,
};
}
} catch (err) {
} catch {
//
}
}
@ -128,7 +128,7 @@ export function addIconToStorage(
storage.icons[name] = Object.freeze(fullIcon(icon));
return true;
}
} catch (err) {
} catch {
// Do nothing
}
return false;
@ -141,17 +141,6 @@ export function iconExists(storage: IconStorage, name: string): boolean {
return storage.icons[name] !== void 0;
}
/**
* Get icon data
*/
export function getIconFromStorage(
storage: IconStorage,
name: string
): Readonly<FullIconifyIcon> | null {
const value = storage.icons[name];
return value === void 0 ? null : value;
}
/**
* List available icons
*/

View File

@ -1,11 +1,12 @@
import { fullIcon } from '@iconify/utils/lib/icon';
import { listIcons } from '../../lib/storage/storage';
import { addIconSet, getStorage, listIcons } from '../../lib/storage/storage';
import {
iconExists,
getIcon,
addIcon,
addCollection,
allowSimpleNames,
getIconData,
} from '../../lib/storage/functions';
describe('Testing IconifyStorageFunctions', () => {
@ -15,6 +16,13 @@ describe('Testing IconifyStorageFunctions', () => {
return 'storage-test-' + (count++).toString();
}
beforeEach(() => {
allowSimpleNames(false);
});
afterAll(() => {
allowSimpleNames(false);
});
it('Storage functions', () => {
const provider = nextProvider();
const testName = `@${provider}:foo:bar`;
@ -22,6 +30,7 @@ describe('Testing IconifyStorageFunctions', () => {
// Empty
expect(iconExists(testName)).toBe(false);
expect(getIcon(testName)).toBeNull();
expect(getIconData(testName)).toBeUndefined();
expect(listIcons(provider)).toEqual([]);
// Add and test one icon
@ -32,17 +41,52 @@ describe('Testing IconifyStorageFunctions', () => {
).toBe(true);
expect(iconExists(testName)).toBe(true);
expect(listIcons(provider)).toEqual([testName]);
let expected = fullIcon({
body: '<g />',
});
expect(getIconData(testName)).toEqual(expected);
expect(getIcon(testName)).toEqual(expected);
// Add icon set
const prefix = 'prefix' + (count++).toString();
const storage = getStorage('', prefix);
addIconSet(storage, {
prefix,
icons: {
home: {
body: '<g id="home" />',
},
},
not_found: ['missing'],
});
// Test 'home' icon
expect(iconExists(`${prefix}:home`)).toBe(true);
expected = fullIcon({
body: '<g id="home" />',
});
expect(getIconData(`${prefix}:home`)).toEqual(expected);
expect(getIcon(`${prefix}:home`)).toEqual(expected);
// Test 'missing' icon
expect(iconExists(`${prefix}:missing`)).toBe(false);
expect(getIconData(`${prefix}:missing`)).toBeNull();
expect(getIcon(`${prefix}:missing`)).toBeNull();
// Test 'invalid' icon
expect(iconExists(`${prefix}:invalid`)).toBe(false);
expect(getIconData(`${prefix}:invalid`)).toBeUndefined();
expect(getIcon(`${prefix}:invalid`)).toBeNull();
});
it('Invalid icon name', () => {
const testName = 'storage' + (count++).toString();
// Reset module
allowSimpleNames(false);
// Empty
expect(iconExists(testName)).toBe(false);
expect(getIcon(testName)).toBeNull();
expect(getIconData(testName)).toBeUndefined();
// Add and test one icon (icon should not be added)
expect(
@ -54,9 +98,6 @@ describe('Testing IconifyStorageFunctions', () => {
});
it('Invalid icon set', () => {
// Reset module
allowSimpleNames(false);
// Icon set without prefix (should work only when simple names are allowed, tested later in this file)
expect(
addCollection({
@ -87,9 +128,6 @@ describe('Testing IconifyStorageFunctions', () => {
})
).toBe(true);
expect(iconExists(testName)).toBe(true);
// Reset config after test
allowSimpleNames(false);
});
it('Collection with simple icon name', () => {
@ -104,6 +142,7 @@ describe('Testing IconifyStorageFunctions', () => {
const name1 = 'test' + n.toString();
const prefix2 = `prefixed${n}`;
const name2 = `icon${n2}`;
const missing = `missing${n}`;
expect(
addCollection({
prefix: '',
@ -115,38 +154,41 @@ describe('Testing IconifyStorageFunctions', () => {
body: '<g data-icon="prefixed-icon" />',
},
},
not_found: [missing],
})
).toBe(true);
// Test 'test'
name = name1;
expect(iconExists(name)).toBe(true);
expect(getIcon(name)).toEqual(
fullIcon({
body: '<g data-icon="basic-icon" />',
})
);
let expected = fullIcon({
body: '<g data-icon="basic-icon" />',
});
expect(getIcon(name)).toEqual(expected);
expect(getIconData(name)).toEqual(expected);
// Test prefixed icon, using ':' separator
name = `${prefix2}:${name2}`;
expect(listIcons('', prefix2)).toEqual([name]);
expect(iconExists(name)).toBe(true);
expect(getIcon(name)).toEqual(
fullIcon({
body: '<g data-icon="prefixed-icon" />',
})
);
expected = fullIcon({
body: '<g data-icon="prefixed-icon" />',
});
expect(getIcon(name)).toEqual(expected);
expect(getIconData(name)).toEqual(expected);
// Test prefixed icon, using '-' separator
name = `${prefix2}-${name2}`;
expect(iconExists(name)).toBe(true);
expect(getIcon(name)).toEqual(
fullIcon({
body: '<g data-icon="prefixed-icon" />',
})
);
expected = fullIcon({
body: '<g data-icon="prefixed-icon" />',
});
expect(getIcon(name)).toEqual(expected);
expect(getIconData(name)).toEqual(expected);
// Reset config after test
allowSimpleNames(false);
// Test missing icon: should not exist because without provider missing icon cannot be added
expect(iconExists(missing)).toBe(false);
expect(getIcon(missing)).toBeNull();
expect(getIconData(missing)).toBeUndefined();
});
});

View File

@ -3,7 +3,6 @@ import {
newStorage,
addIconToStorage,
iconExists,
getIconFromStorage,
addIconSet,
getStorage,
listIcons,
@ -65,7 +64,7 @@ describe('Testing storage', () => {
vFlip: false,
rotate: 0,
};
const icon = getIconFromStorage(storage, 'test');
const icon = storage.icons['test'];
expect(icon).toEqual(expected);
// Test icon mutation
@ -88,10 +87,9 @@ describe('Testing storage', () => {
vFlip: false,
rotate: 1,
};
expect(getIconFromStorage(storage, 'constructor')).toEqual(expected);
expect(storage.icons['constructor']).toEqual(expected);
expect(getIconFromStorage(storage, 'invalid')).toBeNull();
expect(getIconFromStorage(storage, 'missing')).toBeNull();
expect(storage.icons['invalid']).toBeUndefined();
});
it('Adding simple icon set', () => {
@ -134,7 +132,7 @@ describe('Testing storage', () => {
vFlip: false,
rotate: 0,
};
expect(getIconFromStorage(storage, 'icon1')).toEqual(expected);
expect(storage.icons['icon1']).toEqual(expected);
expected = {
body: '<path d="icon2" />',
width: 24,
@ -145,9 +143,7 @@ describe('Testing storage', () => {
vFlip: false,
rotate: 0,
};
expect(getIconFromStorage(storage, 'icon2')).toEqual(expected);
expect(getIconFromStorage(storage, 'invalid')).toBeNull();
expect(getIconFromStorage(storage, 'missing')).toBeNull();
expect(storage.icons['icon2']).toEqual(expected);
});
it('Icon set with aliases that use transformations', () => {
@ -190,9 +186,7 @@ describe('Testing storage', () => {
vFlip: false,
rotate: 0,
};
expect(getIconFromStorage(storage, '16-chevron-left')).toEqual(
expected
);
expect(storage.icons['16-chevron-left']).toEqual(expected);
// Test alias
expected = {
@ -205,9 +199,7 @@ describe('Testing storage', () => {
vFlip: false,
rotate: 0,
};
expect(getIconFromStorage(storage, '16-chevron-right')).toEqual(
expected
);
expect(storage.icons['16-chevron-right']).toEqual(expected);
});
it('List icons in a global storage', () => {

View File

@ -1,7 +1,4 @@
import {
getIconFromStorage,
getStorage,
} from '@iconify/core/lib/storage/storage';
import { getStorage } from '@iconify/core/lib/storage/storage';
import { isPending, loadIcons } from '@iconify/core/lib/api/icons';
import { findRootNode, listRootNodes } from '../observer/root';
import type { ObservedNode } from '../observer/types';
@ -65,10 +62,11 @@ export function scanDOM(rootNode?: ObservedNode, addTempNode = false): void {
const { provider, prefix, name } = icon;
const storage = getStorage(provider, prefix);
if (storage.icons[name]) {
const storedIcon = storage.icons[name];
if (storedIcon) {
return {
status: 'loaded',
icon: getIconFromStorage(storage, name),
icon: storedIcon,
};
}

View File

@ -4,7 +4,7 @@ import { addAPIProvider } from '@iconify/core/lib/api/config';
import { setAPIModule } from '@iconify/core/lib/api/modules';
import { removeRootNode, listRootNodes } from '../src/observer/root';
import { onReady } from '../src/helpers/ready';
import { stopObserver, stopObserving } from '../src/observer';
import { stopObserver } from '../src/observer';
/**
* Generate next prefix

View File

@ -316,20 +316,23 @@ class IconComponent extends React.Component<
// Load icon
const data = getIconData(iconName);
if (data === null) {
// Icon needs to be loaded
if (!data) {
// Icon data is not available
if (!this._loading || this._loading.name !== icon) {
// New icon to load
this._abortLoading();
this._icon = '';
this._setData(null);
this._loading = {
name: icon,
abort: loadIcons(
[iconName],
this._checkIcon.bind(this, false)
),
};
if (data !== null) {
// Icon was not loaded
this._loading = {
name: icon,
abort: loadIcons(
[iconName],
this._checkIcon.bind(this, false)
),
};
}
}
return;
}

View File

@ -293,8 +293,8 @@ export function checkIconState(
// Load icon
const data = getIconData(iconName);
if (data === null) {
// Icon needs to be loaded
if (!data) {
// Icon data is not available
// Do not load icon until component is mounted
if (mounted && (!state.loading || state.loading.name !== icon)) {
// New icon to load

View File

@ -311,18 +311,21 @@ export const Icon = defineComponent({
// Load icon
const data = getIconData(iconName);
if (data === null) {
// Icon needs to be loaded
if (!data) {
// Icon data is not available
if (!this._loadingIcon || this._loadingIcon.name !== icon) {
// New icon to load
this.abortLoading();
this._name = '';
this._loadingIcon = {
name: icon,
abort: loadIcons([iconName], () => {
this.counter++;
}),
};
if (data !== null) {
// Icon was not loaded
this._loadingIcon = {
name: icon,
abort: loadIcons([iconName], () => {
this.counter++;
}),
};
}
}
return null;
}

View File

@ -297,18 +297,21 @@ export const Icon = Vue.extend({
// Load icon
const data = getIconData(iconName);
if (data === null) {
// Icon needs to be loaded
if (!data) {
// Icon data is not available
if (!this._loadingIcon || this._loadingIcon.name !== icon) {
// New icon to load
this.abortLoading();
this._name = '';
this._loadingIcon = {
name: icon,
abort: loadIcons([iconName], () => {
this.$forceUpdate();
}),
};
if (data !== null) {
// Icon was not loaded
this._loadingIcon = {
name: icon,
abort: loadIcons([iconName], () => {
this.$forceUpdate();
}),
};
}
}
return null;
}