import fs from "fs"; import path from "path"; import { optimize } from "svgo"; import { fileURLToPath } from "url"; import { dirname } from "path"; import outlineConfig from "./svgo.24.outline.js"; import solidConfig from "./svgo.24.solid.js"; import deprecatedIcons from "./deprecated.json" assert { type: "json" }; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const iconMetadataPath = path.resolve(__dirname, "./iconMetadata.json"); const iconMetadata = JSON.parse(fs.readFileSync(iconMetadataPath, "utf-8")); const mapSvgAttributes = (svgContent) => { return svgContent .replace(/fill-rule/g, "fillRule") .replace(/clip-rule/g, "clipRule"); }; const generateIconComponent = ( name, svgContent, description = "", usage = [], isDeprecated = false, aliases = [] ) => { const aliasExport = aliases.length ? `, ${aliases.map((alias) => `${name}Icon as ${alias}Icon`).join(", ")}` : ""; return ` import * as React from 'react'; interface IconProps extends React.SVGAttributes { children?: never; color?: string; } /** * @name ${name}Icon * ${ aliases.length ? `* @alias ${aliases.map((alias) => alias + "Icon").join(", ")}` : "" } * * @category ${usage.length ? "solid" : "outline"} * * @description * ${description} * * ${isDeprecated ? "@deprecated\n * " : ""} * @usage * ${usage.map((item) => `- ${item}`).join("\n * ")} * * @accessibility * Asegurarse de incluir un atributo \`aria-label\` o \`aria-hidden="true"\` si el ícono es decorativo. * * @returns {JSX.Element} Componente SVG. */ const ${name}Icon = React.forwardRef( ({ color = 'currentColor', ...props }, forwardedRef) => { return ( ${mapSvgAttributes(svgContent).replace( " { const exports = components .map( ({ name, aliases }) => `export { ${name}Icon${ aliases.length ? `, ${aliases .map((alias) => `${name}Icon as ${alias}Icon`) .join(", ")}` : "" } } from './${name}Icon';` ) .join("\n"); const indexPath = path.resolve(__dirname, `../src/${iconType}/index.ts`); fs.writeFileSync(indexPath, exports, "utf-8"); }; const processIcons = async (iconType) => { const svgDir = path.resolve(__dirname, `../src/svgs/${iconType}`); const componentDir = path.resolve(__dirname, `../src/${iconType}`); if (!fs.existsSync(componentDir)) { fs.mkdirSync(componentDir, { recursive: true }); } const components = []; const files = fs.readdirSync(svgDir); for (const file of files) { const filePath = path.resolve(svgDir, file); const svgContent = fs.readFileSync(filePath, "utf-8"); const svgoConfig = iconType === "outline" ? outlineConfig : solidConfig; const { data } = await optimize(svgContent, svgoConfig); const componentName = file .replace(".svg", "") .replace(/(^\w|-\w)/g, clearAndUpper); const metadata = iconMetadata[componentName]; const isDeprecated = deprecatedIcons.includes(componentName); if (!metadata) { console.warn( `Metadata for ${componentName} not found, generating without metadata.` ); } const aliases = metadata && metadata.aliases ? metadata.aliases : []; components.push({ name: componentName, aliases }); const componentContent = generateIconComponent( componentName, data, metadata ? metadata.description : "", metadata ? metadata.usage : [], isDeprecated, aliases ); const componentPath = path.resolve( componentDir, `${componentName}Icon.tsx` ); fs.writeFileSync(componentPath, componentContent, "utf-8"); } generateIndexFile(components, iconType); }; const clearAndUpper = (text) => text.replace(/-/, "").toUpperCase(); (async () => { await processIcons("solid"); await processIcons("outline"); })();