refactor(scripts): Cleaning up scripts (#2092)

* cleanup scripts

* Move helpers to package

* Fixes scripts

* Fix scripts

* Formatting

* Fix helpers import paths

* Remove lucide-figma

* Rename helpers package

* Fix build

* formatting

* Adjust main build-icons file

* Add export casing

* Adds `exportModuleNameCasing` fro lab project

* format files

* Bump package version @lucide/build-icons

* Revert changes in icons

* Revert changes in PR yml

* Fix lint issues

* Fix site build

* fix lint errors

* Attempt fix linting

* Fix lint errors
This commit is contained in:
Eric Fennis
2024-06-28 11:24:37 +02:00
committed by GitHub
parent ce79418c66
commit 077242cfa0
113 changed files with 455 additions and 31739 deletions

View File

@@ -0,0 +1,20 @@
export * from './src/toCamelCase.mjs';
export * from './src/toPascalCase.mjs';
export * from './src/toKebabCase.mjs';
export * from './src/resetFile.mjs';
export * from './src/readFile.mjs';
export * from './src/appendFile.mjs';
export * from './src/writeFile.mjs';
export * from './src/writeFileIfNotExists.mjs';
export * from './src/readAllMetadata.mjs';
export * from './src/readMetadata.mjs';
export * from './src/readSvgDirectory.mjs';
export * from './src/readSvg.mjs';
export * from './src/writeSvgFile.mjs';
export * from './src/hash.mjs';
export * from './src/generateHashedKey.mjs';
export * from './src/hasDuplicatedChildren.mjs';
export * from './src/mergeArrays.mjs';
export * from './src/getCurrentDirPath.mjs';
export * from './src/minifySvg.mjs';
export * from './src/shuffleArray.mjs';

View File

@@ -0,0 +1,11 @@
{
"name": "@lucide/helpers",
"private": true,
"version": "1.0.0",
"description": "A internal used package with helpers.",
"main": "main.mjs",
"types": "module",
"author": "",
"license": "ISC",
"type": "module"
}

View File

@@ -0,0 +1,13 @@
/* eslint-disable import/prefer-default-export */
import fs from 'fs';
import path from 'path';
/**
* 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');

View File

@@ -0,0 +1,12 @@
/* eslint-disable import/prefer-default-export */
import { hash } from './hash.mjs';
/**
* Generate Hashed string based on name and attributes
*
* @param {object} seed
* @param {string} seed.name A name, for example an icon name
* @param {object} seed.attributes An object of SVGElement Attrbutes
* @returns {string} A hashed string of 6 characters
*/
export const generateHashedKey = ({ name, attributes }) => hash(JSON.stringify([name, attributes]));

View File

@@ -0,0 +1,11 @@
/* eslint-disable import/prefer-default-export */
import path from 'path';
import { fileURLToPath } from 'url';
/**
* Get the current directory path.
*
* @param {string} currentPath
* @returns {string}
*/
export const getCurrentDirPath = (currentPath) => path.dirname(fileURLToPath(currentPath));

View File

@@ -0,0 +1,16 @@
/* eslint-disable import/prefer-default-export */
import { generateHashedKey } from './generateHashedKey.mjs';
/**
* Checks if array of items contains duplicated items
*
* @param {array} children an array of items
* @returns {Boolean} if items contains duplicated items.
*/
export const hasDuplicatedChildren = (children) => {
const hashedKeys = children.map(generateHashedKey);
return !hashedKeys.every(
(key, index) => index === hashedKeys.findIndex((childKey) => childKey === key),
);
};

View File

@@ -0,0 +1,19 @@
/* eslint-disable import/prefer-default-export */
/**
* djb2 hashing function
*
* @param {string} string
* @param {number} seed
* @returns {string} A hashed string of 6 characters
*/
export const hash = (string, seed = 5381) => {
let i = string.length;
while (i) {
// eslint-disable-next-line no-bitwise, no-plusplus
seed = (seed * 33) ^ string.charCodeAt(--i);
}
// eslint-disable-next-line no-bitwise
return (seed >>> 0).toString(36).substr(0, 6);
};

View File

@@ -0,0 +1,13 @@
/* eslint-disable import/prefer-default-export */
/**
* Merge two arrays and remove duplicates
*
* @param {array} a
* @param {array} b
* @returns {array}
*/
export const mergeArrays = (a, b) => {
a = a.concat(b);
a = a.filter((i, p) => a.indexOf(i) === p);
return a;
};

View File

@@ -0,0 +1,15 @@
/* eslint-disable import/prefer-default-export */
/**
* Minifies SVG
*
* @param {string} string
* @returns string
*/
export function minifySvg(string) {
return string
? string
.replace(/>[\r\n ]+</g, '><')
.replace(/(<.*?>)|\s+/g, (m, $1) => $1 || ' ')
.trim()
: '';
}

View File

@@ -0,0 +1,19 @@
/* eslint-disable import/prefer-default-export */
import fs from 'fs';
import path from 'path';
import { readMetadata } from './readMetadata.mjs';
/**
* Reads metadata from the icons/categories directories
*
* @param {string} directory
* @returns {object} A map of icon or category metadata
*/
export const readAllMetadata = (directory) =>
fs
.readdirSync(directory)
.filter((file) => path.extname(file) === '.json')
.reduce((acc, fileName) => {
acc[path.basename(fileName, '.json')] = readMetadata(fileName, directory);
return acc;
}, {});

View File

@@ -0,0 +1,11 @@
/* eslint-disable import/prefer-default-export */
import fs from 'fs';
import path from 'path';
/**
* Reads the file contents.
*
* @param {string} path
* @returns {string} The contents of a file
*/
export const readFile = (path) => fs.readFileSync(path.resolve(__dirname, '../', path), 'utf-8');

View File

@@ -0,0 +1,13 @@
/* eslint-disable import/prefer-default-export */
import fs from 'fs';
import path from 'path';
/**
* Reads metadata for an icon or category
*
* @param {string} fileName
* @param {string} directory
* @returns {object} The metadata for the icon or category
*/
export const readMetadata = (fileName, directory) =>
JSON.parse(fs.readFileSync(path.join(directory, fileName), 'utf-8'));

View File

@@ -0,0 +1,12 @@
/* eslint-disable import/prefer-default-export */
import fs from 'fs';
import path from 'path';
/**
* Read svg from directory
*
* @param {string} fileName
* @param {string} directory
*/
export const readSvg = (fileName, directory) =>
fs.readFileSync(path.join(directory, fileName), 'utf-8');

View File

@@ -0,0 +1,13 @@
/* eslint-disable import/prefer-default-export */
import fs from 'fs';
import path from 'path';
/**
* reads the icon directory
*
* @param {string} directory
* @param {string} fileExtension
* @returns {array} An array of file paths containing svgs
*/
export const readSvgDirectory = (directory, fileExtension = '.svg') =>
fs.readdirSync(directory).filter((file) => path.extname(file) === fileExtension);

View File

@@ -0,0 +1,12 @@
/* eslint-disable import/prefer-default-export */
import fs from 'fs';
import path from 'path';
/**
* Resets the file contents.
*
* @param {string} fileName
* @param {string} outputDirectory
*/
export const resetFile = (fileName, outputDirectory) =>
fs.writeFileSync(path.join(outputDirectory, fileName), '', 'utf-8');

View File

@@ -0,0 +1,13 @@
/* eslint-disable import/prefer-default-export */
/**
* @param {array} array
* @returns {array}
*/
export const shuffle = (array) => {
// eslint-disable-next-line no-plusplus
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
};

View File

@@ -0,0 +1,11 @@
/* eslint-disable import/prefer-default-export */
/**
* Converts string to CamelCase
*
* @param {string} string
* @returns {string} A camelized string
*/
export const toCamelCase = (string) =>
string.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2) =>
p2 ? p2.toUpperCase() : p1.toLowerCase(),
);

