Featherity Npm package, reorganize scripting. (#52)
* New setup for new NPM package * Add build scripts for dist * Add introduction readme * Refactor names * update package.json * remove log * rename variable * Factoring * Improve optimize script * Add eslint config * Eslint fixes * rename import * Move packeges * Setup rollup and build progress * Refactor scripts * fix lint error * remove lint disabler * Bring back old libraries * add indentation * reset packages directory * remove vscode setting files * 0.1.0-alpha.0 * new version * 0.1.0-alpha.1 * Fix build process * Add create element to the entry file * update version number * publish new alhpa version * fixing bugs * Add jest and tests * replace with XML createElement * set new version * Fix svg generation * Add tests for main library * Update docs * Adjust tests and selectors * update the spec * Update README.md * Update README.md * Update README.md * update version * Update README.md * Move function to helpers file * rename license, package and readme * Fix build files * rename packages Co-authored-by: Eric Fennis <eric.fennis@endurance.com>
This commit is contained in:
23
scripts/build/generateExportsFile.js
Normal file
23
scripts/build/generateExportsFile.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import path from 'path';
|
||||
|
||||
import { generateComponentName, resetFile, appendFile } from '../helpers';
|
||||
|
||||
export default function(inputEntry, outputDirectory, componentGetter, iconNodes) {
|
||||
const fileName = path.basename(inputEntry);
|
||||
|
||||
// Reset file
|
||||
resetFile(fileName, outputDirectory);
|
||||
|
||||
const icons = Object.keys(iconNodes);
|
||||
|
||||
// Generate Import for Icon VNodes
|
||||
icons.forEach(iconName => {
|
||||
const componentName = generateComponentName(iconName);
|
||||
const importString = `export { default as ${componentName} } from './${iconName}';\n`;
|
||||
appendFile(importString, fileName, outputDirectory);
|
||||
});
|
||||
|
||||
appendFile('\n', fileName, outputDirectory);
|
||||
|
||||
console.log(`Successfully generated ${fileName} file`);
|
||||
}
|
||||
27
scripts/build/generateIconFiles.js
Normal file
27
scripts/build/generateIconFiles.js
Normal file
@@ -0,0 +1,27 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import prettier from 'prettier';
|
||||
import { generateComponentName } from '../helpers';
|
||||
|
||||
export default function(iconNode, outputDirectory, template) {
|
||||
const icons = Object.keys(iconNode);
|
||||
const iconsDistDirectory = path.join(outputDirectory, `icons`);
|
||||
|
||||
if (!fs.existsSync(iconsDistDirectory)) {
|
||||
fs.mkdirSync(iconsDistDirectory);
|
||||
}
|
||||
|
||||
icons.forEach(icon => {
|
||||
const location = path.join(iconsDistDirectory, `${icon}.js`);
|
||||
const componentName = generateComponentName(icon);
|
||||
|
||||
const node = JSON.stringify(iconNode[icon]);
|
||||
|
||||
const elementTemplate = template({ componentName, node });
|
||||
|
||||
fs.writeFileSync(location, prettier.format(elementTemplate, { parser: 'babel' }), 'utf-8');
|
||||
|
||||
console.log('Successfully built', componentName);
|
||||
});
|
||||
}
|
||||
42
scripts/buildIcons.js
Normal file
42
scripts/buildIcons.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import renderIconsObject from './render/renderIconsObject';
|
||||
import renderIconNodes from './render/renderIconNodes';
|
||||
import generateIconFiles from './build/generateIconFiles';
|
||||
import generateExportsFile from './build/generateExportsFile';
|
||||
|
||||
import { readSvgDirectory } from './helpers';
|
||||
|
||||
const ICONS_DIR = path.resolve(__dirname, '../icons');
|
||||
const OUTPUT_DIR = path.resolve(__dirname, '../build');
|
||||
const SRC_DIR = path.resolve(__dirname, '../src');
|
||||
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.mkdirSync(OUTPUT_DIR);
|
||||
}
|
||||
|
||||
const svgFiles = readSvgDirectory(ICONS_DIR);
|
||||
|
||||
const icons = renderIconsObject(svgFiles, ICONS_DIR);
|
||||
|
||||
const iconVNodes = renderIconNodes(icons);
|
||||
|
||||
// Generates iconsNodes files for each icon
|
||||
generateIconFiles(
|
||||
iconVNodes,
|
||||
OUTPUT_DIR,
|
||||
({ componentName, node }) => `
|
||||
const ${componentName} = ${node};
|
||||
|
||||
export default ${componentName};
|
||||
`,
|
||||
);
|
||||
|
||||
// Generates entry files for the compiler filled with icons exports
|
||||
generateExportsFile(
|
||||
path.join(SRC_DIR, 'icons/index.js'),
|
||||
path.join(OUTPUT_DIR, 'icons'),
|
||||
'getElement',
|
||||
iconVNodes,
|
||||
);
|
||||
74
scripts/helpers.js
Normal file
74
scripts/helpers.js
Normal file
@@ -0,0 +1,74 @@
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { upperFirst, camelCase } from 'lodash/string';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* Generates a componentName of a String.
|
||||
*
|
||||
* @param {string} iconName
|
||||
*/
|
||||
export const generateComponentName = iconName =>
|
||||
iconName === 'github' ? 'GitHub' : upperFirst(camelCase(iconName));
|
||||
|
||||
/**
|
||||
* Resets the file contents.
|
||||
*
|
||||
* @param {string} fileName
|
||||
* @param {string} outputDirectory
|
||||
*/
|
||||
export const resetFile = (fileName, outputDirectory) =>
|
||||
fs.writeFileSync(path.join(outputDirectory, fileName), '', 'utf-8');
|
||||
|
||||
/**
|
||||
* Reads the file contents.
|
||||
*
|
||||
* @param {string} path
|
||||
*/
|
||||
export const readFile = entry => fs.readFileSync(path.resolve(__dirname, '../', entry), 'utf-8');
|
||||
|
||||
/**
|
||||
* append content to a file
|
||||
*
|
||||
* @param {string} content
|
||||
* @param {string} fileName
|
||||
* @param {string} outputDirectory
|
||||
*/
|
||||
export const appendFile = (content, fileName, outputDirectory) =>
|
||||
fs.appendFileSync(path.join(outputDirectory, fileName), content, 'utf-8');
|
||||
|
||||
/**
|
||||
* writes content to a file
|
||||
*
|
||||
* @param {string} content
|
||||
* @param {string} fileName
|
||||
* @param {string} outputDirectory
|
||||
*/
|
||||
export const writeFile = (content, fileName, outputDirectory) =>
|
||||
fs.writeFileSync(path.join(outputDirectory, fileName), content, 'utf-8');
|
||||
|
||||
/**
|
||||
* reads the icon directory
|
||||
*
|
||||
* @param {string} directory
|
||||
*/
|
||||
export const readSvgDirectory = directory =>
|
||||
fs.readdirSync(directory).filter(file => path.extname(file) === '.svg');
|
||||
|
||||
/**
|
||||
* Read svg from directory
|
||||
*
|
||||
* @param {string} fileName
|
||||
* @param {string} directory
|
||||
*/
|
||||
export const readSvg = (fileName, directory) => fs.readFileSync(path.join(directory, fileName));
|
||||
|
||||
/**
|
||||
* writes content to a file
|
||||
*
|
||||
* @param {string} fileName
|
||||
* @param {string} outputDirectory
|
||||
* @param {string} content
|
||||
*/
|
||||
export const writeSvgFile = (fileName, outputDirectory, content) =>
|
||||
fs.appendFileSync(path.join(outputDirectory, fileName), content, 'utf-8');
|
||||
15
scripts/optimizeSvgs.js
Normal file
15
scripts/optimizeSvgs.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import processSvg from './render/processSvg';
|
||||
import { readSvgDirectory, writeSvgFile } from './helpers';
|
||||
|
||||
const ICONS_DIR = path.resolve(__dirname, '../icons');
|
||||
|
||||
console.log(`Optimizing SVGs...`);
|
||||
|
||||
const svgFiles = readSvgDirectory(ICONS_DIR);
|
||||
|
||||
svgFiles.forEach(svgFile => {
|
||||
const content = fs.readFileSync(path.join(ICONS_DIR, svgFile));
|
||||
processSvg(content).then(svg => writeSvgFile(svg, ICONS_DIR, content));
|
||||
});
|
||||
11
scripts/render/default-attrs.json
Normal file
11
scripts/render/default-attrs.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"xmlns": "http://www.w3.org/2000/svg",
|
||||
"width": 24,
|
||||
"height": 24,
|
||||
"viewBox": "0 0 24 24",
|
||||
"fill": "none",
|
||||
"stroke": "currentColor",
|
||||
"stroke-width": 2,
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round"
|
||||
}
|
||||
57
scripts/render/processSvg.js
Normal file
57
scripts/render/processSvg.js
Normal file
@@ -0,0 +1,57 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import Svgo from 'svgo';
|
||||
import cheerio from 'cheerio';
|
||||
import { format } from 'prettier';
|
||||
|
||||
import DEFAULT_ATTRS from './default-attrs.json';
|
||||
|
||||
/**
|
||||
* Process SVG string.
|
||||
* @param {string} svg - An SVG string.
|
||||
* @param {Promise<string>}
|
||||
*/
|
||||
function processSvg(svg) {
|
||||
return (
|
||||
optimize(svg)
|
||||
.then(setAttrs)
|
||||
.then(format)
|
||||
// remove semicolon inserted by prettier
|
||||
// because prettier thinks it's formatting JSX not HTML
|
||||
.then(svg => svg.replace(/;/g, ''))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize SVG with `svgo`.
|
||||
* @param {string} svg - An SVG string.
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
function optimize(svg) {
|
||||
const svgo = new Svgo({
|
||||
plugins: [
|
||||
{ convertShapeToPath: false },
|
||||
{ mergePaths: false },
|
||||
{ removeAttrs: { attrs: '(fill|stroke.*)' } },
|
||||
{ removeTitle: true },
|
||||
],
|
||||
});
|
||||
|
||||
return new Promise(resolve => {
|
||||
svgo.optimize(svg, ({ data }) => resolve(data));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default attibutes on SVG.
|
||||
* @param {string} svg - An SVG string.
|
||||
* @returns {string}
|
||||
*/
|
||||
function setAttrs(svg) {
|
||||
const $ = cheerio.load(svg);
|
||||
|
||||
Object.keys(DEFAULT_ATTRS).forEach(key => $('svg').attr(key, DEFAULT_ATTRS[key]));
|
||||
|
||||
return $('body').html();
|
||||
}
|
||||
|
||||
export default processSvg;
|
||||
29
scripts/render/renderIconNodes.js
Normal file
29
scripts/render/renderIconNodes.js
Normal file
@@ -0,0 +1,29 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import { parseDOM } from 'htmlparser2';
|
||||
import DEFAULT_ATTRS from './default-attrs.json';
|
||||
|
||||
export default iconsObject => {
|
||||
const iconNodes = {};
|
||||
|
||||
Object.keys(iconsObject).forEach(icon => {
|
||||
const svgString = iconsObject[icon];
|
||||
const dom = parseDOM(svgString);
|
||||
|
||||
const children = dom.map(element => [
|
||||
element.name,
|
||||
{
|
||||
...element.attribs,
|
||||
},
|
||||
]);
|
||||
|
||||
iconNodes[icon] = [
|
||||
'svg',
|
||||
{
|
||||
...DEFAULT_ATTRS,
|
||||
},
|
||||
children,
|
||||
];
|
||||
});
|
||||
|
||||
return iconNodes;
|
||||
};
|
||||
35
scripts/render/renderIconsObject.js
Normal file
35
scripts/render/renderIconsObject.js
Normal file
@@ -0,0 +1,35 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import path from 'path';
|
||||
import cheerio from 'cheerio';
|
||||
import { minify } from 'html-minifier';
|
||||
import { readSvg } from '../helpers';
|
||||
|
||||
/**
|
||||
* Get contents between opening and closing `<svg>` tags.
|
||||
* @param {string} svg
|
||||
* @returns {string}
|
||||
*/
|
||||
function getSvgContents(svg) {
|
||||
const $ = cheerio.load(svg);
|
||||
|
||||
return minify($('svg').html(), { collapseWhitespace: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an object in the format: `{ <name>: <contents> }`.
|
||||
* @param {string[]} svgFiles - A list of filenames.
|
||||
* @param {Function} getSvg - A function that returns the contents of an SVG file given a filename.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export default (svgFiles, iconsDirectory) =>
|
||||
svgFiles
|
||||
.map(svgFile => {
|
||||
const name = path.basename(svgFile, '.svg');
|
||||
const svg = readSvg(svgFile, iconsDirectory);
|
||||
const contents = getSvgContents(svg);
|
||||
return { name, contents };
|
||||
})
|
||||
.reduce((icons, icon) => {
|
||||
icons[icon.name] = icon.contents;
|
||||
return icons;
|
||||
}, {});
|
||||
Reference in New Issue
Block a user