diff --git a/scripts/generate.js b/scripts/generate.js index e81ce7c..9b30579 100755 --- a/scripts/generate.js +++ b/scripts/generate.js @@ -10,6 +10,7 @@ const dataFile = '../src/data/icons.json'; const restrictedDataFile = '../src/data/restrictedIcons.json'; const logoDataFile = '../src/data/logoIcons.json'; +const distDir = `${__dirname}/../dist`; const indexFileES5 = `${__dirname}/../dist/index_es5.js`; const indexFileES6 = `${__dirname}/../dist/index.js`; const iconsDir = `${__dirname}/../src`; @@ -25,35 +26,48 @@ let buildIconsDir = `${__dirname}/../dist/icons`; const { getDistFilename, getDistSubFolder } = require('./utils'); -// creates necessary directory on build of not already there +// creates necessary directory on build if not already there const icoDir = './dist/icons'; -if (!fileSys.existsSync(icoDir)){ +if (!fileSys.existsSync(icoDir)) { fileSys.mkdirSync(icoDir); } function titleCase(str) { let splitStr = str.toLowerCase().split(' '); for (let i = 0; i < splitStr.length; i++) { - splitStr[i] = splitStr[i].charAt(0).toUpperCase() + splitStr[i].substring(1); + splitStr[i] = splitStr[i].charAt(0).toUpperCase() + splitStr[i].substring(1); } return splitStr.join(' '); } +// Helper function to convert file names to PascalCase (for React components) +function toCamelCase(str) { + return str + .replace(/[-_]+(.)?/g, (_, char) => char ? char.toUpperCase() : '') + .replace(/^./, firstChar => firstChar.toUpperCase()); +} + // export JS versions of Icons // ======================================================================= const icons = {}; -console.log(chalk.hex('#f26135')(`Generating Icons ... \n`)) +console.log(chalk.hex('#f26135')(`Generating Icons ... \n`)); +// Accumulate import statements for the output file +let importStatements = ''; + +/** + * Runs the generator to process the icons data and generate necessary files. + * + * @param {Object} data - The icons data object. + */ function runGenerator(data) { data.icons.forEach((iconRaw, index) => { let count = index + 1; let icon = { ...data.commonProperties, ...iconRaw - } - - // const iconStatus = icon.status; + }; const iconName = icon.name; const distFilename = getDistFilename(icon); @@ -86,15 +100,15 @@ function runGenerator(data) { const fillNone = icon.svg.match(/fill="none"/); if (fill) { - icon.svg = icon.svg.replace(fill, '') + icon.svg = icon.svg.replace(fill, ''); } if (fillNone) { - icon.svg = icon.svg.replace(fillNone, '') + icon.svg = icon.svg.replace(fillNone, ''); } } - // adds attributes to SVG string based on icons.json data + // Adds attributes to SVG string based on icons.json data icon.svg = [icon.svg.slice(0, insertPos), ariaHidden, icon.svg.slice(insertPos)].join(''); icon.svg = [icon.svg.slice(0, insertPos), elementStyle, icon.svg.slice(insertPos)].join(''); icon.svg = [icon.svg.slice(0, insertPos), labelledBy, icon.svg.slice(insertPos)].join(''); @@ -106,7 +120,7 @@ function runGenerator(data) { icon.svg = [icon.svg.slice(0, insertPos), iconDeprecated, icon.svg.slice(insertPos)].join(''); icon.svg = [icon.svg.slice(0, insertPos), ` `, icon.svg.slice(insertPos)].join(''); - //optimize SVG + // Optimize SVG icon.svg = optimize(icon.svg, { plugins: [ { @@ -115,9 +129,7 @@ function runGenerator(data) { overrides: { removeDesc: false, // keep cleanupIds: false, - sortDefsChildren: false, - removeTitle: false, // keep removeUnusedNS: false, // keep xmlns:xlink= removeUnknownsAndDefaults: { @@ -147,48 +159,67 @@ function runGenerator(data) { buildIconsDir = `${__dirname}/../dist`; } + // Create the publish folder if it doesn't exist const publishFolder = `${buildIconsDir}/${getDistSubFolder(icon.category)}`; - if (!fileSys.existsSync(publishFolder)){ + + if (!fileSys.existsSync(publishFolder)) { fileSys.mkdirSync(publishFolder); } + // Add the icon to the icons object icons[icon.name] = icon; - // write the static .js file for the icon - fs.writeFileSync( `${buildIconsDir}/${distFilename}.js`, `module.exports=${JSON.stringify(icon)};`); - fs.writeFileSync( `${buildIconsDir}/${distFilename}_es6.js`, `export default ${JSON.stringify(icon)};`); + // Generate the import statement for react specific icons + const camelCaseName = toCamelCase(icon.name); + const importStatement = `import { ReactComponent as ${camelCaseName} } from "@alaskaairux/icons/dist/icons/${icon.category}/${iconName}.svg";`; + + // Identify deprecated icons + if (icon.deprecated) { + importStatements += `${importStatement} // deprecated: discontinue use!\n`; + } else { + importStatements += `${importStatement}\n`; + } + + // Write the static .js file for the icon + fs.writeFileSync(`${buildIconsDir}/${distFilename}.js`, `module.exports=${JSON.stringify(icon)};`); + fs.writeFileSync(`${buildIconsDir}/${distFilename}_es6.js`, `export default ${JSON.stringify(icon)};`); // restrict new extension generation of files if (icon.type === 'icon' || icon.type === 'restricted' || icon.esm === true) { - fs.writeFileSync( `${buildIconsDir}/${distFilename}.mjs`, `export default ${JSON.stringify(icon)};`); + fs.writeFileSync(`${buildIconsDir}/${distFilename}.mjs`, `export default ${JSON.stringify(icon)};`); } // write new SVGs to ./dist - fs.writeFileSync( `${buildIconsDir}/${distFilename}.svg`, icon.svg); + fs.writeFileSync(`${buildIconsDir}/${distFilename}.svg`, icon.svg); process.stdout.write(`- `); }); } +// Generate the icons and React imports runGenerator(iconData); runGenerator(restrictedIconData); runGenerator(logoData); +// Write the accumulated React import statements to the output file after all icons are processed +const outputFile = `${distDir}/reactComponents.js`; +fs.writeFileSync(outputFile, importStatements); +console.log(chalk.green(`\n\nGenerated reactComponents.js with ${Object.keys(icons).length} icons.`)); console.log(chalk.hex('#f26135')(` - _______ __ __ __ -| __|.---.-.--.--. | |--.-----.| | |.-----. -|__ || _ | | | | | -__|| | || _ | -|_______||___._|___ | |__|__|_____||__|__||_____| - |_____| - __ _______ __ -| |_.-----. | _ |.--.--.----.-----.| | -| _| _ | | || | | _| _ ||__| -|____|_____| |___|___||_____|__| |_____||__| - -Generating the Icons People Love. -`)) - -// write our generic index.js -fs.writeFileSync(indexFileES5, `module.exports=${JSON.stringify(icons)};`); -fs.writeFileSync(indexFileES6, `export default ${JSON.stringify(icons)};`); + _______ __ __ __ + | __|.---.-.--.--. | |--.-----.| | |.-----. + |__ || _ | | | | | -__|| | || _ | + |_______||___._|___ | |__|__|_____||__|__||_____| + |_____| + __ _______ __ + | |_.-----. | _ |.--.--.----.-----.| | + | _| _ | | || | | _| _ ||__| + |____|_____| |___|___||_____|__| |_____||__| + + Generating the Icons People Love. + `)) + + // write our generic index.js + fs.writeFileSync(indexFileES5, `module.exports=${JSON.stringify(icons)};`); + fs.writeFileSync(indexFileES6, `export default ${JSON.stringify(icons)};`);