View File

@@ -0,0 +1,8 @@
/* eslint-disable import/prefer-default-export */
/**
* Converts string to KebabCase
*
* @param {string} string
* @returns {string} A kebabized string
*/
export const toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();

View File

@@ -0,0 +1,14 @@
/* eslint-disable import/prefer-default-export */
import { toCamelCase } from './toCamelCase.mjs';
/**
* Converts string to PascalCase
*
* @param {string} string
* @returns {string} A pascalized string
*/
export const toPascalCase = (string) => {
const camelCase = toCamelCase(string);
return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
};

View File

@@ -0,0 +1,13 @@
/* eslint-disable import/prefer-default-export */
import fs from 'fs';
import path from 'path';
/**
* 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');

View File

@@ -0,0 +1,17 @@
/* eslint-disable import/prefer-default-export */
import fs from 'fs';
import path from 'path';
import { writeFile } from './writeFile.mjs';
/**
* writes content to a file if it does not exist
*
* @param {string} content
* @param {string} fileName
* @param {string} outputDirectory
*/
export const writeFileIfNotExists = (content, fileName, outputDirectory) => {
if (!fs.existsSync(path.join(outputDirectory, fileName))) {
writeFile(content, fileName, outputDirectory);
}
};

View File

@@ -0,0 +1,13 @@
/* eslint-disable import/prefer-default-export */
import fs from 'fs';
import path from 'path';
/**
* writes content to a file
*
* @param {string} fileName
* @param {string} outputDirectory
* @param {string} content
*/
export const writeSvgFile = (fileName, outputDirectory, content) =>
fs.writeFileSync(path.join(outputDirectory, fileName), content, 'utf-8');

