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

Replace unnecessary complex icon set validation function with basic function

This commit is contained in:
Vjacheslav Trushkin 2022-03-31 11:07:02 +03:00
parent 0f21f877b8
commit 19e951cdb7
11 changed files with 285 additions and 71 deletions

View File

@ -1,6 +1,7 @@
import type { IconifyJSON, IconifyIcon } from '@iconify/types';
import type { FullIconifyIcon } from '@iconify/utils/lib/icon';
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 {
@ -108,21 +109,17 @@ export function addCollection(data: IconifyJSON, provider?: string): boolean {
) {
// Simple names: add icons one by one
let added = false;
parseIconSet(
data,
(name, icon) => {
if (quicklyValidateIconSet(data)) {
// Reset prefix
data.prefix = '';
parseIconSet(data, (name, icon) => {
if (icon && addIcon(name, icon)) {
added = true;
}
},
{
// Validate icon set and set prefix to empty
validate: {
fix: true,
prefix: '',
},
}
);
});
}
return added;
}

View File

@ -2,6 +2,7 @@ import type { IconifyJSON, IconifyIcon } from '@iconify/types';
import type { FullIconifyIcon } from '@iconify/utils/lib/icon';
import { fullIcon } from '@iconify/utils/lib/icon';
import { parseIconSet } from '@iconify/utils/lib/icon-set/parse';
import { quicklyValidateIconSet } from '@iconify/utils/lib/icon-set/validate-basic';
/**
* List of icons
@ -99,6 +100,10 @@ export function getStorage(provider: string, prefix: string): IconStorage {
* Returns array of added icons
*/
export function addIconSet(storage: IconStorage, data: IconifyJSON): string[] {
if (!quicklyValidateIconSet(data)) {
return [];
}
const t = Date.now();
return parseIconSet(data, (name, icon: FullIconifyIcon | null) => {
if (icon) {

View File

@ -7,6 +7,7 @@ import type {
} from '@iconify/utils/lib/customisations';
import { fullIcon } from '@iconify/utils/lib/icon';
import { parseIconSet } from '@iconify/utils/lib/icon-set/parse';
import { quicklyValidateIconSet } from '@iconify/utils/lib/icon-set/validate-basic';
import type {
IconifyIconCustomisations,
IconifyIconProps,
@ -116,19 +117,11 @@ export function addCollection(
: prefix !== false && typeof data.prefix === 'string'
? data.prefix + ':'
: '';
parseIconSet(
data,
(name, icon) => {
quicklyValidateIconSet(data) &&
parseIconSet(data, (name, icon) => {
if (icon) {
storage[iconPrefix + name] = icon;
}
},
{
// Allow empty prefix
validate: {
fix: true,
prefix: iconPrefix,
},
}
);
});
}

View File

@ -1,6 +1,7 @@
import type { IconifyIcon, IconifyJSON } from '@iconify/types';
import { fullIcon } from '@iconify/utils/lib/icon';
import { parseIconSet } from '@iconify/utils/lib/icon-set/parse';
import { quicklyValidateIconSet } from '@iconify/utils/lib/icon-set/validate-basic';
import { render } from './render';
import type { RenderResult } from './render';
import type { IconProps } from './props';
@ -60,19 +61,10 @@ export function addCollection(
: prefix !== false && typeof data.prefix === 'string'
? data.prefix + ':'
: '';
parseIconSet(
data,
(name, icon) => {
quicklyValidateIconSet(data) &&
parseIconSet(data, (name, icon) => {
if (icon) {
storage[iconPrefix + name] = icon;
}
},
{
// Allow empty prefix
validate: {
fix: true,
prefix: iconPrefix,
},
}
);
});
}

View File

@ -102,6 +102,10 @@
"require": "./lib/icon-set/validate.cjs",
"import": "./lib/icon-set/validate.mjs"
},
"./lib/icon-set/validate-basic": {
"require": "./lib/icon-set/validate-basic.cjs",
"import": "./lib/icon-set/validate-basic.mjs"
},
"./lib/icon": {
"require": "./lib/icon/index.cjs",
"import": "./lib/icon/index.mjs"

View File

@ -1,7 +1,6 @@
import type { IconifyAlias, IconifyJSON } from '@iconify/types';
import { FullIconifyIcon, iconDefaults } from '../icon';
import { getIconData } from './get-icon';
import { IconSetValidationOptions, validateIconSet } from './validate';
/**
* Which aliases to parse:
@ -35,7 +34,6 @@ export function isVariation(item: IconifyAlias): boolean {
}
export interface ParseIconSetOptions {
validate?: boolean | IconSetValidationOptions;
aliases?: ParseIconSetAliases;
}
@ -59,20 +57,6 @@ export function parseIconSet(
return names;
}
// Validate icon set
const validate = options.validate;
if (validate !== false) {
// Validate icon set
try {
validateIconSet(
data,
typeof validate === 'object' ? validate : { fix: true }
);
} catch (err) {
return names;
}
}
// Check for missing icons list returned by API
if (data.not_found instanceof Array) {
data.not_found.forEach((name) => {

View File

@ -0,0 +1,99 @@
import type { IconifyJSON } from '@iconify/types';
import { iconDefaults, matchName } from '../icon';
/**
* Optional properties
*/
const optionalProperties = {
provider: 'string',
aliases: 'object',
not_found: 'object',
} as Record<string, string>;
for (const prop in iconDefaults) {
optionalProperties[prop] =
typeof iconDefaults[prop as keyof typeof iconDefaults];
}
/**
* Validate icon set, return it as IconifyJSON on success, null on failure
*
* Unlike validateIconSet(), this function is very basic.
* It does not throw exceptions, it does not check metadata, it does not fix stuff.
*/
export function quicklyValidateIconSet(obj: unknown): IconifyJSON | null {
// Check for object with 'icons' nested object
if (typeof obj !== 'object' || obj === null) {
return null;
}
// Convert type
const data = obj as IconifyJSON;
// Check for prefix and icons
if (
typeof data.prefix !== 'string' ||
!(obj as Record<string, unknown>).icons ||
typeof (obj as Record<string, unknown>).icons !== 'object'
) {
return null;
}
// Check for optional properties
for (const prop in optionalProperties) {
if (
(obj as Record<string, unknown>)[prop] !== void 0 &&
typeof (obj as Record<string, unknown>)[prop] !==
optionalProperties[prop]
) {
return null;
}
}
// Check all icons
const icons = data.icons;
for (const name in icons) {
const icon = icons[name];
if (!name.match(matchName) || typeof icon.body !== 'string') {
return null;
}
for (const prop in iconDefaults) {
if (
icon[prop as keyof typeof icon] !== void 0 &&
typeof icon[prop as keyof typeof icon] !==
typeof iconDefaults[prop as keyof typeof iconDefaults]
) {
return null;
}
}
}
// Check all aliases
const aliases = data.aliases;
if (aliases) {
for (const name in aliases) {
const icon = aliases[name];
const parent = icon.parent;
if (
!name.match(matchName) ||
typeof parent !== 'string' ||
(!icons[parent] && !aliases[parent])
) {
return null;
}
for (const prop in iconDefaults) {
if (
icon[prop as keyof typeof icon] !== void 0 &&
typeof icon[prop as keyof typeof icon] !==
typeof iconDefaults[prop as keyof typeof iconDefaults]
) {
return null;
}
}
}
}
return data;
}

View File

@ -27,6 +27,7 @@ export {
// Icon set functions
export { parseIconSet, isVariation } from './icon-set/parse';
export { validateIconSet } from './icon-set/validate';
export { quicklyValidateIconSet } from './icon-set/validate-basic';
export { expandIconSet } from './icon-set/expand';
export { minifyIconSet } from './icon-set/minify';
export { getIcons } from './icon-set/get-icons';

View File

@ -0,0 +1,152 @@
import { quicklyValidateIconSet } from '../lib/icon-set/validate-basic';
describe('Testing validation', () => {
test('Not object', () => {
expect(quicklyValidateIconSet(void 0)).toBe(null);
expect(quicklyValidateIconSet({})).toBe(null);
expect(quicklyValidateIconSet(null)).toBe(null);
expect(quicklyValidateIconSet([])).toBe(null);
});
test('Valid sets', () => {
expect(
quicklyValidateIconSet({
prefix: 'foo',
icons: {
bar: {
body: '<g />',
},
},
width: 24,
height: 24,
})
).toEqual({
prefix: 'foo',
icons: {
bar: {
body: '<g />',
},
},
width: 24,
height: 24,
});
expect(
quicklyValidateIconSet({
prefix: 'foo',
icons: {
bar: {
body: '<g />',
width: 32,
height: 32,
rotate: 0,
hFlip: false,
vFlip: true,
// Legacy property
verticalAlign: -0.14,
},
},
aliases: {
baz: {
parent: 'bar',
hFlip: true,
},
},
width: 24,
height: 24,
})
).toEqual({
prefix: 'foo',
icons: {
bar: {
body: '<g />',
width: 32,
height: 32,
rotate: 0,
hFlip: false,
vFlip: true,
verticalAlign: -0.14,
},
},
aliases: {
baz: {
parent: 'bar',
hFlip: true,
},
},
width: 24,
height: 24,
});
// Empty is allowed
expect(
quicklyValidateIconSet({
prefix: 'foo',
icons: {},
})
).toEqual({
prefix: 'foo',
icons: {},
});
});
test('Missing required properties', () => {
expect(
quicklyValidateIconSet({
prefix: 'foo',
})
).toBe(null);
expect(
quicklyValidateIconSet({
icons: {},
})
).toBe(null);
});
test('Invalid optional properties', () => {
expect(
quicklyValidateIconSet({
prefix: 'foo',
icons: {
icon1: {
body: '<path d="icon1" />',
},
},
height: 24,
// Object
rotate: {
foo: 1,
},
})
).toBe(null);
expect(
quicklyValidateIconSet({
prefix: 'foo',
icons: {
icon1: {
body: '<path d="icon1" />',
},
},
height: 24,
// Object
hFlip: null,
})
).toBe(null);
expect(
quicklyValidateIconSet({
prefix: 'foo',
icons: {
icon1: {
body: '<path d="icon1" />',
},
},
height: 24,
// String
width: '32',
})
).toBe(null);
});
});

View File

@ -16,6 +16,7 @@ import type {
} from '@iconify/utils/lib/customisations';
import { fullIcon } from '@iconify/utils/lib/icon';
import { parseIconSet } from '@iconify/utils/lib/icon-set/parse';
import { quicklyValidateIconSet } from '@iconify/utils/lib/icon-set/validate-basic';
import type {
IconifyIconCustomisations,
IconifyIconProps,
@ -70,21 +71,12 @@ export function addCollection(
: prefix !== false && typeof data.prefix === 'string'
? data.prefix + ':'
: '';
parseIconSet(
data,
(name, icon) => {
quicklyValidateIconSet(data) &&
parseIconSet(data, (name, icon) => {
if (icon) {
storage[iconPrefix + name] = icon;
}
},
{
// Allow empty prefix
validate: {
fix: true,
prefix: iconPrefix,
},
}
);
});
}
/**

View File

@ -9,6 +9,7 @@ import type {
} from '@iconify/utils/lib/customisations';
import { fullIcon } from '@iconify/utils/lib/icon';
import { parseIconSet } from '@iconify/utils/lib/icon-set/parse';
import { quicklyValidateIconSet } from '@iconify/utils/lib/icon-set/validate-basic';
import type {
IconifyIconCustomisations,
IconifyIconProps,
@ -63,16 +64,10 @@ export function addCollection(
: prefix !== false && typeof data.prefix === 'string'
? data.prefix + ':'
: '';
parseIconSet(data, (name, icon) => {
quicklyValidateIconSet(data) && parseIconSet(data, (name, icon) => {
if (icon) {
storage[iconPrefix + name] = icon;
}
}, {
// Allow empty prefix
validate: {
fix: true,
prefix: iconPrefix,
},
});
}