diff --git a/scripts/generate.js b/scripts/generate.js index c7fe634..bf98cf5 100644 --- a/scripts/generate.js +++ b/scripts/generate.js @@ -1,35 +1,34 @@ -const fs = require('fs'); -const { sync: mkdirp } = require('mkdirp'); -const path = require('path'); -const rollup = require('rollup'); -const babel = require('rollup-plugin-babel'); +const fs = require('fs') +const { sync: mkdirp } = require('mkdirp') +const path = require('path') +const rollup = require('rollup') +const babel = require('rollup-plugin-babel') -const svgPathRegex = /]*)>/g; -const svgAttrRegex = /(?:\s*|^)([^= ]*)="([^"]*)"/g; -const validIconName = /^[A-Z]/; +const svgPathRegex = /]*)>/g +const svgAttrRegex = /(?:\s*|^)([^= ]*)="([^"]*)"/g +const validIconName = /^[A-Z]/ function getRollupInputConfig(target) { return { external: [target], plugins: [ babel({ - presets: [ - ['es2015', { modules: false }], - target - ], - plugins: [ - 'transform-object-rest-spread', - 'external-helpers' - ] + presets: [['es2015', { modules: false }], target], + plugins: ['transform-object-rest-spread', 'external-helpers'] }) ] - }; + } } function normalizeName(name) { - return name.split(/[ -]/g).map(part => { - return part.charAt(0).toUpperCase() + part.slice(1); - }).join('') + 'Icon'; + return ( + name + .split(/[ -]/g) + .map((part) => { + return part.charAt(0).toUpperCase() + part.slice(1) + }) + .join('') + 'Icon' + ) } function checkAllowedAttr(attr, value, content, name) { @@ -56,20 +55,20 @@ function checkAllowedAttr(attr, value, content, name) { function extractPath(content, name) { const allPaths = [] while (true) { - const svgPathMatches = svgPathRegex.exec(content); - const svgPath = svgPathMatches && svgPathMatches[1]; + const svgPathMatches = svgPathRegex.exec(content) + const svgPath = svgPathMatches && svgPathMatches[1] if (!svgPath) { break } const attrs = {} while (true) { - const svgAttrMatches = svgAttrRegex.exec(svgPath); + const svgAttrMatches = svgAttrRegex.exec(svgPath) if (!svgAttrMatches) { break } if (!checkAllowedAttr(svgAttrMatches[1], svgAttrMatches[2])) { throw new Error( - `Unknown SVG attr in ${name}: ${svgAttrMatches[1]}="${svgAttrMatches[2]}"\n${content}`, + `Unknown SVG attr in ${name}: ${svgAttrMatches[1]}="${svgAttrMatches[2]}"\n${content}` ) } attrs[svgAttrMatches[1]] = svgAttrMatches[2] @@ -82,42 +81,42 @@ function extractPath(content, name) { if (allPaths.length !== 1 || !allPaths[0].d) { throw new Error( `Wrong number of path in ${name}: ${allPaths.length}\n` + - `${JSON.stringify(allPaths, undefined, 2)}\n${content}`, + `${JSON.stringify(allPaths, undefined, 2)}\n${content}` ) } return allPaths[0].d } function collectComponents(svgFilesPath) { - const svgFiles = fs.readdirSync(svgFilesPath); + const svgFiles = fs.readdirSync(svgFilesPath) - const icons = []; + const icons = [] for (const svgFile of svgFiles) { - const svgFilePath = path.join(svgFilesPath, svgFile); + const svgFilePath = path.join(svgFilesPath, svgFile) // Handle sub-directories. - const stats = fs.statSync(svgFilePath); + const stats = fs.statSync(svgFilePath) if (stats.isDirectory()) { - icons.push(...collectComponents(svgFilePath)); - continue; + icons.push(...collectComponents(svgFilePath)) + continue } - const origName = svgFile.slice(0, -4); - const name = normalizeName(origName); + const origName = svgFile.slice(0, -4) + const name = normalizeName(origName) if (!validIconName.exec(name)) { console.log(`Skipping icon with invalid name: ${svgFilePath}`) - continue; + continue } - const content = fs.readFileSync(svgFilePath); + const content = fs.readFileSync(svgFilePath) let svgPath try { - svgPath = extractPath(content, svgFilePath); + svgPath = extractPath(content, svgFilePath) } catch (err) { // Ignore file. console.log(err) - continue; + continue } const icon = { @@ -125,69 +124,108 @@ function collectComponents(svgFilesPath) { fileName: name + '.js', defFileName: name + '.d.ts', svgPath - }; + } - icons.push(icon); + icons.push(icon) } - return icons; + return icons } async function generate(target, jsCb, tsCb, tsAllCb) { - const basePath = path.resolve(__dirname, '..'); - const svgFilesPath = path.resolve(basePath, 'node_modules/remixicon/icons'); - const buildPath = path.resolve(basePath, 'build'); - mkdirp(buildPath); - const publishPath = path.resolve(basePath, 'publish-' + target); - mkdirp(publishPath); - const distPath = path.resolve(publishPath, 'dist'); - mkdirp(distPath); - - console.log('Collecting components...'); - const components = collectComponents(svgFilesPath); - console.log('Generating components...'); - const pathsToUnlink = []; + const basePath = path.resolve(__dirname, '..') + const svgFilesPath = path.resolve(basePath, 'node_modules/remixicon/icons') + const buildPath = path.resolve(basePath, 'build') + mkdirp(buildPath) + const publishPath = path.resolve(basePath, 'publish-' + target) + mkdirp(publishPath) + const distPath = path.resolve(publishPath, 'dist') + mkdirp(distPath) + + console.log('Collecting components...') + const components = collectComponents(svgFilesPath) + console.log('Generating components...') + const pathsToUnlink = [] + const componentNames = [] for (const [index, component] of components.entries()) { - if (!component.aliasFor) { - console.log(`Generating ${component.name}... (${index + 1}/${components.length})`); - } else { - console.log(`Generating alias ${component.name}... (${index + 1}/${components.length})`); - } + try { + /* + if (!component.aliasFor) { + console.log( + `Generating ${component.name}... (${index + 1}/${components.length})` + ) + } else { + console.log( + `Generating alias ${component.name}... (${index + 1}/${ + components.length + })` + ) + } + */ - const fileContent = jsCb(component); - const inputPath = path.resolve(buildPath, component.fileName); - const outputPath = path.resolve(publishPath, component.fileName); + const fileContent = jsCb(component) - fs.writeFileSync(inputPath, fileContent); + const inputPath = path.resolve(buildPath, component.fileName) + const outputPath = path.resolve(publishPath, component.fileName) - const bundle = await rollup.rollup({ - input: inputPath, - ...getRollupInputConfig(target) - }); + fs.writeFileSync(inputPath, fileContent) - await bundle.write({ - file: outputPath, - format: 'cjs' - }); + const bundle = await rollup.rollup({ + input: inputPath, + ...getRollupInputConfig(target) + }) - // remember paths to unlink later - if (!pathsToUnlink.includes(inputPath)) { - pathsToUnlink.push(inputPath); - } + await bundle.write({ + file: outputPath, + format: 'cjs', + exports: 'auto' + }) - const definitionContent = tsCb(component); - fs.writeFileSync(path.join(publishPath, component.defFileName), definitionContent); + // remember paths to unlink later + if (!pathsToUnlink.includes(inputPath)) { + pathsToUnlink.push(inputPath) + } + + const definitionContent = tsCb(component) + fs.writeFileSync( + path.join(publishPath, component.defFileName), + definitionContent + ) + + componentNames.push(component.name) + } catch (error) { + console.log(`→ ${error}`) + } } - console.log('Generating typings...'); + console.log('Generating index.ts') + + const defaultImports = [] + componentNames.forEach((name) => { + defaultImports.push(`import ${name} from './${name}'`) + }) + const exportDefaultImport = [] + componentNames.forEach((name) => { + exportDefaultImport.push(name) + }) + + fs.writeFileSync( + path.resolve(publishPath, 'index.ts'), + `${defaultImports.join('\n')}\n +export default { + ${exportDefaultImport.join(',\n ')} +}` + ) + + console.log('Generating typings...') // create the global typings.d.ts - const typingsContent = tsAllCb(); - fs.writeFileSync(path.resolve(distPath, 'typings.d.ts'), typingsContent); + const typingsContent = tsAllCb() + fs.writeFileSync(path.resolve(distPath, 'typings.d.ts'), typingsContent) // clean up for (const pathToUnlink of pathsToUnlink) { - fs.unlinkSync(pathToUnlink); + fs.unlinkSync(pathToUnlink) } } -module.exports = generate; +module.exports = generate