via-icons/scripts/generateHiIcons.js

146 lines
3.8 KiB
JavaScript
Raw Normal View History

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 = {};
2024-08-07 21:53:10 -06:00
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(/<svg\s+([^>]+)>([\s\S]*?)<\/svg>/);
if (!svgMatch) return null;
const [_, svgAttributes, svgInner] = svgMatch;
const svgData = {
tag: "svg",
2024-08-07 21:53:10 -06:00
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")
);