chore(scripts): Refactor scripts to typescript (#3316)

* Adjust typescript types

* adjust types

* fix types in all helper files

* Fix types

* Migrate js files to ts files

* Refactor to TS files

* Rename extentions

* Adjust imports

* Fix builds

* Update lockfile

* Fix last typescript migration

* Fix entry path @lucide/outline-svg

* Fix types

* add checkout step

* format files

* Format files
This commit is contained in:
Eric Fennis
2025-06-18 15:47:24 +02:00
committed by GitHub
parent 7517894f2d
commit 3e644fda2d
111 changed files with 833 additions and 527 deletions

View File

@@ -30,19 +30,20 @@
"scripts": {
"copy:license": "cp ../../LICENSE ./LICENSE",
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm build:bundles && pnpm build:lib && pnpm build:tags",
"build:tags": "node ../../scripts/migrateIconsToTags.mjs",
"build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mjs --iconFileExtension=.ts --withAliases --aliasNamesOnly --aliasesFileExtension=.ts --exportFileName=index.ts",
"build:lib": "node ./scripts/buildLib.mjs",
"build:tags": "node ./scripts/migrateIconsToTags.mts",
"build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mts --iconFileExtension=.ts --withAliases --aliasNamesOnly --aliasesFileExtension=.ts --exportFileName=index.ts",
"build:lib": "node ./scripts/buildLib.mts",
"build:bundles": "rollup -c rollup.config.mjs",
"clean": "rm -rf lib && rm -rf build && rm -rf icons && rm -f sprite.svg",
"version": "pnpm version --git-tag-version=false"
},
"devDependencies": {
"@lucide/build-icons": "workspace:*",
"@lucide/helpers": "workspace:*",
"@lucide/rollup-plugins": "workspace:*",
"@types/node": "^22.15.30",
"prettier": "^2.3.2",
"svgson": "^5.2.1",
"@lucide/build-icons": "workspace:*",
"@lucide/rollup-plugins": "workspace:*",
"@lucide/helpers": "workspace:*",
"rollup": "^4.40.0",
"rollup-plugin-dts": "^6.2.1"
}

View File

@@ -1,18 +1,16 @@
import fs from 'fs';
import path from 'path';
import getArgumentOptions from 'minimist';
import { parseSync } from 'svgson';
import { readSvgDirectory, getCurrentDirPath } from '@lucide/helpers';
import readSvgs from './readSvgs.mjs';
import generateSprite from './generateSprite.mjs';
import generateIconNodes from './generateIconNodes.mjs';
import copyIcons from './copyIcons.mjs';
import readSvgs from './readSvgs.mts';
import generateSprite from './generateSprite.mts';
import generateIconNodes from './generateIconNodes.mts';
import copyIcons from './copyIcons.mts';
import pkg from '../package.json' with { type: 'json' };
const cliArguments = getArgumentOptions(process.argv.slice(2));
const createDirectory = (dir) => {
const createDirectory = (dir: string) => {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
@@ -22,7 +20,7 @@ const currentDir = getCurrentDirPath(import.meta.url);
const PACKAGE_DIR = path.resolve(currentDir, '../');
const ICONS_DIR = path.join(PACKAGE_DIR, '../../icons');
const LIB_DIR = path.join(PACKAGE_DIR, cliArguments.output || 'lib');
const LIB_DIR = path.join(PACKAGE_DIR, 'lib');
const ICON_MODULE_DIR = path.join(LIB_DIR, 'icons');
const license = `@license ${pkg.name} v${pkg.version} - ${pkg.license}`;
@@ -33,14 +31,8 @@ createDirectory(ICON_MODULE_DIR);
const svgFiles = await readSvgDirectory(ICONS_DIR);
const svgs = await readSvgs(svgFiles, ICONS_DIR);
const parsedSvgs = svgs.map(({ name, contents }) => ({
name,
contents,
parsedSvg: parseSync(contents),
}));
await Promise.all([
generateSprite(parsedSvgs, PACKAGE_DIR, license),
generateIconNodes(parsedSvgs, PACKAGE_DIR),
copyIcons(parsedSvgs, PACKAGE_DIR, license),
generateSprite(svgs, PACKAGE_DIR, license),
generateIconNodes(svgs, PACKAGE_DIR),
copyIcons(svgs, PACKAGE_DIR, license),
]);

View File

@@ -1,7 +1,12 @@
import { writeFile } from 'fs/promises';
import { existsSync, unlinkSync, mkdirSync } from 'fs';
import { type SVGFile } from './readSvgs.mts';
export default async function copyIcons(parsedSvgs, packageDir, license) {
export default async function copyIcons(
parsedSvgs: SVGFile[],
packageDir: string,
license: string
) {
const iconsDirectory = `${packageDir}/icons`;
if (existsSync(iconsDirectory)) {

View File

@@ -1,7 +1,7 @@
/* eslint-disable import/no-extraneous-dependencies */
import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs';
import base64SVG from '@lucide/build-icons/utils/base64SVG';
import defineExportTemplate from '@lucide/build-icons/utils/defineExportTemplate';
export default async ({ componentName, iconName, getSvg, deprecated, deprecationReason }) => {
export default defineExportTemplate(async ({ componentName, iconName, getSvg, deprecated, deprecationReason }) => {
let svgContents = await getSvg();
const svgBase64 = base64SVG(svgContents);
@@ -29,4 +29,4 @@ ${svgContents}\
export default ${componentName};
`;
};
});

View File

@@ -1,11 +1,12 @@
import { writeFile } from '@lucide/helpers';
import { type SVGFile } from './readSvgs.mts';
export default async function generateIconNodes(parsedSvgs, packageDir) {
export default async function generateIconNodes(parsedSvgs: SVGFile[], packageDir: string) {
const iconNodes = parsedSvgs.reduce((acc, { name, parsedSvg }) => {
acc[name] = parsedSvg.children.map(({ name, attributes }) => [name, attributes]);
return acc;
}, {});
}, {} as Record<string, [string, Record<string, unknown> | undefined][]>);
const iconNodesStringified = JSON.stringify(iconNodes, null, 2);

View File

@@ -1,36 +1,44 @@
/* eslint-disable import/no-extraneous-dependencies */
import { stringify } from 'svgson';
import { type INode, stringify } from 'svgson';
import { format } from 'prettier';
import { appendFile } from '@lucide/helpers';
import { type SVGFile } from './readSvgs.mts';
export default async function generateSprite(svgs, packageDir, license) {
const symbols = svgs.map(({ name, parsedSvg }) => ({
export default async function generateSprite(
svgs: SVGFile[],
packageDir: string,
license: string
) {
const symbols = svgs.map<INode>(({ name, parsedSvg }) => ({
name: 'symbol',
type: 'element',
value: '',
attributes: {
id: name,
},
children: parsedSvg.children,
}));
const spriteSvgObject = {
const spriteSvgObject: INode = {
name: 'svg',
type: 'element',
attributes: {
xmlns: 'http://www.w3.org/2000/svg',
version: '1.1',
},
value: '',
children: [
{
name: 'defs',
type: 'element',
children: symbols,
},
value: '',
} as INode,
],
};
const spriteSvg = stringify(spriteSvgObject);
const prettifiedSprite = format(spriteSvg, { parser: 'babel' }).replace(/;/g, '');
const prettifiedSprite = (await format(spriteSvg, { parser: 'babel' })).replace(/;/g, '');
const xmlMeta = `<?xml version="1.0" encoding="utf-8"?>\n<!-- ${license} -->\n`;

View File

@@ -0,0 +1,17 @@
import path from 'path';
import { writeFile, getCurrentDirPath, readAllMetadata } from '@lucide/helpers';
const currentDir = getCurrentDirPath(import.meta.url);
const ICONS_DIR = path.resolve(currentDir, '../icons');
const icons = await readAllMetadata(ICONS_DIR);
const tags = Object.keys(icons)
.sort()
.reduce((acc, iconName) => {
acc[iconName] = icons[iconName].tags;
return acc;
}, {});
const tagsContent = JSON.stringify(tags, null, 2);
await writeFile(tagsContent, 'tags.json', path.resolve(process.cwd()));

View File

@@ -1,6 +1,7 @@
/* eslint-disable import/no-extraneous-dependencies */
import { basename } from 'path';
import { readSvg } from '@lucide/helpers';
import { type INode, parseSync } from 'svgson';
/**
* Build an object in the format: `{ <name>: <contents> }`.
@@ -8,13 +9,23 @@ import { readSvg } from '@lucide/helpers';
* @param {Function} getSvg - A function that returns the contents of an SVG file given a filename.
* @returns {Object}
*/
export default function readSVGs(svgFiles, iconsDirectory) {
export default function readSVGs(svgFiles: string[], iconsDirectory: string) {
const SVGReadPromises = svgFiles.map(async (svgFile) => {
const name = basename(svgFile, '.svg');
const contents = await readSvg(svgFile, iconsDirectory);
return { name, contents };
return {
name,
contents,
parsedSvg: parseSync(contents),
};
});
return Promise.all(SVGReadPromises);
}
export type SVGFile = {
name: string;
contents: string;
parsedSvg: INode
}

View File

@@ -11,6 +11,7 @@
"allowJs": true,
"lib": ["esnext", "dom"],
"resolveJsonModule": true,
"allowImportingTsExtensions": true,
"sourceMap": true,
"outDir": "./dist",
},