Alias support for lucide package (#1592)

* Setup aliases for lucide

* Make aliases work for lucide package
This commit is contained in:
Eric Fennis
2023-10-17 21:27:46 +02:00
committed by GitHub
parent 52adb78df8
commit dbfce919fc
9 changed files with 58 additions and 26 deletions

View File

@@ -25,7 +25,7 @@
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm build:bundles", "build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm build:bundles",
"copy:license": "cp ../../LICENSE ./LICENSE", "copy:license": "cp ../../LICENSE ./LICENSE",
"clean": "rm -rf dist && rm -rf stats && rm -rf ./src/icons/*.ts", "clean": "rm -rf dist && rm -rf stats && rm -rf ./src/icons/*.ts",
"build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mjs --iconFileExtension=.ts", "build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mjs --iconFileExtension=.ts --withAliases --aliasNamesOnly --aliasesFileExtension=.ts --exportFileName=index.ts",
"build:types": "node ./scripts/buildTypes.mjs", "build:types": "node ./scripts/buildTypes.mjs",
"build:bundles": "rollup -c rollup.config.mjs", "build:bundles": "rollup -c rollup.config.mjs",
"test": "vitest run", "test": "vitest run",

View File

@@ -40,7 +40,7 @@ const configs = bundles
...( ...(
format === 'umd' ? [ format === 'umd' ? [
replace({ replace({
'icons = {}': 'icons = allIcons', 'icons = {}': 'icons = iconAndAliases',
delimiters: ['', ''], delimiters: ['', ''],
preventAssignment: false, preventAssignment: false,
}), }),

View File

@@ -0,0 +1,2 @@
export * from './icons'
export * from './aliases'

View File

@@ -1,5 +1,5 @@
import replaceElement from './replaceElement'; import replaceElement from './replaceElement';
import * as allIcons from './icons'; import * as iconAndAliases from './iconsAndAliases';
/** /**
* Replaces all elements with matching nameAttr with the defined icons * Replaces all elements with matching nameAttr with the defined icons
@@ -43,5 +43,5 @@ export { default as createElement } from './createElement';
/* /*
Icons exports. Icons exports.
*/ */
export { allIcons as icons }; export { iconAndAliases as icons };
export * from './icons'; export * from './icons';

View File

@@ -66,7 +66,7 @@ interface ReplaceElementOptions {
const replaceElement = (element: Element, { nameAttr, icons, attrs }: ReplaceElementOptions) => { const replaceElement = (element: Element, { nameAttr, icons, attrs }: ReplaceElementOptions) => {
const iconName = element.getAttribute(nameAttr); const iconName = element.getAttribute(nameAttr);
if(iconName == null) return if (iconName == null) return
const ComponentName = toPascalCase(iconName); const ComponentName = toPascalCase(iconName);

View File

@@ -2,4 +2,6 @@
exports[`createIcons > should add custom attributes 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\" fill=\\"black\\" stroke=\\"currentColor\\" stroke-width=\\"2\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" data-lucide=\\"volume-2\\" class=\\"lucide lucide-volume-2 icon custom-class\\"><polygon points=\\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\\"></polygon><path d=\\"M15.54 8.46a5 5 0 0 1 0 7.07\\"></path><path d=\\"M19.07 4.93a10 10 0 0 1 0 14.14\\"></path></svg>"`; exports[`createIcons > should add custom attributes 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\" fill=\\"black\\" stroke=\\"currentColor\\" stroke-width=\\"2\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" data-lucide=\\"volume-2\\" class=\\"lucide lucide-volume-2 icon custom-class\\"><polygon points=\\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\\"></polygon><path d=\\"M15.54 8.46a5 5 0 0 1 0 7.07\\"></path><path d=\\"M19.07 4.93a10 10 0 0 1 0 14.14\\"></path></svg>"`;
exports[`createIcons > should read elements from DOM and replace icon with alias name 1`] = `"<svg 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\\" data-lucide=\\"grid\\" class=\\"lucide lucide-grid\\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\"></rect><path d=\\"M3 9h18\\"></path><path d=\\"M3 15h18\\"></path><path d=\\"M9 3v18\\"></path><path d=\\"M15 3v18\\"></path></svg>"`;
exports[`createIcons > should read elements from DOM and replace it with icons 1`] = `"<svg 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\\" data-lucide=\\"volume-2\\" class=\\"lucide lucide-volume-2\\"><polygon points=\\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\\"></polygon><path d=\\"M15.54 8.46a5 5 0 0 1 0 7.07\\"></path><path d=\\"M19.07 4.93a10 10 0 0 1 0 14.14\\"></path></svg>"`; exports[`createIcons > should read elements from DOM and replace it with icons 1`] = `"<svg 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\\" data-lucide=\\"volume-2\\" class=\\"lucide lucide-volume-2\\"><polygon points=\\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\\"></polygon><path d=\\"M15.54 8.46a5 5 0 0 1 0 7.07\\"></path><path d=\\"M19.07 4.93a10 10 0 0 1 0 14.14\\"></path></svg>"`;

View File

@@ -1,18 +1,17 @@
import { describe, it, expect } from 'vitest'; import { describe, it, expect } from 'vitest';
import * as icons from '../src/icons'; import { createIcons, icons } from '../src/lucide';
import { createIcons } from '../src/lucide';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import { parseSync, stringify } from 'svgson'; import { parseSync, stringify } from 'svgson';
const ICONS_DIR = path.resolve(__dirname, '../../../icons'); const ICONS_DIR = path.resolve(__dirname, '../../../icons');
const getOriginalSvg = (iconName) => { const getOriginalSvg = (iconName, aliasName) => {
const svgContent = fs.readFileSync(path.join(ICONS_DIR, `${iconName}.svg`), 'utf8'); const svgContent = fs.readFileSync(path.join(ICONS_DIR, `${iconName}.svg`), 'utf8');
const svgParsed = parseSync(svgContent); const svgParsed = parseSync(svgContent);
svgParsed.attributes['data-lucide'] = iconName; svgParsed.attributes['data-lucide'] = aliasName ?? iconName;
svgParsed.attributes['class'] = `lucide lucide-${iconName}`; svgParsed.attributes['class'] = `lucide lucide-${aliasName ?? iconName}`;
return stringify(svgParsed, { selfClose: false }); return stringify(svgParsed, { selfClose: false });
}; };
@@ -86,4 +85,15 @@ describe('createIcons', () => {
expect(attributesAndValues).toEqual(expect.objectContaining(attrs)); expect(attributesAndValues).toEqual(expect.objectContaining(attrs));
}); });
it('should read elements from DOM and replace icon with alias name', () => {
document.body.innerHTML = `<i data-lucide="grid"></i>`;
createIcons({ icons });
const svg = getOriginalSvg('grid-3x3', 'grid');
expect(document.body.innerHTML).toBe(svg)
expect(document.body.innerHTML).toMatchSnapshot()
});
}); });

View File

@@ -12,6 +12,7 @@ export default async function generateAliasesFile({
iconFileExtension = '.js', iconFileExtension = '.js',
aliases, aliases,
aliasImportFileExtension, aliasImportFileExtension,
aliasNamesOnly = false,
separateAliasesFile = false, separateAliasesFile = false,
showLog = true, showLog = true,
}) { }) {
@@ -24,14 +25,28 @@ export default async function generateAliasesFile({
// Generate Import for Icon VNodes // Generate Import for Icon VNodes
await Promise.all( await Promise.all(
icons.map(async (iconName) => { icons.map(async (iconName, index) => {
const componentName = toPascalCase(iconName); const componentName = toPascalCase(iconName);
const iconAliases = aliases[iconName]?.aliases; const iconAliases = aliases[iconName]?.aliases;
let importString = `// ${componentName} aliases\n`; let importString = '';
importString += getImportString(`${componentName}Icon`, iconName, aliasImportFileExtension); if ((iconAliases != null && Array.isArray(iconAliases)) || !aliasNamesOnly) {
importString += getImportString(`Lucide${componentName}`, iconName, aliasImportFileExtension); if (index > 0) {
importString += '\n';
}
importString += `// ${componentName} aliases\n`;
}
if (!aliasNamesOnly) {
importString += getImportString(`${componentName}Icon`, iconName, aliasImportFileExtension);
importString += getImportString(
`Lucide${componentName}`,
iconName,
aliasImportFileExtension,
);
}
if (iconAliases != null && Array.isArray(iconAliases)) { if (iconAliases != null && Array.isArray(iconAliases)) {
await Promise.all( await Promise.all(
@@ -57,23 +72,24 @@ export default async function generateAliasesFile({
exportFileIcon, exportFileIcon,
aliasImportFileExtension, aliasImportFileExtension,
); );
importString += getImportString(
`${componentNameAlias}Icon`,
exportFileIcon,
aliasImportFileExtension,
);
importString += getImportString( if (!aliasNamesOnly) {
`Lucide${componentNameAlias}`, importString += getImportString(
exportFileIcon, `${componentNameAlias}Icon`,
aliasImportFileExtension, exportFileIcon,
); aliasImportFileExtension,
);
importString += getImportString(
`Lucide${componentNameAlias}`,
exportFileIcon,
aliasImportFileExtension,
);
}
}), }),
); );
} }
importString += '\n';
appendFile(importString, fileName, outputDirectory); appendFile(importString, fileName, outputDirectory);
}), }),
); );

View File

@@ -31,6 +31,7 @@ const {
importImportFileExtension = '', importImportFileExtension = '',
exportFileName = 'index.js', exportFileName = 'index.js',
withAliases = false, withAliases = false,
aliasNamesOnly = false,
withDynamicImports = false, withDynamicImports = false,
separateAliasesFile = false, separateAliasesFile = false,
aliasesFileExtension = '.js', aliasesFileExtension = '.js',
@@ -66,6 +67,7 @@ async function buildIcons() {
await generateAliasesFile({ await generateAliasesFile({
iconNodes: icons, iconNodes: icons,
aliases, aliases,
aliasNamesOnly,
iconFileExtension, iconFileExtension,
outputDirectory: OUTPUT_DIR, outputDirectory: OUTPUT_DIR,
fileExtension: aliasesFileExtension, fileExtension: aliasesFileExtension,