2
0
mirror of https://github.com/iconify/iconify.git synced 2025-02-13 00:58:30 +00:00
iconify/packages/utils/src/icon-set/convert-info.ts
2022-03-16 10:58:02 +02:00

289 lines
5.6 KiB
TypeScript

import type { IconifyInfo } from '@iconify/types';
const minDisplayHeight = 16;
const maxDisplayHeight = 24;
const maxSamplesCount = 3;
/**
* Item provided by API or loaded from collections.json, slightly different from IconifyInfo
*/
export interface LegacyIconifyInfo {
// Icon set name.
name: string;
// Total number of icons.
total?: number;
// Version string.
version?: string;
// Author
author?: string;
url?: string;
// License
license?: string;
licenseURL?: string;
licenseSPDX?: string;
// Samples
samples?: string[];
// Icon grid
height?: number | number[];
displayHeight?: number;
samplesHeight?: number;
// Category
category?: string;
palette?: 'Colorless' | 'Colorful';
// Hidden
hidden?: boolean;
}
/**
* Check if displayHeight value is valid, returns 0 on failure
*/
function validateDisplayHeight(value: number): number {
while (value < minDisplayHeight) {
value *= 2;
}
while (value > maxDisplayHeight) {
value /= 2;
}
return value === Math.round(value) &&
value >= minDisplayHeight &&
value <= maxDisplayHeight
? value
: 0;
}
/**
* Convert data to valid CollectionInfo
*/
export function convertIconSetInfo(
data: unknown,
expectedPrefix = ''
): IconifyInfo | null {
if (typeof data !== 'object' || data === null) {
return null;
}
const source = data as Record<string, unknown>;
const getSourceNestedString = (
field: string,
key: string,
defaultValue = ''
): string => {
if (typeof source[field] !== 'object') {
return defaultValue;
}
const obj = source[field] as Record<string, string>;
return typeof obj[key] === 'string' ? obj[key] : defaultValue;
};
// Get name
let name: string;
if (typeof source.name === 'string') {
name = source.name;
} else if (typeof source.title === 'string') {
name = source.title;
} else {
return null;
}
// Validate prefix
if (
expectedPrefix !== '' &&
typeof source.prefix === 'string' &&
source.prefix !== expectedPrefix
) {
// Prefixes do not match
return null;
}
// Generate basic info
const info = {
name,
} as IconifyInfo;
// Number of icons
switch (typeof source.total) {
case 'number':
info.total = source.total;
break;
case 'string': {
const num = parseInt(source.total);
if (num > 0) {
info.total = num;
}
break;
}
}
// Version
if (typeof source.version === 'string') {
info.version = source.version;
}
// Author
info.author = {
name: getSourceNestedString(
'author',
'name',
typeof source.author === 'string' ? source.author : ''
),
};
if (typeof source.author === 'object') {
const sourceAuthor = source.author as Record<string, string>;
if (typeof sourceAuthor.url === 'string') {
info.author.url = sourceAuthor.url;
}
}
// License
info.license = {
title: getSourceNestedString(
'license',
'title',
typeof source.license === 'string' ? source.license : ''
),
};
if (typeof source.license === 'object') {
const sourceLicense = source.license as Record<string, string>;
if (typeof sourceLicense.spdx === 'string') {
info.license.spdx = sourceLicense.spdx;
}
if (typeof sourceLicense.url === 'string') {
info.license.url = sourceLicense.url;
}
}
// Samples
if (source.samples instanceof Array) {
const samples: string[] = [];
source.samples.forEach((item) => {
if (typeof item === 'string' && samples.length < maxSamplesCount) {
samples.push(item);
}
});
if (samples.length) {
info.samples = samples;
}
}
// Add height
if (
typeof source.height === 'number' ||
typeof source.height === 'string'
) {
const num = parseInt(source.height as string);
if (num > 0) {
info.height = num;
}
}
if (source.height instanceof Array) {
source.height.forEach((item) => {
const num = parseInt(item as string);
if (num > 0) {
if (!(info.height instanceof Array)) {
info.height = [];
}
info.height.push(num);
}
});
switch ((info.height as number[]).length) {
case 0:
delete info.height;
break;
case 1:
info.height = (info.height as number[])[0];
}
}
// Add display height
if (typeof info.height === 'number') {
// Convert from height
const displayHeight = validateDisplayHeight(info.height);
if (displayHeight && displayHeight !== info.height) {
info.displayHeight = displayHeight;
}
}
['samplesHeight', 'displayHeight'].forEach((prop) => {
const value = source[prop];
if (typeof value === 'number' || typeof value === 'string') {
// Convert from source.displayHeight or source.samplesHeight
const displayHeight = validateDisplayHeight(
parseInt(value as string)
);
if (displayHeight) {
info.displayHeight = displayHeight;
}
}
});
// Category
if (typeof source.category === 'string') {
info.category = source.category;
}
// Palette
switch (typeof source.palette) {
case 'boolean':
info.palette = source.palette;
break;
case 'string':
switch (source.palette.toLowerCase()) {
case 'colorless': // Iconify v1
case 'false': // Boolean as string
info.palette = false;
break;
case 'colorful': // Iconify v1
case 'true': // Boolean as string
info.palette = true;
}
break;
}
// Hidden
if (source.hidden === true) {
info.hidden = true;
}
// Parse all old strings
Object.keys(source).forEach((key) => {
const value = source[key];
if (typeof value !== 'string') {
return;
}
switch (key) {
case 'url':
case 'uri':
info.author.url = value;
break;
case 'licenseURL':
case 'licenseURI':
info.license.url = value;
break;
case 'licenseID':
case 'licenseSPDX':
info.license.spdx = value;
break;
}
});
return info;
}