import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); function toPascalCase(str) { return str.replace(/(^\w|-\w)/g, (match) => match.replace(/-/, "").toUpperCase() ); } function parseAttributes(attributeString) { const attributes = {}; attributeString.replace(/(\w+)=["']([^"']*)["']/g, (match, name, value) => { const newName = name.replace(/-([a-z])/g, (g) => g[1].toUpperCase()); if (newName !== "xmlns" && newName !== "hidden" && newName !== "slot") { attributes[newName] = value; } return match; }); return attributes; } function parseSvgContent(svgContent) { const svgMatch = svgContent.match(/]+)>([\s\S]*?)<\/svg>/); if (!svgMatch) return null; const [_, svgAttributes, svgInner] = svgMatch; const svgData = { tag: "svg", attr: { viewBox: svgAttributes.match(/viewBox="([^"]*)"/)?.[1] || "0 0 24 24", fill: svgAttributes.match(/fill="([^"]*)"/)?.[1] || "currentColor", "aria-hidden": "true", }, child: parseChildren(svgInner), }; return svgData; } function parseChildren(innerContent) { const children = []; innerContent.replace( /<(\w+)\s+([^>]+)>([\s\S]*?)<\/\1>/g, (match, tag, attributes, inner) => { const child = { tag, attr: parseAttributes(attributes), child: parseChildren(inner), }; children.push(child); return match; } ); innerContent.replace(/<(\w+)\s+([^>]+)\/>/g, (match, tag, attributes) => { const child = { tag, attr: parseAttributes(attributes), child: [], }; children.push(child); return match; }); return children; } function generateIconComponents(prefix, folderPath, outputPath) { const files = fs.readdirSync(folderPath); let outputContent = `// THIS FILE IS AUTO GENERATED\nimport { GenIcon, IconBaseProps } from '../../lib';\n\n`; const componentNames = []; files.forEach((file) => { if (path.extname(file) === ".svg") { const iconName = path.basename(file, ".svg"); const svgContent = fs.readFileSync(path.join(folderPath, file), "utf8"); const svgData = parseSvgContent(svgContent); if (svgData) { const componentName = `${toPascalCase(iconName)}Icon`; outputContent += `export const ${componentName} = (props: IconBaseProps) => GenIcon(${JSON.stringify( svgData )})(props);\n\n`; componentNames.push(componentName); } } }); fs.mkdirSync(path.dirname(outputPath), { recursive: true }); fs.writeFileSync(outputPath, outputContent); return componentNames; } function generateHiIconComponents( outlineFolderPath, solidFolderPath, outputDir ) { const outlineOutputPath = path.join(outputDir, "outline", "index.ts"); const solidOutputPath = path.join(outputDir, "solid", "index.ts"); const outlineComponents = generateIconComponents( "", outlineFolderPath, outlineOutputPath ); const solidComponents = generateIconComponents( "", solidFolderPath, solidOutputPath ); const combinedIndexContent = outlineComponents .map( (component) => `export { ${component} as HiOutline${component.replace( "Icon", "" )} } from './outline';` ) .concat( solidComponents.map( (component) => `export { ${component} as Hi${component.replace( "Icon", "" )} } from './solid';` ) ) .join("\n"); fs.writeFileSync(path.join(outputDir, "index.ts"), combinedIndexContent); } // Special case for Hi icons generateHiIconComponents( path.join(__dirname, "..", "src", "svgs", "hi", "outline"), path.join(__dirname, "..", "src", "svgs", "hi", "solid"), path.join(__dirname, "..", "src", "hi") );