2
0
mirror of https://github.com/iconify/iconify.git synced 2024-09-20 01:09:04 +00:00

Parse icons tree only once when parsing icon set

This commit is contained in:
Vjacheslav Trushkin 2022-06-20 20:39:06 +03:00
parent 89a2def126
commit 7b4409665a
3 changed files with 180 additions and 171 deletions

View File

@ -4,6 +4,57 @@ import type { IconifyIcon, FullIconifyIcon } from '../icon/defaults';
import { mergeIconData } from '../icon/merge'; import { mergeIconData } from '../icon/merge';
import { getIconsTree } from './tree'; import { getIconsTree } from './tree';
/**
* Get icon data, using prepared aliases tree
*/
export function internalGetIconData(
data: IconifyJSON,
name: string,
tree: string[],
full: true
): FullIconifyIcon;
export function internalGetIconData(
data: IconifyJSON,
name: string,
tree: string[],
full: false
): IconifyIcon;
export function internalGetIconData(
data: IconifyJSON,
name: string,
tree: string[],
full: boolean
): FullIconifyIcon | IconifyIcon {
const icons = data.icons;
const aliases = data.aliases || {};
let currentProps = {} as IconifyIcon;
// Parse parent item
function parse(name: string) {
currentProps = mergeIconData(
icons[name] || aliases[name],
currentProps,
false
);
}
parse(name);
tree.forEach(parse);
// Add default values
currentProps = mergeIconData(
data,
currentProps,
false
) as unknown as IconifyIcon;
// Return icon
return full
? Object.assign({}, defaultIconProps, currentProps)
: currentProps;
}
/** /**
* Get data for icon * Get data for icon
*/ */
@ -22,43 +73,12 @@ export function getIconData(
name: string, name: string,
full = false full = false
): FullIconifyIcon | IconifyIcon | null { ): FullIconifyIcon | IconifyIcon | null {
const icons = data.icons; if (data.icons[name]) {
const aliases = data.aliases || {};
let currentProps = {} as IconifyIcon;
// Parse parent item
function parse(name: string) {
currentProps = mergeIconData(
icons[name] || aliases[name],
currentProps,
false
);
}
const icon = icons[name];
if (icon) {
// Parse only icon // Parse only icon
parse(name); return internalGetIconData(data, name, [], full as true);
} else {
// Resolve tree
const tree = getIconsTree(data, [name])[name];
if (!tree) {
return null;
}
parse(name);
tree.forEach(parse);
} }
// Add default values // Resolve tree
currentProps = mergeIconData( const tree = getIconsTree(data, [name])[name];
data, return tree ? internalGetIconData(data, name, tree, full as true) : null;
currentProps,
false
) as unknown as IconifyIcon;
// Return icon
return full
? Object.assign({}, defaultIconProps, currentProps)
: currentProps;
} }

View File