View File

@@ -1,6 +1,7 @@
import path from 'path';
import fs from 'fs';
import { toPascalCase, resetFile, appendFile } from '../../../scripts/helpers.mjs';
// eslint-disable-next-line import/no-extraneous-dependencies
import { toPascalCase, resetFile, appendFile } from '@lucide/helpers';
import { deprecationReasonTemplate } from '../utils/deprecationReasonTemplate.mjs';
const getImportString = (

View File

@@ -1,5 +1,5 @@
import path from 'path';
import { resetFile, appendFile } from '../../../scripts/helpers.mjs';
import { resetFile, appendFile } from '@lucide/helpers';
export default function generateDynamicImports({
iconNodes,

View File

@@ -1,8 +1,15 @@
import path from 'path';
import { toPascalCase, resetFile, appendFile } from '../../../scripts/helpers.mjs';
// eslint-disable-next-line import/no-extraneous-dependencies
import { toPascalCase, toCamelCase, resetFile, appendFile } from '@lucide/helpers';
export default (inputEntry, outputDirectory, iconNodes, iconFileExtension = '') => {
export default (
inputEntry,
outputDirectory,
iconNodes,
exportModuleNameCasing,
iconFileExtension = '',
) => {
const fileName = path.basename(inputEntry);
// Reset file
@@ -12,7 +19,13 @@ export default (inputEntry, outputDirectory, iconNodes, iconFileExtension = '')
// Generate Import for Icon VNodes
icons.forEach((iconName) => {
const componentName = toPascalCase(iconName);
let componentName;
if (exportModuleNameCasing === 'camel') {
componentName = toCamelCase(iconName);
} else if (exportModuleNameCasing === 'pascal') {
componentName = toPascalCase(iconName);
}
const importString = `export { default as ${componentName} } from './${iconName}${iconFileExtension}';\n`;
appendFile(importString, fileName, outputDirectory);
});

View File

@@ -1,7 +1,7 @@
import fs from 'fs';
import path from 'path';
import prettier from 'prettier';
import { readSvg, toPascalCase } from '../../../scripts/helpers.mjs';
import { readSvg, toPascalCase } from '@lucide/helpers';
import { deprecationReasonTemplate } from '../utils/deprecationReasonTemplate.mjs';
export default ({

View File

@@ -3,20 +3,19 @@ import fs from 'fs';
import path from 'path';
import getArgumentOptions from 'minimist';
import { readSvgDirectory } from '@lucide/helpers';
import renderIconsObject from './render/renderIconsObject.mjs';
import generateIconFiles from './building/generateIconFiles.mjs';
import generateExportsFile from './building/generateExportsFile.mjs';
import { readSvgDirectory, getCurrentDirPath } from '../../scripts/helpers.mjs';
import generateAliasesFile from './building/generateAliasesFile.mjs';
// eslint-disable-next-line import/no-named-as-default, import/no-named-as-default-member
import getIconMetaData from './utils/getIconMetaData.mjs';
import generateDynamicImports from './building/generateDynamicImports.mjs';
const cliArguments = getArgumentOptions(process.argv.slice(2));
const currentDir = getCurrentDirPath(import.meta.url);
const ICONS_DIR = path.resolve(currentDir, '../../icons');
const ICONS_DIR = path.resolve(process.cwd(), '../../icons');
const OUTPUT_DIR = path.resolve(process.cwd(), cliArguments.output || '../build');
if (!fs.existsSync(OUTPUT_DIR)) {
@@ -30,6 +29,7 @@ const {
iconFileExtension = '.js',
importImportFileExtension = '',
exportFileName = 'index.js',
exportModuleNameCasing = 'pascal',
withAliases = false,
aliasNamesOnly = false,
withDynamicImports = false,
@@ -72,6 +72,7 @@ async function buildIcons() {
iconFileExtension,
outputDirectory: OUTPUT_DIR,
fileExtension: aliasesFileExtension,
exportModuleNameCasing,
aliasImportFileExtension,
separateAliasesFile,
showLog: !silent,
@@ -92,6 +93,7 @@ async function buildIcons() {
path.join(OUTPUT_DIR, 'icons', exportFileName),
path.join(OUTPUT_DIR, 'icons'),
icons,
exportModuleNameCasing,
importImportFileExtension,
);
}

View File

@@ -1,2 +1,3 @@
// eslint-disable-next-line import/prefer-default-export
export { default as getAliases } from './utils/getAliases.mjs';
export { default as getIconMetaData } from './utils/getIconMetaData.mjs';
export { default as renderIconsObject } from './render/renderIconsObject.mjs';

View File

@@ -1,7 +1,7 @@
{
"name": "@lucide/build-icons",
"description": "A internal used package to build icon code files for the lucide icon library packages.",
"version": "1.0.0",
"version": "1.1.0",
"main": "index.mjs",
"type": "module",
"scripts": {
@@ -16,7 +16,11 @@
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@lucide/helpers": "workspace:*"
},
"dependencies": {
"@lucide/helpers": "^1.0.0",
"minimist": "^1.2.7",
"node-fetch": "^3.2.10",
"prettier": "2.7.1",

View File

@@ -1,6 +1,6 @@
import { basename } from 'path';
import { parseSync } from 'svgson';
import { generateHashedKey, readSvg, hasDuplicatedChildren } from '../../../scripts/helpers.mjs';
import { generateHashedKey, readSvg, hasDuplicatedChildren } from '@lucide/helpers';
/**
* Build an object in the format: `{ <name>: <contents> }`.

View File

@@ -0,0 +1,16 @@
import path from 'path';
import { readSvgDirectory } from '@lucide/helpers';
async function getAliases(iconDirectory) {
const iconJsons = readSvgDirectory(iconDirectory, '.json');
const aliasesEntries = await Promise.all(
iconJsons.map(async (jsonFile) => {
const file = await import(path.join(iconDirectory, jsonFile), { assert: { type: 'json' } });
return [path.basename(jsonFile, '.json'), file.default];
}),
);
return Object.fromEntries(aliasesEntries);
}
export default getAliases;

View File

@@ -1,10 +1,11 @@
import path from 'path';
import { readSvgDirectory } from '../../../scripts/helpers.mjs';
import { readSvgDirectory } from '@lucide/helpers';
async function getIconMetaData(iconDirectory) {
const iconJsons = readSvgDirectory(iconDirectory, '.json');
const aliasesEntries = await Promise.all(
iconJsons.map(async (jsonFile) => {
/** eslint-disable */
const file = await import(path.join(iconDirectory, jsonFile), { assert: { type: 'json' } });
return [path.basename(jsonFile, '.json'), file.default];
}),