mirror of
https://github.com/iconify/iconify.git
synced 2024-12-04 18:23:17 +00:00
feat(utils): do not force naming convension when validating icon sets and icon names
This commit is contained in:
parent
c5d1a469d1
commit
3ae86d5f0d
@ -1,5 +1,4 @@
|
||||
import type { IconifyAliases, IconifyJSON } from '@iconify/types';
|
||||
import { matchIconName } from '../icon/name';
|
||||
import {
|
||||
defaultIconDimensions,
|
||||
defaultExtendedIconProps,
|
||||
@ -63,8 +62,11 @@ export function quicklyValidateIconSet(obj: unknown): IconifyJSON | null {
|
||||
for (const name in icons) {
|
||||
const icon = icons[name];
|
||||
if (
|
||||
!name.match(matchIconName) ||
|
||||
// Name cannot be empty
|
||||
!name ||
|
||||
// Must have body
|
||||
typeof icon.body !== 'string' ||
|
||||
// Check other props
|
||||
!checkOptionalProps(
|
||||
icon as unknown as PropsList,
|
||||
defaultExtendedIconProps
|
||||
@ -80,9 +82,12 @@ export function quicklyValidateIconSet(obj: unknown): IconifyJSON | null {
|
||||
const icon = aliases[name];
|
||||
const parent = icon.parent;
|
||||
if (
|
||||
!name.match(matchIconName) ||
|
||||
// Name cannot be empty
|
||||
!name ||
|
||||
// Parent must be set and point to existing icon
|
||||
typeof parent !== 'string' ||
|
||||
(!icons[parent] && !aliases[parent]) ||
|
||||
// Check other props
|
||||
!checkOptionalProps(
|
||||
icon as unknown as PropsList,
|
||||
defaultExtendedIconProps
|
||||
|
@ -4,7 +4,6 @@ import type {
|
||||
IconifyJSON,
|
||||
IconifyOptional,
|
||||
} from '@iconify/types';
|
||||
import { matchIconName } from '../icon/name';
|
||||
import { defaultExtendedIconProps } from '../icon/defaults';
|
||||
import { getIconsTree } from './tree';
|
||||
|
||||
@ -99,8 +98,9 @@ export function validateIconSet(
|
||||
if (options && typeof options.prefix === 'string') {
|
||||
data.prefix = options.prefix;
|
||||
} else if (
|
||||
// Prefix must be a string and not empty
|
||||
typeof data.prefix !== 'string' ||
|
||||
!data.prefix.match(matchIconName)
|
||||
!data.prefix
|
||||
) {
|
||||
throw new Error('Invalid prefix');
|
||||
}
|
||||
@ -110,10 +110,7 @@ export function validateIconSet(
|
||||
data.provider = options.provider;
|
||||
} else if (data.provider !== void 0) {
|
||||
const value = data.provider;
|
||||
if (
|
||||
typeof value !== 'string' ||
|
||||
(value !== '' && !value.match(matchIconName))
|
||||
) {
|
||||
if (typeof value !== 'string') {
|
||||
if (fix) {
|
||||
delete data.provider;
|
||||
} else {
|
||||
@ -150,7 +147,7 @@ export function validateIconSet(
|
||||
throw new Error(`Invalid alias: ${name}`);
|
||||
}
|
||||
|
||||
if (!name.match(matchIconName)) {
|
||||
if (!name) {
|
||||
if (fix) {
|
||||
delete parentObj[name];
|
||||
continue;
|
||||
|
@ -14,11 +14,14 @@ export type IconifyIconSource = Omit<IconifyIconName, 'name'>;
|
||||
|
||||
/**
|
||||
* Expression to test part of icon name.
|
||||
*
|
||||
* Used when loading icons from Iconify API due to project naming convension.
|
||||
* Ignored when using custom icon sets - convension does not apply.
|
||||
*/
|
||||
export const matchIconName = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
||||
|
||||
/**
|
||||
* Convert string to Icon object.
|
||||
* Convert string icon name to IconifyIconName object.
|
||||
*/
|
||||
export const stringToIcon = (
|
||||
value: string,
|
||||
@ -96,9 +99,11 @@ export const validateIconName = (
|
||||
}
|
||||
|
||||
return !!(
|
||||
(icon.provider === '' || icon.provider.match(matchIconName)) &&
|
||||
((allowSimpleName && icon.prefix === '') ||
|
||||
icon.prefix.match(matchIconName)) &&
|
||||
icon.name.match(matchIconName)
|
||||
// Check prefix: cannot be empty, unless allowSimpleName is enabled
|
||||
// Check name: cannot be empty
|
||||
(
|
||||
((allowSimpleName && icon.prefix === '') || !!icon.prefix) &&
|
||||
!!icon.name
|
||||
)
|
||||
);
|
||||
};
|
||||
|
@ -58,7 +58,7 @@ describe('Testing icon name', () => {
|
||||
expect(validateIconName(icon)).toBe(false);
|
||||
expect(validateIconName(icon, true)).toBe(false);
|
||||
|
||||
// Underscore is not an acceptable separator
|
||||
// No prefix
|
||||
icon = stringToIcon('fa_home');
|
||||
expect(icon).toEqual(null);
|
||||
expect(validateIconName(icon)).toBe(false);
|
||||
@ -71,30 +71,30 @@ describe('Testing icon name', () => {
|
||||
name: 'fa_home',
|
||||
});
|
||||
expect(validateIconName(icon)).toBe(false);
|
||||
expect(validateIconName(icon, true)).toBe(false);
|
||||
expect(validateIconName(icon, true)).toBe(true);
|
||||
|
||||
// Invalid character '_': fail validateIcon
|
||||
// Underscore is allowed now
|
||||
icon = stringToIcon('fa:home_outline') as IconifyIconName;
|
||||
expect(icon).toEqual({
|
||||
provider: '',
|
||||
prefix: 'fa',
|
||||
name: 'home_outline',
|
||||
});
|
||||
expect(validateIconName(icon)).toBe(false);
|
||||
expect(validateIconName(icon)).toBe(true);
|
||||
|
||||
// Too many colons: fail stringToIcon
|
||||
icon = stringToIcon('mdi:light:home:outline');
|
||||
expect(icon).toEqual(null);
|
||||
expect(validateIconName(icon)).toBe(false);
|
||||
|
||||
// Upper case: fail validateIcon
|
||||
// Upper case: allowed now
|
||||
icon = stringToIcon('MD:Home') as IconifyIconName;
|
||||
expect(icon).toEqual({
|
||||
provider: '',
|
||||
prefix: 'MD',
|
||||
name: 'Home',
|
||||
});
|
||||
expect(validateIconName(icon)).toBe(false);
|
||||
expect(validateIconName(icon)).toBe(true);
|
||||
|
||||
// Numbers: pass
|
||||
icon = stringToIcon('1:foo') as IconifyIconName;
|
||||
@ -105,14 +105,14 @@ describe('Testing icon name', () => {
|
||||
});
|
||||
expect(validateIconName(icon)).toBe(true);
|
||||
|
||||
// Accented letters: fail validateIcon
|
||||
// Accented letters: allowed now
|
||||
icon = stringToIcon('md-fõö') as IconifyIconName;
|
||||
expect(icon).toEqual({
|
||||
provider: '',
|
||||
prefix: 'md',
|
||||
name: 'fõö',
|
||||
});
|
||||
expect(validateIconName(icon)).toBe(false);
|
||||
expect(validateIconName(icon)).toBe(true);
|
||||
});
|
||||
|
||||
it('Providers', () => {
|
||||
@ -167,13 +167,13 @@ describe('Testing icon name', () => {
|
||||
icon = stringToIcon('@mdi:light:home:outline', false, true);
|
||||
expect(icon).toEqual(null);
|
||||
|
||||
// Upper case: fail validateIcon
|
||||
// Upper case: allowed now
|
||||
icon = stringToIcon('@MD:home-outline') as IconifyIconName;
|
||||
expect(icon).toEqual({
|
||||
provider: 'MD',
|
||||
prefix: 'home',
|
||||
name: 'outline',
|
||||
});
|
||||
expect(validateIconName(icon)).toBe(false);
|
||||
expect(validateIconName(icon)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
@ -33,9 +33,11 @@ describe('Testing validation', () => {
|
||||
|
||||
expect(
|
||||
quicklyValidateIconSet({
|
||||
prefix: 'foo',
|
||||
// Characters that used to be invalid
|
||||
prefix: 'fòó_bār',
|
||||
icons: {
|
||||
bar: {
|
||||
// Characters that used to be invalid
|
||||
bär: {
|
||||
body: '<g />',
|
||||
width: 32,
|
||||
height: 32,
|
||||
@ -47,8 +49,9 @@ describe('Testing validation', () => {
|
||||
},
|
||||
},
|
||||
aliases: {
|
||||
baz: {
|
||||
parent: 'bar',
|
||||
// Characters that used to be invalid
|
||||
Bär_Bāz: {
|
||||
parent: 'bär',
|
||||
hFlip: true,
|
||||
},
|
||||
},
|
||||
@ -56,9 +59,9 @@ describe('Testing validation', () => {
|
||||
height: 24,
|
||||
})
|
||||
).toEqual({
|
||||
prefix: 'foo',
|
||||
prefix: 'fòó_bār',
|
||||
icons: {
|
||||
bar: {
|
||||
bär: {
|
||||
body: '<g />',
|
||||
width: 32,
|
||||
height: 32,
|
||||
@ -69,8 +72,8 @@ describe('Testing validation', () => {
|
||||
},
|
||||
},
|
||||
aliases: {
|
||||
baz: {
|
||||
parent: 'bar',
|
||||
Bär_Bāz: {
|
||||
parent: 'bär',
|
||||
hFlip: true,
|
||||
},
|
||||
},
|
||||
@ -104,6 +107,19 @@ describe('Testing validation', () => {
|
||||
).toBe(null);
|
||||
});
|
||||
|
||||
test('Empty icon name', () => {
|
||||
expect(
|
||||
quicklyValidateIconSet({
|
||||
prefix: 'foo',
|
||||
icons: {
|
||||
'': {
|
||||
body: '<g />',
|
||||
},
|
||||
},
|
||||
})
|
||||
).toBe(null);
|
||||
});
|
||||
|
||||
test('Invalid optional properties', () => {
|
||||
expect(
|
||||
quicklyValidateIconSet({
|
||||
|
@ -5,7 +5,7 @@ describe('Testing validation', () => {
|
||||
return new Promise((fulfill, reject) => {
|
||||
try {
|
||||
validateIconSet(void 0);
|
||||
reject('Expected to throw error on undefined');
|
||||
reject(new Error('Expected to throw error on undefined'));
|
||||
return;
|
||||
} catch {
|
||||
//
|
||||
@ -13,7 +13,7 @@ describe('Testing validation', () => {
|
||||
|
||||
try {
|
||||
validateIconSet({});
|
||||
reject('Expected to throw error on empty object');
|
||||
reject(new Error('Expected to throw error on empty object'));
|
||||
return;
|
||||
} catch {
|
||||
//
|
||||
@ -21,7 +21,7 @@ describe('Testing validation', () => {
|
||||
|
||||
try {
|
||||
validateIconSet(null);
|
||||
reject('Expected to throw error on null');
|
||||
reject(new Error('Expected to throw error on null'));
|
||||
return;
|
||||
} catch {
|
||||
//
|
||||
@ -29,7 +29,7 @@ describe('Testing validation', () => {
|
||||
|
||||
try {
|
||||
validateIconSet([]);
|
||||
reject('Expected to throw error on array');
|
||||
reject(new Error('Expected to throw error on array'));
|
||||
return;
|
||||
} catch {
|
||||
//
|
||||
@ -42,19 +42,74 @@ describe('Testing validation', () => {
|
||||
test('Valid set', () => {
|
||||
expect(
|
||||
validateIconSet({
|
||||
prefix: 'foo',
|
||||
prefix: 'fòó_bār',
|
||||
icons: {
|
||||
bar: {
|
||||
body: '<g />',
|
||||
},
|
||||
// Characters that used to be invalid
|
||||
fòó_: {
|
||||
body: '<g />',
|
||||
},
|
||||
},
|
||||
})
|
||||
).toEqual({
|
||||
prefix: 'foo',
|
||||
prefix: 'fòó_bār',
|
||||
icons: {
|
||||
bar: {
|
||||
body: '<g />',
|
||||
},
|
||||
fòó_: {
|
||||
body: '<g />',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('Bad icon names', () => {
|
||||
// Empty name, not fixed
|
||||
let threw = false;
|
||||
try {
|
||||
validateIconSet({
|
||||
prefix: 'foo',
|
||||
icons: {
|
||||
// Cannot be empty
|
||||
'': {
|
||||
body: '<g />',
|
||||
},
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
threw = true;
|
||||
}
|
||||
expect(threw).toBeTruthy();
|
||||
|
||||
// Empty name, fixed
|
||||
expect(
|
||||
validateIconSet(
|
||||
{
|
||||
prefix: 'foo',
|
||||
icons: {
|
||||
// Empty name
|
||||
'': {
|
||||
body: '<g />',
|
||||
},
|
||||
// Characters that used to be invalid
|
||||
'fòó_': {
|
||||
body: '<g />',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
fix: true,
|
||||
}
|
||||
)
|
||||
).toEqual({
|
||||
prefix: 'foo',
|
||||
icons: {
|
||||
fòó_: {
|
||||
body: '<g />',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
@ -65,7 +120,9 @@ describe('Testing validation', () => {
|
||||
validateIconSet({
|
||||
prefix: 'foo',
|
||||
});
|
||||
reject('Expected to throw error when icons are missing');
|
||||
reject(
|
||||
new Error('Expected to throw error when icons are missing')
|
||||
);
|
||||
return;
|
||||
} catch {
|
||||
//
|
||||
@ -76,7 +133,9 @@ describe('Testing validation', () => {
|
||||
prefix: 'foo',
|
||||
icons: {},
|
||||
});
|
||||
reject('Expected to throw error when icons are empty');
|
||||
reject(
|
||||
new Error('Expected to throw error when icons are empty')
|
||||
);
|
||||
return;
|
||||
} catch {
|
||||
//
|
||||
@ -84,7 +143,7 @@ describe('Testing validation', () => {
|
||||
|
||||
try {
|
||||
validateIconSet([]);
|
||||
reject('Expected to throw error on array');
|
||||
reject(new Error('Expected to throw error on array'));
|
||||
return;
|
||||
} catch {
|
||||
//
|
||||
@ -149,7 +208,9 @@ describe('Testing validation', () => {
|
||||
},
|
||||
});
|
||||
reject(
|
||||
'Expected to throw error when character points to missing icon'
|
||||
new Error(
|
||||
'Expected to throw error when character points to missing icon'
|
||||
)
|
||||
);
|
||||
return;
|
||||
} catch {
|
||||
@ -193,7 +254,11 @@ describe('Testing validation', () => {
|
||||
test: 'bar',
|
||||
},
|
||||
});
|
||||
reject('Expected to throw error when character is invalid');
|
||||
reject(
|
||||
new Error(
|
||||
'Expected to throw error when character is invalid'
|
||||
)
|
||||
);
|
||||
return;
|
||||
} catch {
|
||||
//
|
||||
@ -253,7 +318,11 @@ describe('Testing validation', () => {
|
||||
},
|
||||
{ fix: true }
|
||||
);
|
||||
reject('Expected to throw error for bad default properties');
|
||||
reject(
|
||||
new Error(
|
||||
'Expected to throw error for bad default properties'
|
||||
)
|
||||
);
|
||||
return;
|
||||
} catch {
|
||||
//
|
||||
@ -274,7 +343,11 @@ describe('Testing validation', () => {
|
||||
},
|
||||
{ fix: true }
|
||||
);
|
||||
reject('Expected to throw error for bad default properties');
|
||||
reject(
|
||||
new Error(
|
||||
'Expected to throw error for bad default properties'
|
||||
)
|
||||
);
|
||||
return;
|
||||
} catch {
|
||||
//
|
||||
@ -295,7 +368,11 @@ describe('Testing validation', () => {
|
||||
},
|
||||
{ fix: true }
|
||||
);
|
||||
reject('Expected to throw error for bad default properties');
|
||||
reject(
|
||||
new Error(
|
||||
'Expected to throw error for bad default properties'
|
||||
)
|
||||
);
|
||||
return;
|
||||
} catch {
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user