feat:移除了弹窗,服务器添加sls
This commit is contained in:
213
packages/assets/build/add-icons.ts
Normal file
213
packages/assets/build/add-icons.ts
Normal file
@ -0,0 +1,213 @@
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import readline from 'node:readline'
|
||||
|
||||
const packageRoot = path.resolve(__dirname, '..')
|
||||
const iconsDir = path.join(packageRoot, 'icons')
|
||||
const lucideIconsDir = path.join(packageRoot, 'node_modules/lucide-static/icons')
|
||||
|
||||
function listAvailableIcons(): string[] {
|
||||
if (!fs.existsSync(lucideIconsDir)) {
|
||||
return []
|
||||
}
|
||||
return fs
|
||||
.readdirSync(lucideIconsDir)
|
||||
.filter((file) => file.endsWith('.svg'))
|
||||
.map((file) => path.basename(file, '.svg'))
|
||||
.sort()
|
||||
}
|
||||
|
||||
function paginateList(allIcons: string[], pageSize = 20): void {
|
||||
let page = 0
|
||||
let search = ''
|
||||
let filteredIcons = allIcons
|
||||
|
||||
const getFilteredIcons = (): string[] => {
|
||||
if (!search) return allIcons
|
||||
return allIcons.filter((icon) => icon.includes(search))
|
||||
}
|
||||
|
||||
const renderPage = (): void => {
|
||||
console.clear()
|
||||
filteredIcons = getFilteredIcons()
|
||||
const totalPages = Math.max(1, Math.ceil(filteredIcons.length / pageSize))
|
||||
|
||||
if (page >= totalPages) page = Math.max(0, totalPages - 1)
|
||||
|
||||
const start = page * pageSize
|
||||
const end = Math.min(start + pageSize, filteredIcons.length)
|
||||
const pageIcons = filteredIcons.slice(start, end)
|
||||
|
||||
console.log(`\x1b[1mAvailable Lucide Icons\x1b[0m`)
|
||||
console.log(`\x1b[2mSearch: \x1b[0m${search || '\x1b[2m(type to search)\x1b[0m'}\n`)
|
||||
|
||||
if (pageIcons.length === 0) {
|
||||
console.log(` \x1b[2mNo icons found matching "${search}"\x1b[0m`)
|
||||
} else {
|
||||
pageIcons.forEach((icon) => {
|
||||
if (search) {
|
||||
const highlighted = icon.replace(search, `\x1b[33m${search}\x1b[0m`)
|
||||
console.log(` ${highlighted}`)
|
||||
} else {
|
||||
console.log(` ${icon}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
console.log(
|
||||
`\n\x1b[2m${filteredIcons.length}/${allIcons.length} icons | Page ${page + 1}/${totalPages} | ← → navigate | :q quit\x1b[0m`,
|
||||
)
|
||||
}
|
||||
|
||||
renderPage()
|
||||
|
||||
readline.emitKeypressEvents(process.stdin)
|
||||
if (process.stdin.isTTY) {
|
||||
process.stdin.setRawMode(true)
|
||||
}
|
||||
|
||||
process.stdin.on('keypress', (str, key) => {
|
||||
if (key.ctrl && key.name === 'c') {
|
||||
console.clear()
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
// :q to quit
|
||||
if (search === ':' && key.name === 'q') {
|
||||
console.clear()
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
// Navigation
|
||||
if (key.name === 'right') {
|
||||
const totalPages = Math.max(1, Math.ceil(filteredIcons.length / pageSize))
|
||||
if (page < totalPages - 1) {
|
||||
page++
|
||||
renderPage()
|
||||
}
|
||||
return
|
||||
}
|
||||
if (key.name === 'left') {
|
||||
if (page > 0) {
|
||||
page--
|
||||
renderPage()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Backspace
|
||||
if (key.name === 'backspace') {
|
||||
search = search.slice(0, -1)
|
||||
page = 0
|
||||
renderPage()
|
||||
return
|
||||
}
|
||||
|
||||
// Escape to clear search
|
||||
if (key.name === 'escape') {
|
||||
search = ''
|
||||
page = 0
|
||||
renderPage()
|
||||
return
|
||||
}
|
||||
|
||||
// Type to search
|
||||
if (str && str.length === 1 && !key.ctrl && !key.meta) {
|
||||
search += str
|
||||
page = 0
|
||||
renderPage()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function addIcon(iconId: string, overwrite: boolean): boolean {
|
||||
const sourcePath = path.join(lucideIconsDir, `${iconId}.svg`)
|
||||
const targetPath = path.join(iconsDir, `${iconId}.svg`)
|
||||
|
||||
if (!fs.existsSync(sourcePath)) {
|
||||
console.error(`❌ Icon "${iconId}" not found in lucide-static`)
|
||||
console.error(` Run with --list to see available icons`)
|
||||
return false
|
||||
}
|
||||
|
||||
if (fs.existsSync(targetPath) && !overwrite) {
|
||||
console.log(`⏭️ Skipping "${iconId}" (already exists, use --overwrite to replace)`)
|
||||
return false
|
||||
}
|
||||
|
||||
fs.copyFileSync(sourcePath, targetPath)
|
||||
console.log(`✅ Added "${iconId}"`)
|
||||
return true
|
||||
}
|
||||
|
||||
function main(): void {
|
||||
const args = process.argv.slice(2)
|
||||
|
||||
if (args.includes('--help') || args.includes('-h')) {
|
||||
console.log(`
|
||||
Usage: pnpm icons:add [options] <icon_id> [icon_id...]
|
||||
|
||||
Options:
|
||||
--list, -l Browse all available Lucide icons (interactive)
|
||||
--overwrite, -o Overwrite existing icons
|
||||
--help, -h Show this help message
|
||||
|
||||
Examples:
|
||||
pnpm icons:add heart star settings-2
|
||||
pnpm icons:add --overwrite heart
|
||||
pnpm icons:add --list # Interactive browser
|
||||
pnpm icons:add --list | grep arrow # Pipe to grep
|
||||
|
||||
Interactive controls:
|
||||
Type Search icons
|
||||
← → Navigate pages
|
||||
Escape Clear search
|
||||
:q Quit
|
||||
`)
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
if (args.includes('--list') || args.includes('-l')) {
|
||||
const icons = listAvailableIcons()
|
||||
if (icons.length === 0) {
|
||||
console.error('❌ lucide-static not installed. Run pnpm install first.')
|
||||
process.exit(1)
|
||||
}
|
||||
if (process.stdout.isTTY) {
|
||||
paginateList(icons)
|
||||
} else {
|
||||
// Non-interactive mode (piped output)
|
||||
icons.forEach((icon) => console.log(icon))
|
||||
process.exit(0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const overwrite = args.includes('--overwrite') || args.includes('-o')
|
||||
const iconIds = args.filter((arg) => !arg.startsWith('-'))
|
||||
|
||||
if (iconIds.length === 0) {
|
||||
console.error('Usage: pnpm icons:add <icon_id> [icon_id...]')
|
||||
console.error('Example: pnpm icons:add heart star settings-2')
|
||||
console.error('Run with --help for more options')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (!fs.existsSync(lucideIconsDir)) {
|
||||
console.error('❌ lucide-static not installed. Run pnpm install first.')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
let added = 0
|
||||
for (const iconId of iconIds) {
|
||||
if (addIcon(iconId, overwrite)) {
|
||||
added++
|
||||
}
|
||||
}
|
||||
|
||||
if (added > 0) {
|
||||
console.log(`\n📦 Added ${added} icon(s). Run 'pnpm prepr:frontend:lib' to update exports.`)
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
417
packages/assets/build/generate-exports.ts
Normal file
417
packages/assets/build/generate-exports.ts
Normal file
@ -0,0 +1,417 @@
|
||||
import { compareImportSources } from '@modrinth/tooling-config/script-utils/import-sort'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
function toPascalCase(str: string): string {
|
||||
return str
|
||||
.split(/[-_.]/)
|
||||
.filter((part) => part.length > 0)
|
||||
.map((word) => {
|
||||
if (/^\d/.test(word)) {
|
||||
return word.charAt(0).toUpperCase() + word.slice(1)
|
||||
}
|
||||
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
|
||||
})
|
||||
.join('')
|
||||
}
|
||||
|
||||
function generateIconExports(): {
|
||||
imports: string
|
||||
exports: string
|
||||
categoryMap: string
|
||||
loaderMap: string
|
||||
} {
|
||||
const packageRoot = path.resolve(__dirname, '..')
|
||||
const iconsDir = path.join(packageRoot, 'icons')
|
||||
|
||||
if (!fs.existsSync(iconsDir)) {
|
||||
throw new Error(`Icons directory not found: ${iconsDir}`)
|
||||
}
|
||||
|
||||
const icons: Array<{ importPath: string; pascalName: string; privateName: string }> = []
|
||||
const categoryMapEntries: Array<{ key: string; value: string }> = []
|
||||
const loaderMapEntries: Array<{ key: string; value: string }> = []
|
||||
|
||||
// Process top-level icons
|
||||
const files = fs.readdirSync(iconsDir).filter((file) => {
|
||||
const filePath = path.join(iconsDir, file)
|
||||
return fs.statSync(filePath).isFile() && file.endsWith('.svg')
|
||||
})
|
||||
|
||||
files.forEach((file) => {
|
||||
const baseName = path.basename(file, '.svg')
|
||||
let pascalName = toPascalCase(baseName)
|
||||
|
||||
if (pascalName === '') {
|
||||
pascalName = 'Unknown'
|
||||
}
|
||||
|
||||
if (!pascalName.endsWith('Icon')) {
|
||||
pascalName += 'Icon'
|
||||
}
|
||||
|
||||
icons.push({
|
||||
importPath: `./icons/${file}?component`,
|
||||
pascalName,
|
||||
privateName: `_${pascalName}`,
|
||||
})
|
||||
})
|
||||
|
||||
// Process tag icons from icons/tags/categories/
|
||||
const categoriesDir = path.join(iconsDir, 'tags', 'categories')
|
||||
if (fs.existsSync(categoriesDir)) {
|
||||
const categoryFiles = fs.readdirSync(categoriesDir).filter((file) => file.endsWith('.svg'))
|
||||
categoryFiles.forEach((file) => {
|
||||
const baseName = path.basename(file, '.svg')
|
||||
let pascalName = toPascalCase(baseName)
|
||||
|
||||
if (pascalName === '') {
|
||||
pascalName = 'Unknown'
|
||||
}
|
||||
|
||||
// Prefix with TagCategory
|
||||
pascalName = `TagCategory${pascalName}`
|
||||
if (!pascalName.endsWith('Icon')) {
|
||||
pascalName += 'Icon'
|
||||
}
|
||||
|
||||
icons.push({
|
||||
importPath: `./icons/tags/categories/${file}?component`,
|
||||
pascalName,
|
||||
privateName: `_${pascalName}`,
|
||||
})
|
||||
|
||||
// Add to category map (key is the original filename without extension, lowercase)
|
||||
categoryMapEntries.push({
|
||||
key: baseName.toLowerCase(),
|
||||
value: pascalName,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Process tag icons from icons/tags/loaders/
|
||||
const loadersDir = path.join(iconsDir, 'tags', 'loaders')
|
||||
if (fs.existsSync(loadersDir)) {
|
||||
const loaderFiles = fs.readdirSync(loadersDir).filter((file) => file.endsWith('.svg'))
|
||||
loaderFiles.forEach((file) => {
|
||||
const baseName = path.basename(file, '.svg')
|
||||
let pascalName = toPascalCase(baseName)
|
||||
|
||||
if (pascalName === '') {
|
||||
pascalName = 'Unknown'
|
||||
}
|
||||
|
||||
// Prefix with TagLoader
|
||||
pascalName = `TagLoader${pascalName}`
|
||||
if (!pascalName.endsWith('Icon')) {
|
||||
pascalName += 'Icon'
|
||||
}
|
||||
|
||||
icons.push({
|
||||
importPath: `./icons/tags/loaders/${file}?component`,
|
||||
pascalName,
|
||||
privateName: `_${pascalName}`,
|
||||
})
|
||||
|
||||
// Add to loader map (key is the original filename without extension, lowercase)
|
||||
loaderMapEntries.push({
|
||||
key: baseName.toLowerCase(),
|
||||
value: pascalName,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Process badge icons from icons/badges/
|
||||
const badgesDir = path.join(iconsDir, 'badges')
|
||||
if (fs.existsSync(badgesDir)) {
|
||||
const badgeFiles = fs.readdirSync(badgesDir).filter((file) => file.endsWith('.svg'))
|
||||
badgeFiles.forEach((file) => {
|
||||
const baseName = path.basename(file, '.svg')
|
||||
let pascalName = toPascalCase(baseName)
|
||||
|
||||
if (pascalName === '') {
|
||||
pascalName = 'Unknown'
|
||||
}
|
||||
|
||||
if (!pascalName.endsWith('Badge')) {
|
||||
pascalName += 'Badge'
|
||||
}
|
||||
|
||||
icons.push({
|
||||
importPath: `./icons/badges/${file}?component`,
|
||||
pascalName,
|
||||
privateName: `_${pascalName}`,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Sort by import path using simple-import-sort's algorithm
|
||||
icons.sort((a, b) => compareImportSources(a.importPath, b.importPath))
|
||||
|
||||
// Sort map entries by key for consistent output
|
||||
categoryMapEntries.sort((a, b) => a.key.localeCompare(b.key))
|
||||
loaderMapEntries.sort((a, b) => a.key.localeCompare(b.key))
|
||||
|
||||
let imports = ''
|
||||
let exports = ''
|
||||
|
||||
icons.forEach(({ importPath, pascalName, privateName }) => {
|
||||
imports += `import ${privateName} from '${importPath}'\n`
|
||||
exports += `export const ${pascalName} = ${privateName}\n`
|
||||
})
|
||||
|
||||
// Generate category map
|
||||
let categoryMap = 'export const categoryIconMap: Record<string, IconComponent> = {\n'
|
||||
categoryMapEntries.forEach(({ key, value }) => {
|
||||
categoryMap += `\t'${key}': ${value},\n`
|
||||
})
|
||||
categoryMap += '}\n'
|
||||
|
||||
// Generate loader map
|
||||
let loaderMap = 'export const loaderIconMap: Record<string, IconComponent> = {\n'
|
||||
loaderMapEntries.forEach(({ key, value }) => {
|
||||
loaderMap += `\t'${key}': ${value},\n`
|
||||
})
|
||||
loaderMap += '}\n'
|
||||
|
||||
return { imports, exports, categoryMap, loaderMap }
|
||||
}
|
||||
|
||||
function runTests(): void {
|
||||
console.log('🧪 Running conversion tests...\n')
|
||||
|
||||
const testCases: Array<{ input: string; expected: string; suffix?: string }> = [
|
||||
{ input: 'align-left', expected: 'AlignLeftIcon' },
|
||||
{ input: 'arrow-big-up-dash', expected: 'ArrowBigUpDashIcon' },
|
||||
{ input: 'check-check', expected: 'CheckCheckIcon' },
|
||||
{ input: 'chevron-left', expected: 'ChevronLeftIcon' },
|
||||
{ input: 'file-archive', expected: 'FileArchiveIcon' },
|
||||
{ input: 'heart-handshake', expected: 'HeartHandshakeIcon' },
|
||||
{ input: 'monitor-smartphone', expected: 'MonitorSmartphoneIcon' },
|
||||
{ input: 'x-circle', expected: 'XCircleIcon' },
|
||||
{ input: 'rotate-ccw', expected: 'RotateCcwIcon' },
|
||||
{ input: 'bell-ring', expected: 'BellRingIcon' },
|
||||
{ input: 'more-horizontal', expected: 'MoreHorizontalIcon' },
|
||||
{ input: 'list_bulleted', expected: 'ListBulletedIcon' },
|
||||
{ input: 'test.name', expected: 'TestNameIcon' },
|
||||
{ input: 'test-name_final.icon', expected: 'TestNameFinalIcon' },
|
||||
{ input: 'downloads-500m', expected: 'Downloads500mBadge', suffix: 'Badge' },
|
||||
{ input: 'early-modpack', expected: 'EarlyModpackBadge', suffix: 'Badge' },
|
||||
{ input: 'plus', expected: 'PlusBadge', suffix: 'Badge' },
|
||||
]
|
||||
|
||||
let passed = 0
|
||||
let failed = 0
|
||||
|
||||
testCases.forEach(({ input, expected, suffix = 'Icon' }) => {
|
||||
const base = toPascalCase(input)
|
||||
const result = base.endsWith(suffix) ? base : base + suffix
|
||||
const success = result === expected
|
||||
|
||||
if (success) {
|
||||
console.log(`✅ ${input} → ${result}`)
|
||||
passed++
|
||||
} else {
|
||||
console.log(`❌ ${input} → ${result} (expected: ${expected})`)
|
||||
failed++
|
||||
}
|
||||
})
|
||||
|
||||
console.log(`\n📊 Test Results: ${passed} passed, ${failed} failed`)
|
||||
|
||||
if (failed > 0) {
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
function generateFiles(): void {
|
||||
try {
|
||||
console.log('🔄 Generating icon exports...')
|
||||
|
||||
const { imports, exports, categoryMap, loaderMap } = generateIconExports()
|
||||
const output = `// Auto-generated icon imports and exports
|
||||
// Do not edit this file manually - run 'pnpm run fix' to regenerate
|
||||
|
||||
import type { FunctionalComponent, SVGAttributes } from 'vue'
|
||||
|
||||
export type IconComponent = FunctionalComponent<SVGAttributes>
|
||||
|
||||
${imports}
|
||||
${exports}
|
||||
|
||||
${categoryMap}
|
||||
${loaderMap}`
|
||||
|
||||
const packageRoot = path.resolve(__dirname, '..')
|
||||
const outputPath = path.join(packageRoot, 'generated-icons.ts')
|
||||
fs.writeFileSync(outputPath, output)
|
||||
|
||||
console.log(`✅ Generated icon exports to: ${outputPath}`)
|
||||
console.log(
|
||||
`📦 Generated ${imports.split('\n').filter((line) => line.trim()).length} icon imports/exports`,
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('❌ Error generating icons:', error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
function main(): void {
|
||||
const args = process.argv.slice(2)
|
||||
|
||||
if (args.includes('--test')) {
|
||||
runTests()
|
||||
} else if (args.includes('--validate')) {
|
||||
validateIconConsistency()
|
||||
} else {
|
||||
generateFiles()
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
function getExpectedIconExports(iconsDir: string): string[] {
|
||||
if (!fs.existsSync(iconsDir)) {
|
||||
return []
|
||||
}
|
||||
|
||||
const exports: string[] = []
|
||||
|
||||
// Process top-level icons
|
||||
const files = fs.readdirSync(iconsDir).filter((file) => {
|
||||
const filePath = path.join(iconsDir, file)
|
||||
return fs.statSync(filePath).isFile() && file.endsWith('.svg')
|
||||
})
|
||||
|
||||
files.forEach((file) => {
|
||||
const baseName = path.basename(file, '.svg')
|
||||
let pascalName = toPascalCase(baseName)
|
||||
|
||||
if (pascalName === '') {
|
||||
pascalName = 'Unknown'
|
||||
}
|
||||
|
||||
if (!pascalName.endsWith('Icon')) {
|
||||
pascalName += 'Icon'
|
||||
}
|
||||
|
||||
exports.push(pascalName)
|
||||
})
|
||||
|
||||
// Process tag icons from icons/tags/categories/
|
||||
const categoriesDir = path.join(iconsDir, 'tags', 'categories')
|
||||
if (fs.existsSync(categoriesDir)) {
|
||||
const categoryFiles = fs.readdirSync(categoriesDir).filter((file) => file.endsWith('.svg'))
|
||||
categoryFiles.forEach((file) => {
|
||||
const baseName = path.basename(file, '.svg')
|
||||
let pascalName = toPascalCase(baseName)
|
||||
|
||||
if (pascalName === '') {
|
||||
pascalName = 'Unknown'
|
||||
}
|
||||
|
||||
pascalName = `TagCategory${pascalName}`
|
||||
if (!pascalName.endsWith('Icon')) {
|
||||
pascalName += 'Icon'
|
||||
}
|
||||
|
||||
exports.push(pascalName)
|
||||
})
|
||||
}
|
||||
|
||||
// Process tag icons from icons/tags/loaders/
|
||||
const loadersDir = path.join(iconsDir, 'tags', 'loaders')
|
||||
if (fs.existsSync(loadersDir)) {
|
||||
const loaderFiles = fs.readdirSync(loadersDir).filter((file) => file.endsWith('.svg'))
|
||||
loaderFiles.forEach((file) => {
|
||||
const baseName = path.basename(file, '.svg')
|
||||
let pascalName = toPascalCase(baseName)
|
||||
|
||||
if (pascalName === '') {
|
||||
pascalName = 'Unknown'
|
||||
}
|
||||
|
||||
pascalName = `TagLoader${pascalName}`
|
||||
if (!pascalName.endsWith('Icon')) {
|
||||
pascalName += 'Icon'
|
||||
}
|
||||
|
||||
exports.push(pascalName)
|
||||
})
|
||||
}
|
||||
|
||||
// Process badge icons from icons/badges/
|
||||
const badgesDir = path.join(iconsDir, 'badges')
|
||||
if (fs.existsSync(badgesDir)) {
|
||||
const badgeFiles = fs.readdirSync(badgesDir).filter((file) => file.endsWith('.svg'))
|
||||
badgeFiles.forEach((file) => {
|
||||
const baseName = path.basename(file, '.svg')
|
||||
let pascalName = toPascalCase(baseName)
|
||||
|
||||
if (pascalName === '') {
|
||||
pascalName = 'Unknown'
|
||||
}
|
||||
|
||||
if (!pascalName.endsWith('Badge')) {
|
||||
pascalName += 'Badge'
|
||||
}
|
||||
|
||||
exports.push(pascalName)
|
||||
})
|
||||
}
|
||||
|
||||
return exports.sort()
|
||||
}
|
||||
|
||||
function getActualIconExports(indexFile: string): string[] {
|
||||
if (!fs.existsSync(indexFile)) {
|
||||
return []
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(indexFile, 'utf8')
|
||||
const exportMatches =
|
||||
content.match(/export const (\w+(?:Icon|Badge)) = _\w+(?:Icon|Badge)/g) || []
|
||||
|
||||
return exportMatches
|
||||
.map((match) => {
|
||||
const result = match.match(/export const (\w+(?:Icon|Badge))/)
|
||||
return result ? result[1] : ''
|
||||
})
|
||||
.filter((name) => name.endsWith('Icon') || name.endsWith('Badge'))
|
||||
.sort()
|
||||
}
|
||||
|
||||
function validateIconConsistency(): void {
|
||||
try {
|
||||
console.log('🔍 Validating icon consistency...')
|
||||
|
||||
const packageRoot = path.resolve(__dirname, '..')
|
||||
const iconsDir = path.join(packageRoot, 'icons')
|
||||
const declarationFile = path.join(packageRoot, 'generated-icons.ts')
|
||||
|
||||
const expectedExports = getExpectedIconExports(iconsDir)
|
||||
const actualExports = getActualIconExports(declarationFile)
|
||||
|
||||
const missingExports = expectedExports.filter((name) => !actualExports.includes(name))
|
||||
const extraExports = actualExports.filter((name) => !expectedExports.includes(name))
|
||||
|
||||
if (missingExports.length > 0) {
|
||||
console.error(`❌ Missing icon exports: ${missingExports.join(', ')}`)
|
||||
console.error("Run 'pnpm run fix' to generate them.")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (extraExports.length > 0) {
|
||||
console.error(
|
||||
`❌ Extra icon exports (no corresponding SVG files): ${extraExports.join(', ')}`,
|
||||
)
|
||||
console.error("Run 'pnpm run fix' to clean them up.")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log('✅ Icon exports are consistent with SVG files')
|
||||
} catch (error) {
|
||||
console.error('❌ Error validating icons:', error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user