via-icons/scripts/generateIcons.js

156 lines
4.1 KiB
JavaScript
Raw Permalink Normal View History

2024-07-28 22:55:15 -06:00
import fs from "fs";
import path from "path";
import { optimize } from "svgo";
import { fileURLToPath } from "url";
import { dirname } from "path";
2024-07-29 20:56:59 -06:00
import outlineConfig from "./svgo.24.outline.js";
import solidConfig from "./svgo.24.solid.js";
import deprecatedIcons from "./deprecated.json" assert { type: "json" };
2024-07-28 22:55:15 -06:00
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"));
2024-07-28 23:41:19 -06:00
const mapSvgAttributes = (svgContent) => {
return svgContent
.replace(/fill-rule/g, "fillRule")
.replace(/clip-rule/g, "clipRule");
};
2024-07-28 23:07:58 -06:00
const generateIconComponent = (
name,
svgContent,
description = "",
2024-07-29 20:56:59 -06:00
usage = [],
2024-07-30 00:01:45 -06:00
isDeprecated = false,
aliases = []
) => {
const aliasExport = aliases.length
? `, ${aliases.map((alias) => `${name}Icon as ${alias}Icon`).join(", ")}`
: "";
return `
2024-07-28 22:55:15 -06:00
import * as React from 'react';
interface IconProps extends React.SVGAttributes<SVGElement> {
children?: never;
color?: string;
}
/**
2024-07-29 20:56:59 -06:00
* @name ${name}Icon
2024-07-30 00:13:41 -06:00
${
2024-07-30 00:01:45 -06:00
aliases.length
? `* @alias ${aliases.map((alias) => alias + "Icon").join(", ")}`
: ""
}
2024-07-29 20:56:59 -06:00
*
* @category ${usage.length ? "solid" : "outline"}
*
* @description
2024-07-28 22:55:15 -06:00
* ${description}
*
2024-07-29 20:56:59 -06:00
* ${isDeprecated ? "@deprecated\n * " : ""}
2024-07-28 22:55:15 -06:00
* @usage
2024-07-29 20:56:59 -06:00
* ${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.
2024-07-28 22:55:15 -06:00
*/
2024-07-30 00:01:45 -06:00
const ${name}Icon = React.forwardRef<SVGSVGElement, IconProps>(
2024-07-28 22:55:15 -06:00
({ color = 'currentColor', ...props }, forwardedRef) => {
return (
2024-07-28 23:41:19 -06:00
${mapSvgAttributes(svgContent).replace(
"<svg",
"<svg {...props} ref={forwardedRef}"
)}
2024-07-28 22:55:15 -06:00
);
}
);
${name}Icon.displayName = '${name}Icon';
2024-07-30 00:01:45 -06:00
export { ${name}Icon${aliasExport} };
2024-07-28 22:55:15 -06:00
`;
2024-07-30 00:01:45 -06:00
};
2024-07-28 22:55:15 -06:00
const generateIndexFile = (components, iconType) => {
const exports = components
2024-07-30 00:01:45 -06:00
.map(
({ name, aliases }) =>
`export { ${name}Icon${
aliases.length
? `, ${aliases
.map((alias) => `${name}Icon as ${alias}Icon`)
.join(", ")}`
: ""
} } from './${name}Icon';`
)
2024-07-28 22:55:15 -06:00
.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");
2024-07-29 20:56:59 -06:00
const svgoConfig = iconType === "outline" ? outlineConfig : solidConfig;
2024-07-28 22:55:15 -06:00
const { data } = await optimize(svgContent, svgoConfig);
const componentName = file
.replace(".svg", "")
.replace(/(^\w|-\w)/g, clearAndUpper);
const metadata = iconMetadata[componentName];
2024-07-29 20:56:59 -06:00
const isDeprecated = deprecatedIcons.includes(componentName);
2024-07-28 22:55:15 -06:00
if (!metadata) {
2024-07-28 23:07:58 -06:00
console.warn(
`Metadata for ${componentName} not found, generating without metadata.`
);
2024-07-28 22:55:15 -06:00
}
2024-07-30 00:01:45 -06:00
const aliases = metadata && metadata.aliases ? metadata.aliases : [];
components.push({ name: componentName, aliases });
2024-07-28 22:55:15 -06:00
const componentContent = generateIconComponent(
componentName,
data,
2024-07-28 23:07:58 -06:00
metadata ? metadata.description : "",
2024-07-29 20:56:59 -06:00
metadata ? metadata.usage : [],
2024-07-30 00:01:45 -06:00
isDeprecated,
aliases
2024-07-28 22:55:15 -06:00
);
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");
})();