openpencil/scripts/check-package-metadata.ts
2026-05-21 17:03:19 +03:00

73 lines
2.1 KiB
TypeScript

import { readFileSync } from 'node:fs'
import { join } from 'node:path'
const publicPackages = ['packages/core', 'packages/cli', 'packages/mcp', 'packages/vue']
interface PackageJson {
name: string
main?: string
types?: string
files?: string[]
bin?: Record<string, string> | string
exports?: unknown
publishConfig?: Record<string, unknown>
}
const errors: string[] = []
function readPackageJson(packageDir: string): PackageJson {
return JSON.parse(readFileSync(join(packageDir, 'package.json'), 'utf8'))
}
function checkRuntimePath(packageName: string, field: string, value: string): void {
if (value.endsWith('.ts') && !value.endsWith('.d.ts')) {
errors.push(`${packageName}: ${field} must not point to runtime TypeScript (${value})`)
}
if (value.startsWith('./src/')) {
errors.push(`${packageName}: ${field} must not point to source files (${value})`)
}
}
function walkExports(packageName: string, value: unknown, path: string[] = []): void {
if (typeof value === 'string') {
const key = path.at(-1)
if (key !== 'types' && key !== 'bun') checkRuntimePath(packageName, `exports.${path.join('.')}`, value)
return
}
if (!value || typeof value !== 'object') return
for (const [key, child] of Object.entries(value)) {
walkExports(packageName, child, [...path, key])
}
}
for (const packageDir of publicPackages) {
const pkg = readPackageJson(packageDir)
if (!pkg.files?.includes('dist')) {
errors.push(`${pkg.name}: files must include dist`)
}
if (pkg.main) checkRuntimePath(pkg.name, 'main', pkg.main)
if (typeof pkg.bin === 'string') {
checkRuntimePath(pkg.name, 'bin', pkg.bin)
} else if (pkg.bin) {
for (const [name, target] of Object.entries(pkg.bin)) {
checkRuntimePath(pkg.name, `bin.${name}`, target)
}
}
walkExports(pkg.name, pkg.exports)
if (pkg.publishConfig && ('exports' in pkg.publishConfig || 'main' in pkg.publishConfig || 'types' in pkg.publishConfig)) {
errors.push(`${pkg.name}: publishConfig must not rewrite runtime entrypoints`)
}
}
if (errors.length > 0) {
console.error(errors.join('\n'))
process.exit(1)
}
console.log('Package metadata is publish-safe.')