Refactor scripts in scripts/ (#4931)

- Rename `titleToFilename` to `titleToSlug`
- Fix indentation where necessary
- Use quotes internally consistently (to reduce the diff size, unfortunately this is the opposite quote from what we use in other projects)
- Update comments & documentation
- Construct file paths

And more...
This commit is contained in:
Eric Cornelissen 2021-02-08 17:14:31 +01:00 committed by GitHub
parent ce27500858
commit 8ecfcafeba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 108 additions and 104 deletions

View File

@ -2,29 +2,30 @@
/** /**
* @fileoverview * @fileoverview
* Compiles our icons into static .js files that can be imported in the browser * Compiles our icons into static .js files that can be imported in the browser
* and are tree-shakeable. * and are tree-shakeable. The static .js files go in icons/{filename}.js. Also
* The static .js files go in icons/{filename}.js. * generates an index.js that exports all icons by title, but is not
* Also generates an index.js that exports all icons by title, but is not tree-shakeable * tree-shakeable
*/ */
const fs = require("fs"); const fs = require("fs");
const path = require("path");
const util = require("util"); const util = require("util");
const minify = require("uglify-js").minify; const minify = require("uglify-js").minify;
const UTF8 = "utf8"; const UTF8 = "utf8";
const dataFile = "../_data/simple-icons.json"; const dataFile = path.resolve(__dirname, "..", "_data", "simple-icons.json");
const indexFile = `${__dirname}/../index.js`; const indexFile = path.resolve(__dirname, "..", "index.js");
const iconsDir = `${__dirname}/../icons`; const iconsDir = path.resolve(__dirname, "..", "icons");
const indexTemplateFile = `${__dirname}/templates/index.js`; const indexTemplateFile = path.resolve(__dirname, "templates", "index.js");
const iconObjectTemplateFile = `${__dirname}/templates/icon-object.js`; const iconObjectTemplateFile = path.resolve(__dirname, "templates", "icon-object.js");
const indexTemplate = fs.readFileSync(indexTemplateFile, UTF8); const indexTemplate = fs.readFileSync(indexTemplateFile, UTF8);
const iconObjectTemplate = fs.readFileSync(iconObjectTemplateFile, UTF8); const iconObjectTemplate = fs.readFileSync(iconObjectTemplateFile, UTF8);
const data = require(dataFile); const data = require(dataFile);
const { titleToFilename } = require("./utils"); const { titleToSlug } = require("./utils.js");
// Local helper functions // Local helper functions
function escape(value) { function escape(value) {
@ -43,32 +44,30 @@ function iconToObject(icon) {
escape(icon.hex) escape(icon.hex)
); );
} }
function minifyAndWrite(filepath, rawJavaScript) {
const { error, code } = minify(rawJavaScript);
if (error) {
console.error(error);
process.exit(1);
} else {
fs.writeFileSync(filepath, code);
}
}
// 'main' // 'main'
const icons = []; const icons = [];
data.icons.forEach(icon => { data.icons.forEach(icon => {
const filename = titleToFilename(icon.title); const filename = titleToSlug(icon.title);
icon.svg = fs.readFileSync(`${iconsDir}/${filename}.svg`, UTF8).replace(/\r?\n/, ''); const svgFilepath = path.resolve(iconsDir, `${filename}.svg`);
icon.slug = filename; icon.svg = fs.readFileSync(svgFilepath, UTF8).replace(/\r?\n/, '');
icons.push(icon); icon.slug = filename;
icons.push(icon);
// write the static .js file for the icon
const { error, code } = minify(`module.exports=${iconToObject(icon)};`);
if (error) {
console.error(error);
process.exit(1);
} else {
fs.writeFileSync(`${iconsDir}/${filename}.js`, code);
}
// write the static .js file for the icon
const jsFilepath = path.resolve(iconsDir, `${filename}.js`);
minifyAndWrite(jsFilepath, `module.exports=${iconToObject(icon)};`);
}); });
// write our generic index.js // write our generic index.js
const rawIndexJs = util.format(indexTemplate, icons.map(iconToKeyValue).join(',')); const rawIndexJs = util.format(indexTemplate, icons.map(iconToKeyValue).join(','));
const { error, code } = minify(rawIndexJs); minifyAndWrite(indexFile, rawIndexJs);
if (error) {
console.error(error);
process.exit(1);
} else {
fs.writeFileSync(indexFile, code);
}

