mirror of
https://github.com/hanzoai/shadcn.git
synced 2026-11-02 13:07:46 +00:00
* refactor: decouple @hanzo/ui from hanzogui Make @hanzo/ui shadcn-only — no hanzogui/Tamagui coupling. - remove primitives/bases (gui/admin/svelte/vue) re-exports - drop @hanzogui peerDependencies + peerDependenciesMeta entries - add check-no-hanzogui guard, wired into build - fix latent NodeJS.Timeout types to keep the build green * refactor: remove duplicate @hanzo/brand from the monorepo @hanzo/brand is owned by the standalone hanzoai/brand (the npm-canonical source); this monorepo's copy was unused and had drifted. - delete pkg/brand - add check-no-brand-pkg guard (wired into `check`) so it can't reappear * refactor(ui): stop importing from the app; use own cn util pkg/ui pulled `cn` from @/lib/utils (../../app) — an inverted dependency on the consuming app. Point the animation components at pkg/ui's own cn and drop the @/app, @/registry, @/lib tsconfig path aliases. * fix(ui): type errors; stop tracking the root lockfile - ModelCard: lucide-react dropped the Github icon → use Code - drawer: annotate DrawerTrigger/DrawerClose (radix type portability) - untrack root pnpm-lock.yaml; CI → --no-frozen-lockfile * release: bump @hanzo/ui to 5.7.0 * refactor: rename pkg/ → pkgs/, merge packages/ into it standardize on 'pkgs/': move pkg/* and packages/* into pkgs/. Update workspace globs, CI, scripts, and config references accordingly.
160 lines
4.3 KiB
JavaScript
160 lines
4.3 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Component Health Check Script
|
|
*
|
|
* This script verifies that all registered components:
|
|
* 1. Have corresponding documentation files
|
|
* 2. Have implementation files
|
|
* 3. Are accessible via their routes
|
|
* 4. Render without errors
|
|
*/
|
|
|
|
import { registry } from '../app/registry/registry.ts'
|
|
import { promises as fs } from 'fs'
|
|
import path from 'path'
|
|
import chalk from 'chalk'
|
|
|
|
interface ComponentStatus {
|
|
name: string
|
|
hasDoc: boolean
|
|
hasImplementation: boolean
|
|
hasRoute: boolean
|
|
errors: string[]
|
|
}
|
|
|
|
async function fileExists(filePath: string): Promise<boolean> {
|
|
try {
|
|
await fs.access(filePath)
|
|
return true
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
|
|
async function checkComponent(component: any): Promise<ComponentStatus> {
|
|
const status: ComponentStatus = {
|
|
name: component.name,
|
|
hasDoc: false,
|
|
hasImplementation: false,
|
|
hasRoute: false,
|
|
errors: []
|
|
}
|
|
|
|
// Check for documentation file
|
|
const docPaths = [
|
|
`app/content/docs/components/${component.name}.mdx`,
|
|
`app/content/docs/ai/${component.name}.mdx`,
|
|
`app/content/docs/blocks/${component.name}.mdx`
|
|
]
|
|
|
|
for (const docPath of docPaths) {
|
|
if (await fileExists(path.join(process.cwd(), docPath))) {
|
|
status.hasDoc = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if (!status.hasDoc) {
|
|
status.errors.push(`Missing documentation file`)
|
|
}
|
|
|
|
// Check for implementation files
|
|
if (component.files && component.files.length > 0) {
|
|
for (const file of component.files) {
|
|
const implementationPaths = [
|
|
`app/registry/default/${file}`,
|
|
`app/registry/new-york/${file}`,
|
|
`app/__registry__/default/${file}`,
|
|
`pkgs/ui/src/${file}`
|
|
]
|
|
|
|
let found = false
|
|
for (const implPath of implementationPaths) {
|
|
if (await fileExists(path.join(process.cwd(), implPath))) {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if (found) {
|
|
status.hasImplementation = true
|
|
} else {
|
|
status.errors.push(`Missing implementation: ${file}`)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if route is accessible (would need running server)
|
|
// This is a placeholder - in real implementation, we'd make HTTP requests
|
|
status.hasRoute = status.hasDoc // Assuming if doc exists, route exists
|
|
|
|
return status
|
|
}
|
|
|
|
async function runHealthCheck() {
|
|
console.log(chalk.blue('🏥 Running Component Health Check...\n'))
|
|
|
|
const results: ComponentStatus[] = []
|
|
const components = registry
|
|
|
|
// Check each component
|
|
for (const component of components) {
|
|
const status = await checkComponent(component)
|
|
results.push(status)
|
|
}
|
|
|
|
// Generate report
|
|
console.log(chalk.bold('Component Health Report\n'))
|
|
console.log('=' .repeat(80))
|
|
|
|
let totalComponents = results.length
|
|
let healthyComponents = 0
|
|
let missingDocs = 0
|
|
let missingImplementations = 0
|
|
|
|
for (const result of results) {
|
|
const isHealthy = result.hasDoc && result.hasImplementation && result.errors.length === 0
|
|
|
|
if (isHealthy) {
|
|
healthyComponents++
|
|
console.log(chalk.green('✅'), chalk.bold(result.name.padEnd(40)), 'Healthy')
|
|
} else {
|
|
const status = []
|
|
if (!result.hasDoc) {
|
|
status.push(chalk.red('No Docs'))
|
|
missingDocs++
|
|
}
|
|
if (!result.hasImplementation) {
|
|
status.push(chalk.red('No Implementation'))
|
|
missingImplementations++
|
|
}
|
|
|
|
console.log(chalk.red('❌'), chalk.bold(result.name.padEnd(40)), status.join(', '))
|
|
|
|
if (result.errors.length > 0) {
|
|
for (const error of result.errors) {
|
|
console.log(' ', chalk.gray(error))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log('\n' + '=' .repeat(80))
|
|
console.log(chalk.bold('\nSummary:'))
|
|
console.log(`Total Components: ${totalComponents}`)
|
|
console.log(`Healthy: ${chalk.green(healthyComponents)} (${((healthyComponents/totalComponents) * 100).toFixed(1)}%)`)
|
|
console.log(`Missing Docs: ${chalk.red(missingDocs)}`)
|
|
console.log(`Missing Implementations: ${chalk.red(missingImplementations)}`)
|
|
|
|
// Exit with error if not all components are healthy
|
|
if (healthyComponents < totalComponents) {
|
|
console.log(chalk.yellow('\n⚠️ Some components need attention!'))
|
|
process.exit(1)
|
|
} else {
|
|
console.log(chalk.green('\n✨ All components are healthy!'))
|
|
}
|
|
}
|
|
|
|
// Run the health check
|
|
runHealthCheck().catch(console.error) |