Cleanup - unused files / unused exports / duplicate exports
[ProtonMail-WebClient.git] / packages / icons / bin / generateReactIcons.ts
blob3466c517126b0acac0c12c0862692b7417214b78
1 import { mkdir, readFile, rm, writeFile } from 'fs/promises';
2 import { JSDOM } from 'jsdom';
3 import mustache from 'mustache';
4 import path from 'path';
5 import * as prettier from 'prettier';
7 function capitalize(string: string) {
8     return string.charAt(0).toUpperCase() + string.slice(1);
11 function camelize(str: string) {
12     return str
13         .replace(/(?:^\w|[A-Z]|[\b\-_]\w)/g, function (word, index) {
14             return index === 0 ? word.toLowerCase() : word.toUpperCase().replace('-', '').replace('_', '');
15         })
16         .replace(/\s+/g, '');
19 function convertToJsx(html: string): string {
20     return html.replace(/<(\w+)([^>]*)\/?>/g, (_, tagName: string, attributes: string) => {
21         // Convert attributes to camelCase
22         const camelCaseAttributes = attributes
23             .trim()
24             .replace(/[\w-]+="[^"]*"/g, (attr) => {
25                 const [key, value] = attr.split('=');
26                 return `${camelize(key)}=${value}`;
27             })
28             .replace(/class=/, 'className=');
29         return `<${tagName} ${camelCaseAttributes}>`;
30     });
33 const disclaimer = `
35  * This file is auto-generated. Do not modify it manually!
36  * Run 'yarn workspace @proton/icons build' to update the icons react components.
40 const iconsDir = path.join(__dirname, '../icons');
42 async function run() {
43     const iconTemplate = await readFile(path.join(__dirname, './IconTemplate.tsx.mustache'), { encoding: 'utf-8' });
45     const iconFile = await readFile('./assets/sprite-icons.svg', 'utf8');
46     const iconNodes = Array.from(new JSDOM(iconFile).window.document.querySelectorAll('g[id]'));
48     const icons = iconNodes.map((node) => {
49         const iconName = capitalize(camelize(node.id));
51         const renderedContent = mustache.render(iconTemplate, { iconName, innerHTML: convertToJsx(node.innerHTML) });
53         return {
54             name: iconName,
55             content: [disclaimer, renderedContent].join('\n'),
56         };
57     });
59     await rm(iconsDir, { recursive: true, force: true });
60     await mkdir(iconsDir);
62     const prettierOptions = (await prettier.resolveConfig(path.join(__dirname, '../../../prettier.config.mjs'))) || {};
64     const writeFilesPromises = icons.map(async (icon) => {
65         await writeFile(
66             `${iconsDir}/${icon.name}.tsx`,
67             await prettier.format(icon.content, { ...prettierOptions, parser: 'typescript' })
68         );
69     });
71     const generateIndex = async () => {
72         const index = [
73             disclaimer,
74             `export * from './types';`,
75             '',
76             `export type IconName = ${iconNodes.map((node) => `'${node.id.replace('ic-', '')}'`).join('|')}`,
77             '',
78             ...icons.map((icon) => `export { ${icon.name} } from './icons/${icon.name}';`),
79         ].join('\n');
81         await writeFile(
82             path.join(__dirname, '../index.ts'),
83             await prettier.format(index, { ...prettierOptions, parser: 'typescript' })
84         );
85     };
86     writeFilesPromises.push(generateIndex());
88     await Promise.all(writeFilesPromises);
91 void run();