[READ-ONLY] a fast, modern browser for the npm registry
at main 99 lines 3.2 kB view raw
1import type { IconifyJSON } from '@iconify-json/lucide' 2import { promises as fs } from 'node:fs' 3import { fileURLToPath } from 'node:url' 4import path from 'node:path' 5import { 6 ADDITIONAL_ICONS, 7 EXTENSION_ICONS, 8 FILENAME_ICONS, 9 COMPOUND_EXTENSIONS, 10 DEFAULT_ICON, 11} from '../app/utils/file-icons.ts' 12 13const rootDir = process.cwd() 14const outputDevPath = path.join(rootDir, 'public', 'file-tree-sprite.svg') 15const outputStagePath = path.join(rootDir, 'public-dev', 'file-tree-sprite.svg') 16const outputProdPath = path.join(rootDir, 'public-prod', 'file-tree-sprite.svg') 17 18const COLLECTION_NAMES = ['lucide', 'simple-icons', 'svg-spinners', 'vscode-icons'] 19 20const COLLECTION_REGEXP = new RegExp(`^(${COLLECTION_NAMES.join('|')})-(.+)$`) 21 22async function loadCollections() { 23 const collections: { [key: string]: IconifyJSON } = {} 24 for (const name of COLLECTION_NAMES) { 25 const filePathUrl = import.meta.resolve(`@iconify-json/${name}/icons.json`) 26 const filePath = fileURLToPath(filePathUrl) 27 const raw = await fs.readFile(filePath, 'utf8') 28 collections[name] = JSON.parse(raw) 29 } 30 return collections 31} 32 33function groupByCollection(iconNames: string[]) { 34 const grouped: { [key: string]: string[] } = {} 35 for (const name of iconNames) { 36 const [, group, iconName] = name.match(COLLECTION_REGEXP) || [] 37 if (group && iconName) { 38 grouped[group] ||= [] 39 grouped[group].push(iconName) 40 } 41 } 42 return grouped 43} 44 45function buildSprite( 46 grouped: { [key: string]: string[] }, 47 collections: { [key: string]: IconifyJSON }, 48) { 49 let symbols = '' 50 Object.entries(grouped).forEach(([prefix, iconNames]) => { 51 const collection = collections[prefix] 52 53 if (!collection?.icons) return 54 55 const defaultWidth = collection.width ?? 16 56 const defaultHeight = collection.height ?? 16 57 58 iconNames.forEach(name => { 59 const icon = collection.icons[name] 60 61 if (!icon?.body) return 62 63 const width = icon.width ?? defaultWidth 64 const height = icon.height ?? defaultHeight 65 const viewBox = `0 0 ${width} ${height}` 66 const id = `${collection.prefix}-${name}` 67 symbols += `<symbol id="${id}" viewBox="${viewBox}">${icon.body}</symbol>` 68 }) 69 }) 70 return `<svg xmlns="http://www.w3.org/2000/svg" style="display:none">${symbols}</svg>\n` 71} 72 73async function main() { 74 const collections = await loadCollections() 75 const iconNames = [ 76 ...Object.values(EXTENSION_ICONS), 77 ...Object.values(FILENAME_ICONS), 78 ...Object.values(COMPOUND_EXTENSIONS), 79 ...Object.values(ADDITIONAL_ICONS), 80 DEFAULT_ICON, 81 ] 82 const grouped = groupByCollection(iconNames) 83 const sprite = buildSprite(grouped, collections) 84 await Promise.all([ 85 fs.mkdir(path.dirname(outputDevPath), { recursive: true }), 86 fs.mkdir(path.dirname(outputStagePath), { recursive: true }), 87 fs.mkdir(path.dirname(outputProdPath), { recursive: true }), 88 ]) 89 await Promise.all([ 90 fs.writeFile(outputDevPath, sprite, 'utf8'), 91 fs.writeFile(outputStagePath, sprite, 'utf8'), 92 fs.writeFile(outputProdPath, sprite, 'utf8'), 93 ]) 94} 95 96main().catch(error => { 97 console.error(error) 98 process.exitCode = 1 99})