146 lines
3.8 KiB
JavaScript
146 lines
3.8 KiB
JavaScript
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(/<svg\s+([^>]+)>([\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")
|
|
);
|