UNPKG

color-name-list

Version:
386 lines (342 loc) • 11.1 kB
import fs from 'fs'; import path from 'path'; import { parseCSVString, objArrToString } from './lib.js'; import { execFileSync } from 'child_process'; // setting const __dirname = path.dirname(new URL(import.meta.url).pathname); const baseFolder = __dirname + '/../'; const folderSrc = 'src/'; const folderDist = 'dist/'; const fileNameSrc = 'colornames'; const fileNameBestOfPostfix = '.bestof'; const readmeFileName = 'README.md'; const fileNameShortPostfix = '.short'; const maxShortNameLength = 12; const csvKeys = ['name', 'hex']; const bestOfKey = 'good name'; // reads the CSV file contents const src = fs .readFileSync(path.normalize(`${baseFolder}${folderSrc}${fileNameSrc}.csv`), 'utf8') .toString(); const colorsSrc = parseCSVString(src); // creates JS related files const JSONExportString = JSON.stringify( [...colorsSrc.entries].map( // removes good name attributes (val) => ({ name: val.name, hex: val.hex, }) ) ); const JSONExportStringBestOf = JSON.stringify( [...colorsSrc.entries] .filter((val) => val[bestOfKey]) .map( // removes good name attributes (val) => ({ name: val.name, hex: val.hex, }) ) ); const JSONExportStringShort = JSON.stringify( [...colorsSrc.entries] .filter( // make sure its only one word long (val) => val[bestOfKey] && // val.name.split(" ").length === 1 && val.name.length < maxShortNameLength + 1 ) .map( // removes good name attributes (val) => ({ name: val.name, hex: val.hex, }) ) ); // make sure dist folder exists const distFolder = path.normalize(`${baseFolder}${folderDist}`); if (!fs.existsSync(distFolder)) { fs.mkdirSync(distFolder); } fs.writeFileSync(path.normalize(`${baseFolder}${folderDist}${fileNameSrc}.json`), JSONExportString); fs.writeFileSync( path.normalize(`${baseFolder}${folderDist}${fileNameSrc}${fileNameBestOfPostfix}.json`), JSONExportStringBestOf ); fs.writeFileSync( path.normalize(`${baseFolder}${folderDist}${fileNameSrc}${fileNameShortPostfix}.json`), JSONExportStringShort ); // creates a more compact JSON file, where the HEX color serves as an id const miniJSONExportObj = colorsSrc.entries.reduce((obj, entry) => { obj[entry.hex.replace('#', '')] = entry.name; return obj; }, {}); const miniJSONExportObjBestOf = colorsSrc.entries.reduce((obj, entry) => { if (entry[bestOfKey]) { obj[entry.hex.replace('#', '')] = entry.name; } return obj; }, {}); const miniJSONExportObjShort = colorsSrc.entries.reduce((obj, entry) => { if ( entry[bestOfKey] && // entry.name.split(" ").length === 1 && entry.name.length < maxShortNameLength + 1 ) { obj[entry.hex.replace('#', '')] = entry.name; } return obj; }, {}); fs.writeFileSync( path.normalize(`${baseFolder}${folderDist}${fileNameSrc}.min.json`), JSON.stringify(miniJSONExportObj) ); fs.writeFileSync( path.normalize(`${baseFolder}${folderDist}${fileNameSrc}${fileNameBestOfPostfix}.min.json`), JSON.stringify(miniJSONExportObjBestOf) ); fs.writeFileSync( path.normalize(`${baseFolder}${folderDist}${fileNameSrc}${fileNameShortPostfix}.min.json`), JSON.stringify(miniJSONExportObjShort) ); // gets UMD template const umdTpl = fs.readFileSync(path.normalize(__dirname + '/umd.js.tpl'), 'utf8').toString(); // create UMD fs.writeFileSync( path.normalize(`${baseFolder}${folderDist}${fileNameSrc}.umd.js`), umdTpl.replace('"{{COLORS}}"', JSONExportString) ); fs.writeFileSync( path.normalize(`${baseFolder}${folderDist}${fileNameSrc}${fileNameBestOfPostfix}.umd.js`), umdTpl.replace('"{{COLORS}}"', JSONExportStringBestOf) ); fs.writeFileSync( path.normalize(`${baseFolder}${folderDist}${fileNameSrc}${fileNameShortPostfix}.umd.js`), umdTpl.replace('"{{COLORS}}"', JSONExportStringShort) ); // gets ESM template const esmTpl = fs.readFileSync(path.normalize(__dirname + '/esm.js.tpl'), 'utf8').toString(); // create ESM fs.writeFileSync( path.normalize(`${baseFolder}${folderDist}${fileNameSrc}.esm.js`), esmTpl.replace('"{{COLORS}}"', JSONExportString) ); fs.writeFileSync( path.normalize(`${baseFolder}${folderDist}${fileNameSrc}.esm.mjs`), esmTpl.replace('"{{COLORS}}"', JSONExportString) ); fs.writeFileSync( path.normalize(`${baseFolder}${folderDist}${fileNameSrc}${fileNameBestOfPostfix}.esm.js`), esmTpl.replace('"{{COLORS}}"', JSONExportStringBestOf) ); fs.writeFileSync( path.normalize(`${baseFolder}${folderDist}${fileNameSrc}${fileNameBestOfPostfix}.esm.mjs`), esmTpl.replace('"{{COLORS}}"', JSONExportStringBestOf) ); fs.writeFileSync( path.normalize(`${baseFolder}${folderDist}${fileNameSrc}${fileNameShortPostfix}.esm.js`), esmTpl.replace('"{{COLORS}}"', JSONExportStringShort) ); fs.writeFileSync( path.normalize(`${baseFolder}${folderDist}${fileNameSrc}${fileNameShortPostfix}.esm.mjs`), esmTpl.replace('"{{COLORS}}"', JSONExportStringShort) ); // create foreign formats // configuration for the file outputs const outputFormats = { csv: { insertBefore: csvKeys.join(',') + '\n', rowDelimitor: '\n', insertAfter: '\n', }, toon: { // TOON tabular array header for flat objects: [N]{name,hex}: insertBefore: `[${colorsSrc.entries.length}]{${csvKeys.join(',')}}:\n `, itemDelimitor: ',', rowDelimitor: '\n ', insertAfter: '\n', }, yaml: { insertBefore: '-\n ', beforeValue: '"', afterValue: '"', includeKeyPerItem: true, rowDelimitor: '\n-\n ', itemDelimitor: '\n ', insertAfter: '\n', }, scss: { insertBefore: '$color-name-list: (', beforeValue: '"', afterValue: '"', insertAfter: ');\n', itemDelimitor: ':', rowDelimitor: ',', }, html: { insertBefore: `<table><thead><tr><th>${csvKeys.join('</th><th>')}</th></tr><thead><tbody><tr><td>`, itemDelimitor: '</td><td>', rowDelimitor: '</td></tr><tr><td>', insertAfter: `</td></tr></tbody></table>\n`, }, xml: { insertBefore: `<?xml version='1.0'?>\n<colors>\n<color>\n<${csvKeys[0]}>`, itemDelimitor: `</${csvKeys[0]}>\n<${csvKeys[1]}>`, rowDelimitor: `</${csvKeys[1]}>\n</color>\n<color>\n<${csvKeys[0]}>`, insertAfter: `</${csvKeys[1]}>\n</color>\n</colors>\n`, }, }; for (const outputFormat in outputFormats) { if (outputFormats[outputFormat]) { let outputString = objArrToString(colorsSrc.entries, csvKeys, outputFormats[outputFormat]); if (outputFormat === 'html' || outputFormat === 'xml') { outputString = outputString.replace(/&/g, '&amp;'); } fs.writeFileSync( path.normalize(`${baseFolder}${folderDist}${fileNameSrc}.${outputFormat}`), outputString ); } } // bestOf files for (const outputFormat in outputFormats) { if (outputFormats[outputFormat]) { let outputString = objArrToString( colorsSrc.entries.filter((val) => val[bestOfKey]), csvKeys, outputFormats[outputFormat] ); if (outputFormat === 'html' || outputFormat === 'xml') { outputString = outputString.replace(/&/g, '&amp;'); } fs.writeFileSync( path.normalize( `${baseFolder}${folderDist}${fileNameSrc}${fileNameBestOfPostfix}.${outputFormat}` ), outputString ); } } // short files for (const outputFormat in outputFormats) { if (outputFormats[outputFormat]) { let outputString = objArrToString( colorsSrc.entries.filter( (val) => val[bestOfKey] && // val.name.split(" ").length === 1 && val.name.length < maxShortNameLength + 1 ), csvKeys, outputFormats[outputFormat] ); if (outputFormat === 'html' || outputFormat === 'xml') { outputString = outputString.replace(/&/g, '&amp;'); } fs.writeFileSync( path.normalize( `${baseFolder}${folderDist}${fileNameSrc}${fileNameShortPostfix}.${outputFormat}` ), outputString ); } } // updates the color count in readme file const readme = fs.readFileSync(path.normalize(`${baseFolder}${readmeFileName}`), 'utf8').toString(); fs.writeFileSync( path.normalize(`${baseFolder}${readmeFileName}`), readme .replace( // update color count in text /__\d+__/g, `__${colorsSrc.entries.length}__` ) .replace( // update color count in badge /\d+-colors-orange/, `${colorsSrc.entries.length}-colors-orange` ) .replace( // update color count in percentage /__\d+(\.\d+)?%__/, `__${((colorsSrc.entries.length / (256 * 256 * 256)) * 100).toFixed(2)}%__` ) .replace( // update file size (update all occurrences) /Bundle size note \(≈?\d+(\.\d+)? MB\)__/g, `Bundle size note (${( fs.statSync(path.normalize(`${baseFolder}${folderDist}${fileNameSrc}.json`)).size / 1024 / 1024 ).toFixed(2)} MB)__` ), 'utf8' ); // gets SVG template const svgTpl = fs.readFileSync(path.normalize(__dirname + '/changes.svg.tpl'), 'utf8').toString(); // generates an SVG image with the names added by the latest commit that added any; // commits that only remove names or change markers are skipped function diffSVG() { const csv = `${folderSrc}${fileNameSrc}.csv`; let commits; try { commits = execFileSync('git', ['log', '-n', '50', '--pretty=format:%H', '--', csv], { cwd: baseFolder, encoding: 'utf8', }) .trim() .split('\n'); } catch (err) { console.error('Error getting commit history:', err); return; } const rowsAt = (commit) => execFileSync('git', ['show', `${commit}:${csv}`], { cwd: baseFolder, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024, }) .split(/\r?\n/) .slice(1) .filter(Boolean) .map((line) => line.split(',')); let added = []; for (let i = 0; i + 1 < commits.length && !added.length; i++) { const before = new Set(rowsAt(commits[i + 1]).map(([name]) => name)); added = rowsAt(commits[i]).filter(([name]) => !before.has(name)); } if (!added.length) { console.log('No new colors in the recent history'); return; } const svgTxtStr = added.reduce( (str, [name, hex], i) => `${str}<text x="40" y="${20 + (i + 1) * 70}" fill="${hex}">${name.replace(/&/g, '&amp;')}</text>`, '' ); fs.writeFileSync( path.normalize(`${baseFolder}changes.svg`), svgTpl.replace(/{height}/g, added.length * 70 + 80).replace(/{items}/g, svgTxtStr) ); console.log(`Generated SVG showing ${added.length} new color(s)`); } diffSVG(); // Copy TypeScript definitions fs.copyFileSync( path.normalize(`${__dirname}/colornames.d.ts`), path.normalize(`${baseFolder}${folderDist}${fileNameSrc}.d.ts`) ); fs.copyFileSync( path.normalize(`${__dirname}/colornames.d.ts`), path.normalize(`${baseFolder}${folderDist}${fileNameSrc}${fileNameBestOfPostfix}.d.ts`) ); fs.copyFileSync( path.normalize(`${__dirname}/colornames.d.ts`), path.normalize(`${baseFolder}${folderDist}${fileNameSrc}${fileNameShortPostfix}.d.ts`) ); console.log('TypeScript definitions copied');