View File

@ -1,22 +1,19 @@
#!/usr/bin/env node #!/usr/bin/env node
/** /**
* @fileoverview * @fileoverview
* Takes a brand name as argument and outputs the corresonding filename to * Script that takes a brand name as argument and outputs the corresponding
* standard output. * icon SVG filename to standard output.
*/ */
const utils = require('./utils.js'); const utils = require("./utils.js");
if (process.argv.length < 3) { if (process.argv.length < 3) {
console.error("Provide a brand name as argument") console.error("Provide a brand name as argument");
process.exit(1);
} else { } else {
let brandName = ""; const brandName = process.argv.slice(3)
for (let i = 2; i < process.argv.length; i++) { .reduce((acc, arg) => `${acc} ${arg}`, process.argv[2]);
brandName += ` ${process.argv[i]}`;
}
brandName = brandName.substring(1); const filename = utils.titleToSlug(brandName);
console.log(`For '${brandName}' use the file 'icons/${filename}.svg'`);
const filename = utils.titleToFilename(brandName);
console.log(`For '${brandName}' use the filename '${filename}.svg'`);
} }

View File

@ -1,6 +1,8 @@
#!/usr/bin/env node #!/usr/bin/env node
/** /**
* @fileoverview Lints for the package that can't be implemented in the existing linters (e.g. jsonlint/svglint) * @fileoverview
* Linters for the package that can't easily be implemented in the existing
* linters (e.g. jsonlint/svglint).
*/ */
const fs = require("fs"); const fs = require("fs");
@ -8,12 +10,13 @@ const path = require("path");
const { diffLinesUnified } = require("jest-diff"); const { diffLinesUnified } = require("jest-diff");
const simpleIconsData = require("../_data/simple-icons.json"); const UTF8 = "utf8";
const simpleIconsDataFile = path.resolve(
__dirname, "..", "_data", "simple-icons.json"); const dataFile = path.resolve( __dirname, "..", "_data", "simple-icons.json");
const data = require(dataFile);
/** /**
* Contains our tests so they can be isolated from eachother; I don't think each test is worth its own file * Contains our tests so they can be isolated from each other.
* @type {{[k:string]: () => (string|undefined)}} * @type {{[k:string]: () => (string|undefined)}}
*/ */
const TESTS = { const TESTS = {
@ -29,38 +32,38 @@ const TESTS = {
return invalidEntries; return invalidEntries;
}; };
const invalids = simpleIconsData.icons.reduce(collector, []); const invalids = data.icons.reduce(collector, []);
if (invalids.length) { if (invalids.length) {
return `Some icons aren't in alphabetical order: return `Some icons aren't in alphabetical order:
${invalids.map(icon => icon.title).join(", ")}`; ${invalids.map(icon => icon.title).join(", ")}`;
} }
}, },
/* Check the prettification of the data file */ /* Check the formatting of the data file */
prettified: function() { prettified: function() {
const simpleIconsDataString = fs.readFileSync( const dataString = fs.readFileSync(dataFile, UTF8).replace(/\r\n/g, '\n');
simpleIconsDataFile, "utf8").replace(/\r\n/g, '\n'); const dataPretty = `${JSON.stringify(data, null, " ")}\n`;
const simpleIconsDataPretty = `${JSON.stringify(simpleIconsData, null, " ")}\n`; if (dataString !== dataPretty) {
if (simpleIconsDataString !== simpleIconsDataPretty) { const dataDiff = diffLinesUnified(
const dataDiff = diffLinesUnified(simpleIconsDataString.split("\n"), dataString.split("\n"),
simpleIconsDataPretty.split("\n"), dataPretty.split("\n"),
{ {
expand: false, expand: false,
omitAnnotationLines: true omitAnnotationLines: true
}); },
return `Data file is not prettified:\n\n${dataDiff}`; );
return `Data file is formatted incorrectly:\n\n${dataDiff}`;
} }
} }
}; };
// execute all tests and log potential errors // execute all tests and log all errors
const errors = Object.keys(TESTS) const errors = Object.keys(TESTS)
.map(k => TESTS[k]()) .map(k => TESTS[k]())
.filter(Boolean); .filter(Boolean);
if (errors.length) { if (errors.length > 0) {
errors.forEach(error => { errors.forEach(error => console.error(`\u001b[31m${error}\u001b[0m`));
console.error(`\u001b[31m${error}\u001b[0m`);
});
process.exit(1); process.exit(1);
} }

