Beautiful
1import fs from 'fs';
2import path from 'path';
3import { readSvgDirectory } from '@lucide/helpers';
4
5const currentDir = process.cwd();
6const ICONS_DIR = path.resolve(currentDir, '../icons');
7const svgFiles = readSvgDirectory(ICONS_DIR, '.json');
8
9const location = path.resolve(currentDir, '.vitepress/data', 'relatedIcons.json');
10
11if (fs.existsSync(location)) {
12 fs.unlinkSync(location);
13}
14
15const nameWeight = 5;
16const tagWeight = 4;
17const categoryWeight = 3;
18
19const MAX_RELATED_ICONS = 4 * 17; // grid of 4x17 icons, = 68 icons
20
21const arrayMatches = (a, b) => {
22 return a.filter((item) => b.includes(item)).length;
23};
24
25const nameParts = (icon) =>
26 [
27 icon.name,
28 ...(icon.aliases?.map((alias) => (typeof alias === 'string' ? alias : alias.name)) ?? []),
29 ]
30 .join('-')
31 .split('-')
32 .filter((word) => word.length > 2);
33
34const getRelatedIcons = (currentIcon, icons) => {
35 const iconSimilarity = (item) =>
36 nameWeight * arrayMatches(nameParts(item), nameParts(currentIcon)) +
37 categoryWeight * arrayMatches(item.categories ?? [], currentIcon.categories ?? []) +
38 tagWeight * arrayMatches(item.tags ?? [], currentIcon.tags ?? []);
39 return icons
40 .filter((i) => i.name !== currentIcon.name)
41 .map((icon) => ({ icon, similarity: iconSimilarity(icon) }))
42 .filter((a) => a.similarity > 0) // @todo: maybe require a minimal non-zero similarity
43 .sort((a, b) => b.similarity - a.similarity)
44 .map((i) => i.icon)
45 .slice(0, MAX_RELATED_ICONS);
46};
47
48const iconsMetaDataPromises = svgFiles.map(async (iconName) => {
49 const metaData = JSON.parse(fs.readFileSync(`../icons/${iconName}`));
50
51 const name = iconName.replace('.json', '');
52
53 return {
54 name,
55 ...metaData.default,
56 };
57});
58
59const iconsMetaData = await Promise.all(iconsMetaDataPromises);
60
61const relatedIcons = iconsMetaData.map((icon) => {
62 const iconRelatedIcons = getRelatedIcons(icon, iconsMetaData);
63 return [icon.name, iconRelatedIcons.map((i) => i.name)];
64});
65
66fs.promises
67 .writeFile(location, JSON.stringify(Object.fromEntries(relatedIcons), null, 2), 'utf-8')
68 .then(() => {
69 console.log('Successfully written relatedIcons.json file');
70 })
71 .catch((error) => {
72 throw new Error(`Something went wrong generating iconNode files,\n ${error}`);
73 });