UNPKG

create-fomantic-icons

Version:

A simple CLI to generate the icon.variables and icon.html.eco files for FUI

349 lines (309 loc) 11.5 kB
// node import { resolve as resolvePath } from 'path'; // npm import * as fse from 'fs-extra'; import { load as parseYAML } from 'js-yaml'; import chalk from 'chalk'; // tasks import { PromptResults } from '../tasks/InitialPrompt'; import { PathResults } from '../tasks/DownloadAsset'; // utils import Logger, { spinner } from '../util/Logger'; // modals import Icon from '../modals/Icon'; import Category from '../modals/Category'; // enums import IconType from '../enums/IconType'; // static import aliases from '../static/aliases.json'; export interface IconMeta { search: { terms: string[]; }; terms?: string[]; styles: string[]; unicode: string; private: boolean; } export interface CategoryMeta { icons: string[]; label: string; } export interface ParseResults { icons: { solid: { icons:Icon[]; aliases: object[]; } outline: { icons: Icon[]; aliases: object[]; } thin: { icons: Icon[]; aliases: object[]; } brand: { icons: Icon[]; aliases: object[]; } duotone: { icons: Icon[]; aliases: object[]; } deprecated: { icons: Icon[]; aliases: object[]; } }; categories: Category[]; fontAssetsDirectory: string; fontFileNames: { [key: string]: string }; } export default function parse(results: PromptResults, paths: PathResults): Promise<ParseResults> { return new Promise((resolve) => { const { asset, } = results; const parseSpinner = spinner() .start('parsing icons'); const fontAwesomeDirectoryName = results.iconSet.name.toLowerCase() .replace(/\d+\+* /g, '') .replace(/\s/g, '-'); const fontAwesomeDirectory = `${fontAwesomeDirectoryName}-${asset.version}-web`; const iconsMetadataFilePath = resolvePath( paths.assetDirectoryPath, fontAwesomeDirectory, 'metadata', 'icons.json', ); const categoriesFilePath = resolvePath( paths.assetDirectoryPath, fontAwesomeDirectory, 'metadata', 'categories.yml', ); fse.readFile(iconsMetadataFilePath, (iconsErr, iconsData) => { if (!iconsErr) { const iconMetadata = JSON.parse(iconsData.toString()); const iconNames = Object.keys(iconMetadata); const deprecatedTester: RegExp = /(^|-)(in|out)(-|$)/; let icons: Icon[] = []; let categories: Category[] = []; iconNames.forEach((iconName) => { const iconMeta: IconMeta = iconMetadata[iconName]; if (!iconMeta.private) { const searchTerms: string[] = iconMeta.search ? (iconMeta.search.terms || []) : (iconMeta.terms || []); // deprecated if (deprecatedTester.test(iconName)) { icons.push(new Icon({ name: iconName, type: IconType.DEPRECATED, unicode: iconMeta.unicode, searchTerms, })); } else { // solid if (iconMeta.styles.includes('solid')) { icons.push(new Icon({ name: iconName, type: IconType.SOLID, unicode: iconMeta.unicode, searchTerms, })); } // outline if (iconMeta.styles.includes('regular')) { icons.push(new Icon({ name: iconName, type: IconType.OUTLINE, unicode: iconMeta.unicode, searchTerms, })); } // thin if (iconMeta.styles.includes('light')) { icons.push(new Icon({ name: iconName, type: IconType.THIN, unicode: iconMeta.unicode, searchTerms, })); } // brand if (iconMeta.styles.includes('brands')) { icons.push(new Icon({ name: iconName, type: IconType.BRAND, unicode: iconMeta.unicode, searchTerms, })); } // duotone if (iconMeta.styles.includes('duotone')) { icons.push(new Icon({ name: iconName, type: IconType.DUOTONE, unicode: iconMeta.unicode, searchTerms, })); } } } }); const sortAz = (a: {[key: string]: any}, b: {[key: string]: any}) => { if (a.name < b.name) return -1; if (a.name > b.name) return 1; return 0; }; // eslint-disable-next-line max-len const deprecatedAliases = aliases.filter((alias) => deprecatedTester.test(alias.rawName)).sort(sortAz); icons = icons.sort(sortAz); parseSpinner.text = 'parsing categories'; fse.readFile(categoriesFilePath, (categoriesErr, categoriesData) => { if (!categoriesErr) { const categoriesMetadata = parseYAML(categoriesData.toString()); // @ts-ignore const categoryNames = Object.keys(categoriesMetadata); categoryNames.forEach((categoryName) => { // @ts-ignore const categoryMeta: CategoryMeta = categoriesMetadata[categoryName]; const categoryIcons: Icon[] = []; categoryMeta.icons.forEach((iconName) => { icons.filter((i) => i.rawName === iconName) .forEach((icon) => { categoryIcons.push(icon); }); }); categories.push(new Category({ name: categoryName, label: categoryMeta.label, icons: categoryIcons.sort(sortAz), })); }); categories = categories .sort(sortAz); categories.push(new Category({ name: 'brands', label: 'Brands', icons: icons .filter((i) => i.type === IconType.BRAND) .sort(sortAz), })); categories.push(new Category({ name: 'duotone', label: 'Duotone', icons: icons .filter((i) => i.type === IconType.DUOTONE) .sort(sortAz), })); const deprecatedCategoryIcons = icons.filter((i) => i.type === IconType.DEPRECATED); deprecatedAliases.forEach((alias) => { deprecatedCategoryIcons.push(new Icon({ name: alias.name, type: IconType.DEPRECATED, unicode: alias.unicode, searchTerms: [], })); deprecatedCategoryIcons.sort(sortAz); }); categories.push(new Category({ name: 'deprecated', label: 'Deprecated', icons: deprecatedCategoryIcons, })); const parseResults = { icons: { solid: icons.filter((i) => i.type === IconType.SOLID), outline: icons.filter((i) => i.type === IconType.OUTLINE), thin: icons.filter((i) => i.type === IconType.THIN), brand: icons.filter((i) => i.type === IconType.BRAND), duotone: icons.filter((i) => i.type === IconType.DUOTONE), deprecated: icons.filter((i) => i.type === IconType.DEPRECATED), }, categories, }; const { solid: solidIcons, outline: outlineIcons, thin: thinIcons, brand: brandIcons, duotone: duotoneIcons, deprecated: deprecatedIcons } = parseResults.icons; const totalIcons = solidIcons.length + outlineIcons.length + thinIcons.length + brandIcons.length + duotoneIcons.length + deprecatedIcons.length + deprecatedAliases.length; parseSpinner.succeed('icons & categories parsed'); Logger.log(); Logger.log(chalk.cyan(' Results:')); Logger.log(` Solid: ${chalk.cyan(String(solidIcons.length))}`); Logger.log(` Outline: ${chalk.cyan(String(outlineIcons.length))}`); Logger.log(` Thin: ${chalk.cyan(String(thinIcons.length))}`); Logger.log(` Brand: ${chalk.cyan(String(brandIcons.length))}`); Logger.log(` Duotone: ${chalk.cyan(String(duotoneIcons.length))}`); Logger.log(` Deprecated: ${chalk.cyan(String(deprecatedIcons.length + deprecatedAliases.length))}`); Logger.log(` ----------------`); Logger.log(` TOTAL: ${chalk.cyan(String(totalIcons))}`); resolve({ icons: { solid: { icons: solidIcons, aliases: aliases.filter((alias) => alias.type === 'solid' && !deprecatedTester.test(alias.rawName)) .sort(sortAz), }, outline: { icons: outlineIcons, aliases: aliases.filter((alias) => alias.type === 'outline' && !deprecatedTester.test(alias.rawName)) .sort(sortAz), }, thin: { icons: thinIcons, aliases: aliases.filter((alias) => alias.type === 'thin' && !deprecatedTester.test(alias.rawName)) .sort(sortAz), }, brand: { icons: brandIcons, aliases: aliases.filter((alias) => alias.type === 'brand' && !deprecatedTester.test(alias.rawName)) .sort(sortAz), }, duotone: { icons: duotoneIcons, aliases: aliases.filter((alias) => alias.type === 'duotone' && !deprecatedTester.test(alias.rawName)) .sort(sortAz), }, deprecated: { icons: deprecatedIcons, aliases: deprecatedAliases, }, }, categories, fontAssetsDirectory: resolvePath( paths.assetDirectoryPath, fontAwesomeDirectory, 'webfonts', ), fontFileNames: { 'fa-solid-900': 'icons', 'fa-regular-400': 'outline-icons', 'fa-light-300': 'thin-icons', 'fa-brands-400': 'brand-icons', 'fa-duotone-900': 'duotone-icons', }, }); } else { parseSpinner.stop(); Logger.error(categoriesErr); process.exit(1); } }); } else { parseSpinner.stop(); Logger.error(iconsErr); process.exit(1); } }); }); }