View File

@ -1,38 +1,43 @@
module.exports = { /**
/** * @fileoverview
* Converts a brand title into a filename (not a full path) * Some common utilities for scripts.
* @param {String} title The title to convert */
*/
titleToFilename: title => (
title.toLowerCase()
.replace(/\+/g, "plus")
.replace(/^\./, "dot-")
.replace(/\.$/, "-dot")
.replace(/\./g, "-dot-")
.replace(/^&/, "and-")
.replace(/&$/, "-and")
.replace(/&/g, "-and-")
.replace(/đ/g, "d")
.replace(/ħ/g, "h")
.replace(/ı/g, "i")
.replace(/ĸ/g, "k")
.replace(/ŀ/g, "l")
.replace(/ł/g, "l")
.replace(/ß/g, "ss")
.replace(/ŧ/g, "t")
.normalize("NFD")
.replace(/[\u0300-\u036f]/g, "")
.replace(/[^a-z0-9_\-]/g, "")
),
/** module.exports = {
* Converts a brand title in HTML friendly format into a brand title (as it /**
* is seen in simple-icons.json) * Converts a brand title into a slug/filename.
* @param {String} htmlFriendlyTitle The title to convert * @param {String} title The title to convert
*/ */
htmlFriendlyToTitle: htmlFriendlyTitle => ( titleToSlug: title => (
htmlFriendlyTitle title.toLowerCase()
.replace(/&apos;/g, "") .replace(/\+/g, "plus")
.replace(/&amp;/g, "&") .replace(/^\./, "dot-")
) .replace(/\.$/, "-dot")
.replace(/\./g, "-dot-")
.replace(/^&/, "and-")
.replace(/&$/, "-and")
.replace(/&/g, "-and-")
.replace(/đ/g, "d")
.replace(/ħ/g, "h")
.replace(/ı/g, "i")
.replace(/ĸ/g, "k")
.replace(/ŀ/g, "l")
.replace(/ł/g, "l")
.replace(/ß/g, "ss")
.replace(/ŧ/g, "t")
.normalize("NFD")
.replace(/[\u0300-\u036f]/g, "")
.replace(/[^a-z0-9_\-]/g, "")
),
/**
* Converts a brand title in HTML/SVG friendly format into a brand title (as
* it is seen in simple-icons.json)
* @param {String} htmlFriendlyTitle The title to convert
*/
htmlFriendlyToTitle: htmlFriendlyTitle => (
htmlFriendlyTitle
.replace(/&apos;/g, "")
.replace(/&amp;/g, "&")
),
} }

View File

@ -1,8 +1,8 @@
const { icons } = require('../_data/simple-icons.json'); const { icons } = require('../_data/simple-icons.json');
const { titleToFilename } = require('../scripts/utils.js'); const { titleToSlug } = require('../scripts/utils.js');
icons.forEach(icon => { icons.forEach(icon => {
const filename = titleToFilename(icon.title); const filename = titleToSlug(icon.title);
const subject = require(`../icons/${filename}.js`); const subject = require(`../icons/${filename}.js`);
test(`${icon.title} has a "title"`, () => { test(`${icon.title} has a "title"`, () => {

View File

@ -1,6 +1,6 @@
const { icons } = require('../_data/simple-icons.json'); const { icons } = require('../_data/simple-icons.json');
const simpleIcons = require('../index.js'); const simpleIcons = require('../index.js');
const { titleToFilename } = require("../scripts/utils.js"); const { titleToSlug } = require("../scripts/utils.js");
icons.forEach(icon => { icons.forEach(icon => {
const subject = simpleIcons[icon.title]; const subject = simpleIcons[icon.title];
@ -38,7 +38,7 @@ icons.forEach(icon => {
}); });
test(`${icon.title} can be found by it's slug`, () => { test(`${icon.title} can be found by it's slug`, () => {
const name = titleToFilename(icon.title); const name = titleToSlug(icon.title);
const found = simpleIcons.get(name); const found = simpleIcons.get(name);
expect(found).toBeDefined(); expect(found).toBeDefined();
expect(found.title).toEqual(icon.title); expect(found.title).toEqual(icon.title);