@ -1,6 +1,7 @@
import type { IconifyJSON } from '@iconify/types'; import type { IconifyJSON } from '@iconify/types';
import type { FullIconifyIcon } from '../icon/defaults'; import type { FullIconifyIcon } from '../icon/defaults';
import { getIconData } from './get-icon'; import { internalGetIconData } from './get-icon';
import { getIconsTree } from './tree';
/** /**
* Callback to call for each icon. * Callback to call for each icon.
@ -37,29 +38,15 @@ export function parseIconSet(
}); });
} }
// Get icons // Get tree
const icons = data.icons; const tree = getIconsTree(data);
for (const name in icons) { for (const name in tree) {
const iconData = getIconData(data, name, true); const item = tree[name];
if (iconData) { if (item) {
// Call callback callback(name, internalGetIconData(data, name, item, true));
callback(name, iconData);
names.push(name); names.push(name);
} }
} }
// Get aliases
const aliases = data.aliases;
if (aliases) {
for (const name in aliases) {
const iconData = icons[name] ? null : getIconData(data, name, true);
if (iconData) {
// Call callback
callback(name, iconData);
names.push(name);
}
}
}
return names; return names;
} }

View File

@ -66,8 +66,8 @@ describe('Testing parsing icon set', () => {
test('Aliases', () => { test('Aliases', () => {
// Names list // Names list
const names: string[] = ['icon1', 'icon2', 'alias1', 'alias2']; let names: string[] = ['icon1', 'icon2', 'alias1', 'alias2'];
const namesCopy = names.slice(0); const expectedNames = names.slice(0).sort((a, b) => a.localeCompare(b));
// Resolved data // Resolved data
const expected: Record<string, FullIconifyIcon | null> = { const expected: Record<string, FullIconifyIcon | null> = {
@ -114,56 +114,57 @@ describe('Testing parsing icon set', () => {
}; };
// Do stuff // Do stuff
expect( const parsedNames = parseIconSet(
parseIconSet( {
{ prefix: 'foo',
prefix: 'foo', icons: {
icons: { icon1: {
icon1: { body: '<path d="icon1" />',
body: '<path d="icon1" />', width: 20,
width: 20,
},
icon2: {
body: '<path d="icon2" />',
width: 24,
vFlip: true,
rotate: 3,
},
}, },
aliases: { icon2: {
alias1: { body: '<path d="icon2" />',
parent: 'icon1', width: 24,
}, vFlip: true,
alias2: { rotate: 3,
parent: 'icon2',
hFlip: true,
width: 20,
},
// invalid alias
icon2: {
parent: 'icon1',
},
}, },
height: 24,
}, },
(name, data) => { aliases: {
// Make sure name matches alias1: {
expect(names.length).toBeGreaterThanOrEqual(1); parent: 'icon1',
expect(name).toBe(names.shift()); },
alias2: {
parent: 'icon2',
hFlip: true,
width: 20,
},
// invalid alias
icon2: {
parent: 'icon1',
},
},
height: 24,
},
(name, data) => {
// Make sure name exists in array of pending names
const index = names.indexOf(name);
expect(index).not.toBe(-1);
names = names.slice(0, index).concat(names.slice(index + 1));
// Check icon data // Check icon data
expect(data).toEqual(expected[name]); expect(data).toEqual(expected[name]);
} }
) );
).toEqual(namesCopy);
// All names should have been parsed // All names should have been parsed, not necessary in expected order
expect(names).toEqual([]); expect(names).toEqual([]);
parsedNames.sort((a, b) => a.localeCompare(b));
expect(parsedNames).toEqual(expectedNames);
}); });
test('Nested aliases', () => { test('Nested aliases', () => {
// Names list // Names list
const names: string[] = [ let names: string[] = [
'icon1', 'icon1',
'icon2', 'icon2',
'alias2a', 'alias2a',
@ -175,7 +176,7 @@ describe('Testing parsing icon set', () => {
'alias2z6', 'alias2z6',
'alias2z7', 'alias2z7',
]; ];
const namesCopy = names.slice(0); const expectedNames = names.slice(0).sort((a, b) => a.localeCompare(b));
// Resolved data // Resolved data
const expected: Record<string, FullIconifyIcon | null> = { const expected: Record<string, FullIconifyIcon | null> = {
@ -290,82 +291,83 @@ describe('Testing parsing icon set', () => {
}; };
// Do stuff // Do stuff
expect( const parsedNames = parseIconSet(
parseIconSet( {
{ prefix: 'foo',
prefix: 'foo', icons: {
icons: { icon1: {
icon1: { body: '<path d="icon1" />',
body: '<path d="icon1" />', width: 20,
width: 20, height: 20,
height: 20,
},
icon2: {
body: '<path d="icon2" />',
width: 24,
rotate: 1,
hFlip: true,
},
}, },
aliases: { icon2: {
alias2a: { body: '<path d="icon2" />',
// Alias before parent width: 24,
parent: 'alias2f', rotate: 1,
width: 20, hFlip: true,
height: 20,
},
alias2f: {
parent: 'icon2',
width: 22,
rotate: 1,
hFlip: true,
vFlip: true,
},
alias2z: {
// Alias after parent
parent: 'alias2f',
width: 21,
rotate: 3,
},
alias2z3: {
// 3 parents: alias2z, alias2f, icon2
parent: 'alias2z',
},
alias2z4: {
// 4 parents: alias2z3, alias2z, alias2f, icon2
parent: 'alias2z3',
},
alias2z5: {
// 5 parents: alias2z4, alias2z3, alias2z, alias2f, icon2
parent: 'alias2z4',
},
alias2z6: {
// 6 parents: alias2z5, alias2z4, alias2z3, alias2z, alias2f, icon2
parent: 'alias2z5',
},
alias2z7: {
// 7 parents: alias2z6, alias2z5, alias2z4, alias2z3, alias2z, alias2f, icon2
parent: 'alias2z6',
},
alias3: {
// invalid parent
parent: 'icon3',
},
}, },
height: 24,
}, },
(name, data) => { aliases: {
// Make sure name matches alias2a: {
expect(names.length).toBeGreaterThanOrEqual(1); // Alias before parent
expect(name).toBe(names.shift()); parent: 'alias2f',
width: 20,
height: 20,
},
alias2f: {
parent: 'icon2',
width: 22,
rotate: 1,
hFlip: true,
vFlip: true,
},
alias2z: {
// Alias after parent
parent: 'alias2f',
width: 21,
rotate: 3,
},
alias2z3: {
// 3 parents: alias2z, alias2f, icon2
parent: 'alias2z',
},
alias2z4: {
// 4 parents: alias2z3, alias2z, alias2f, icon2
parent: 'alias2z3',
},
alias2z5: {
// 5 parents: alias2z4, alias2z3, alias2z, alias2f, icon2
parent: 'alias2z4',
},
alias2z6: {
// 6 parents: alias2z5, alias2z4, alias2z3, alias2z, alias2f, icon2
parent: 'alias2z5',
},
alias2z7: {
// 7 parents: alias2z6, alias2z5, alias2z4, alias2z3, alias2z, alias2f, icon2
parent: 'alias2z6',
},
alias3: {
// invalid parent
parent: 'icon3',
},
},
height: 24,
},
(name, data) => {
// Make sure name exists in array of pending names
const index = names.indexOf(name);
expect(index).not.toBe(-1);
names = names.slice(0, index).concat(names.slice(index + 1));
// Check icon data // Check icon data
expect(data).toEqual(expected[name]); expect(data).toEqual(expected[name]);
} }
) );
).toEqual(namesCopy);
// All names should have been parsed // All names should have been parsed, not necessary in expected order
expect(names).toEqual([]); expect(names).toEqual([]);
parsedNames.sort((a, b) => a.localeCompare(b));
expect(parsedNames).toEqual(expectedNames);
}); });
}); });