mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-15 12:55:51 +00:00
style: 完成所有文件的lint
This commit is contained in:
@@ -12,69 +12,76 @@
|
||||
* bun scripts/check-bundle-integrity.ts ./dist # 指定目录
|
||||
*/
|
||||
|
||||
import { readdir, readFile } from "fs/promises"
|
||||
import { join, resolve, dirname } from "path"
|
||||
import { fileURLToPath } from "url"
|
||||
import { readdir, readFile } from 'fs/promises'
|
||||
import { join, resolve, dirname } from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
// ─── 从 package.json 读取 dependencies 作为白名单 ────────────────
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const pkg = JSON.parse(await readFile(join(__dirname, '..', 'package.json'), 'utf-8'))
|
||||
const pkg = JSON.parse(
|
||||
await readFile(join(__dirname, '..', 'package.json'), 'utf-8'),
|
||||
)
|
||||
const PKG_DEPS = new Set(Object.keys(pkg.dependencies ?? {}))
|
||||
|
||||
// ─── Node.js 内置模块白名单 ────────────────────────────────────────
|
||||
const NODE_BUILTINS = new Set([
|
||||
"assert",
|
||||
"async_hooks",
|
||||
"buffer",
|
||||
"child_process",
|
||||
"cluster",
|
||||
"console",
|
||||
"constants",
|
||||
"crypto",
|
||||
"dgram",
|
||||
"diagnostics_channel",
|
||||
"dns",
|
||||
"domain",
|
||||
"events",
|
||||
"fs",
|
||||
"fs/promises",
|
||||
"http",
|
||||
"http2",
|
||||
"https",
|
||||
"inspector",
|
||||
"module",
|
||||
"net",
|
||||
"os",
|
||||
"path",
|
||||
"perf_hooks",
|
||||
"process",
|
||||
"punycode",
|
||||
"querystring",
|
||||
"readline",
|
||||
"repl",
|
||||
"stream",
|
||||
"string_decoder",
|
||||
"sys",
|
||||
"timers",
|
||||
"tls",
|
||||
"tty",
|
||||
"url",
|
||||
"util",
|
||||
"v8",
|
||||
"vm",
|
||||
"worker_threads",
|
||||
"zlib",
|
||||
"node:test",
|
||||
'assert',
|
||||
'async_hooks',
|
||||
'buffer',
|
||||
'child_process',
|
||||
'cluster',
|
||||
'console',
|
||||
'constants',
|
||||
'crypto',
|
||||
'dgram',
|
||||
'diagnostics_channel',
|
||||
'dns',
|
||||
'domain',
|
||||
'events',
|
||||
'fs',
|
||||
'fs/promises',
|
||||
'http',
|
||||
'http2',
|
||||
'https',
|
||||
'inspector',
|
||||
'module',
|
||||
'net',
|
||||
'os',
|
||||
'path',
|
||||
'perf_hooks',
|
||||
'process',
|
||||
'punycode',
|
||||
'querystring',
|
||||
'readline',
|
||||
'repl',
|
||||
'stream',
|
||||
'string_decoder',
|
||||
'sys',
|
||||
'timers',
|
||||
'tls',
|
||||
'tty',
|
||||
'url',
|
||||
'util',
|
||||
'v8',
|
||||
'vm',
|
||||
'worker_threads',
|
||||
'zlib',
|
||||
'node:test',
|
||||
])
|
||||
|
||||
// Node 18+ 内置但不在传统列表中的模块
|
||||
const NODE_18_PLUS_BUILTINS = new Set(["undici"])
|
||||
const NODE_18_PLUS_BUILTINS = new Set(['undici'])
|
||||
|
||||
// Bun 专用模块(仅在 Bun 运行时可用,Node.js 环境会失败)
|
||||
const BUN_MODULES = new Set(["bun", "bun:ffi", "bun:test", "bun:sqlite"])
|
||||
const BUN_MODULES = new Set(['bun', 'bun:ffi', 'bun:test', 'bun:sqlite'])
|
||||
|
||||
// macOS JXA / native 框架(通过 ObjC.import,非真正的 require)
|
||||
const NATIVE_FRAMEWORKS = new Set(["AppKit", "CoreGraphics", "Foundation", "UIKit"])
|
||||
const NATIVE_FRAMEWORKS = new Set([
|
||||
'AppKit',
|
||||
'CoreGraphics',
|
||||
'Foundation',
|
||||
'UIKit',
|
||||
])
|
||||
|
||||
// ─── 模式 ──────────────────────────────────────────────────────────
|
||||
// 匹配 import { ... } from "./chunk-xxxxx.js" 或 import"./chunk-xxxxx.js"
|
||||
@@ -87,8 +94,13 @@ const DYNAMIC_IMPORT_RE = /import\("([^"]+)"\)/g
|
||||
const NODE_REQUIRE_RE = /nodeRequire\("([^"]+)"\)/g
|
||||
|
||||
interface Finding {
|
||||
type: "broken-chunk-ref" | "third-party-require" | "third-party-import" | "third-party-node-require" | "bun-runtime-only"
|
||||
severity: "error" | "warning"
|
||||
type:
|
||||
| 'broken-chunk-ref'
|
||||
| 'third-party-require'
|
||||
| 'third-party-import'
|
||||
| 'third-party-node-require'
|
||||
| 'bun-runtime-only'
|
||||
severity: 'error' | 'warning'
|
||||
file: string
|
||||
line: number
|
||||
module: string
|
||||
@@ -96,17 +108,17 @@ interface Finding {
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const distDir = resolve(process.argv[2] || "./dist")
|
||||
const distDir = resolve(process.argv[2] || './dist')
|
||||
|
||||
console.log(`\n🔍 检查构建产物完整性: ${distDir}\n`)
|
||||
|
||||
// 1. 列出所有 chunk 文件
|
||||
let files: string[]
|
||||
try {
|
||||
files = (await readdir(distDir)).filter((f) => f.endsWith(".js"))
|
||||
files = (await readdir(distDir)).filter(f => f.endsWith('.js'))
|
||||
} catch {
|
||||
console.error(`❌ 无法读取目录: ${distDir}`)
|
||||
console.error(" 请先运行 bun run build")
|
||||
console.error(' 请先运行 bun run build')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
@@ -118,8 +130,8 @@ async function main() {
|
||||
// 2. 逐文件扫描
|
||||
for (const file of files) {
|
||||
const filePath = join(distDir, file)
|
||||
const content = await readFile(filePath, "utf-8")
|
||||
const lines = content.split("\n")
|
||||
const content = await readFile(filePath, 'utf-8')
|
||||
const lines = content.split('\n')
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i]
|
||||
@@ -130,11 +142,11 @@ async function main() {
|
||||
for (const m of staticImportMatches) {
|
||||
const ref = m[1]
|
||||
// 提取文件名部分(去掉 ./)
|
||||
const refFile = ref.replace(/^\.\//, "")
|
||||
const refFile = ref.replace(/^\.\//, '')
|
||||
if (!fileSet.has(refFile)) {
|
||||
findings.push({
|
||||
type: "broken-chunk-ref",
|
||||
severity: "error",
|
||||
type: 'broken-chunk-ref',
|
||||
severity: 'error',
|
||||
file,
|
||||
line: lineNum,
|
||||
module: ref,
|
||||
@@ -149,11 +161,17 @@ async function main() {
|
||||
const mod = m[1]
|
||||
// 跳过 ObjC.import(JXA 语法,不是真正的 require)
|
||||
if (NATIVE_FRAMEWORKS.has(mod)) continue
|
||||
if (NODE_BUILTINS.has(mod) || NODE_18_PLUS_BUILTINS.has(mod) || PKG_DEPS.has(mod) || mod.startsWith("node:")) continue
|
||||
if (
|
||||
NODE_BUILTINS.has(mod) ||
|
||||
NODE_18_PLUS_BUILTINS.has(mod) ||
|
||||
PKG_DEPS.has(mod) ||
|
||||
mod.startsWith('node:')
|
||||
)
|
||||
continue
|
||||
if (BUN_MODULES.has(mod)) {
|
||||
findings.push({
|
||||
type: "bun-runtime-only",
|
||||
severity: "warning",
|
||||
type: 'bun-runtime-only',
|
||||
severity: 'warning',
|
||||
file,
|
||||
line: lineNum,
|
||||
module: mod,
|
||||
@@ -163,8 +181,8 @@ async function main() {
|
||||
}
|
||||
// 第三方模块 — 在生产环境(全局 npm install)中找不到
|
||||
findings.push({
|
||||
type: "third-party-require",
|
||||
severity: "error",
|
||||
type: 'third-party-require',
|
||||
severity: 'error',
|
||||
file,
|
||||
line: lineNum,
|
||||
module: mod,
|
||||
@@ -177,15 +195,21 @@ async function main() {
|
||||
for (const m of dynImportMatches) {
|
||||
const mod = m[1]
|
||||
// 跳过内部 chunk 引用和相对路径
|
||||
if (mod.startsWith("./") || mod.startsWith("../")) continue
|
||||
if (mod.startsWith('./') || mod.startsWith('../')) continue
|
||||
// 跳过 ObjC.import
|
||||
if (NATIVE_FRAMEWORKS.has(mod)) continue
|
||||
if (NODE_BUILTINS.has(mod) || NODE_18_PLUS_BUILTINS.has(mod) || PKG_DEPS.has(mod) || mod.startsWith("node:")) continue
|
||||
if (
|
||||
NODE_BUILTINS.has(mod) ||
|
||||
NODE_18_PLUS_BUILTINS.has(mod) ||
|
||||
PKG_DEPS.has(mod) ||
|
||||
mod.startsWith('node:')
|
||||
)
|
||||
continue
|
||||
if (BUN_MODULES.has(mod)) {
|
||||
// bun:test 等只在 Bun 运行时可用,Node.js 运行时会失败
|
||||
findings.push({
|
||||
type: "bun-runtime-only",
|
||||
severity: "warning",
|
||||
type: 'bun-runtime-only',
|
||||
severity: 'warning',
|
||||
file,
|
||||
line: lineNum,
|
||||
module: mod,
|
||||
@@ -195,8 +219,8 @@ async function main() {
|
||||
}
|
||||
// 第三方动态 import
|
||||
findings.push({
|
||||
type: "third-party-import",
|
||||
severity: "error",
|
||||
type: 'third-party-import',
|
||||
severity: 'error',
|
||||
file,
|
||||
line: lineNum,
|
||||
module: mod,
|
||||
@@ -209,11 +233,17 @@ async function main() {
|
||||
for (const m of nodeRequireMatches) {
|
||||
const mod = m[1]
|
||||
if (NATIVE_FRAMEWORKS.has(mod)) continue
|
||||
if (NODE_BUILTINS.has(mod) || NODE_18_PLUS_BUILTINS.has(mod) || PKG_DEPS.has(mod) || mod.startsWith("node:")) continue
|
||||
if (
|
||||
NODE_BUILTINS.has(mod) ||
|
||||
NODE_18_PLUS_BUILTINS.has(mod) ||
|
||||
PKG_DEPS.has(mod) ||
|
||||
mod.startsWith('node:')
|
||||
)
|
||||
continue
|
||||
if (BUN_MODULES.has(mod)) {
|
||||
findings.push({
|
||||
type: "bun-runtime-only",
|
||||
severity: "warning",
|
||||
type: 'bun-runtime-only',
|
||||
severity: 'warning',
|
||||
file,
|
||||
line: lineNum,
|
||||
module: mod,
|
||||
@@ -222,8 +252,8 @@ async function main() {
|
||||
continue
|
||||
}
|
||||
findings.push({
|
||||
type: "third-party-node-require",
|
||||
severity: "error",
|
||||
type: 'third-party-node-require',
|
||||
severity: 'error',
|
||||
file,
|
||||
line: lineNum,
|
||||
module: mod,
|
||||
@@ -234,18 +264,22 @@ async function main() {
|
||||
}
|
||||
|
||||
// 3. 汇总报告
|
||||
const errors = findings.filter((f) => f.severity === "error")
|
||||
const warnings = findings.filter((f) => f.severity === "warning")
|
||||
const errors = findings.filter(f => f.severity === 'error')
|
||||
const warnings = findings.filter(f => f.severity === 'warning')
|
||||
|
||||
// 按 type 分组
|
||||
const brokenRefs = errors.filter((f) => f.type === "broken-chunk-ref")
|
||||
const thirdPartyRequires = errors.filter((f) => f.type === "third-party-require")
|
||||
const thirdPartyImports = errors.filter((f) => f.type === "third-party-import")
|
||||
const thirdPartyNodeRequires = errors.filter((f) => f.type === "third-party-node-require")
|
||||
const bunRuntimeOnly = warnings.filter((f) => f.type === "bun-runtime-only")
|
||||
const brokenRefs = errors.filter(f => f.type === 'broken-chunk-ref')
|
||||
const thirdPartyRequires = errors.filter(
|
||||
f => f.type === 'third-party-require',
|
||||
)
|
||||
const thirdPartyImports = errors.filter(f => f.type === 'third-party-import')
|
||||
const thirdPartyNodeRequires = errors.filter(
|
||||
f => f.type === 'third-party-node-require',
|
||||
)
|
||||
const bunRuntimeOnly = warnings.filter(f => f.type === 'bun-runtime-only')
|
||||
|
||||
if (brokenRefs.length > 0) {
|
||||
console.log("❌ 断裂的 chunk 引用(引用了不存在的文件):")
|
||||
console.log('❌ 断裂的 chunk 引用(引用了不存在的文件):')
|
||||
for (const f of brokenRefs) {
|
||||
console.log(` ${f.file}:${f.line} → ${f.module}`)
|
||||
}
|
||||
@@ -253,7 +287,7 @@ async function main() {
|
||||
}
|
||||
|
||||
if (thirdPartyRequires.length > 0) {
|
||||
console.log("❌ 通过 __require() 引用的第三方模块(生产环境会找不到):")
|
||||
console.log('❌ 通过 __require() 引用的第三方模块(生产环境会找不到):')
|
||||
const grouped = groupByModule(thirdPartyRequires)
|
||||
for (const [mod, items] of grouped) {
|
||||
console.log(` "${mod}" — 出现 ${items.length} 次:`)
|
||||
@@ -266,7 +300,7 @@ async function main() {
|
||||
}
|
||||
|
||||
if (thirdPartyImports.length > 0) {
|
||||
console.log("❌ 通过 import() 动态引用的第三方模块(生产环境会找不到):")
|
||||
console.log('❌ 通过 import() 动态引用的第三方模块(生产环境会找不到):')
|
||||
const grouped = groupByModule(thirdPartyImports)
|
||||
for (const [mod, items] of grouped) {
|
||||
console.log(` "${mod}" — 出现 ${items.length} 次:`)
|
||||
@@ -279,7 +313,9 @@ async function main() {
|
||||
}
|
||||
|
||||
if (thirdPartyNodeRequires.length > 0) {
|
||||
console.log("❌ 通过 nodeRequire() 引用的第三方模块(绕过打包,生产环境会找不到):")
|
||||
console.log(
|
||||
'❌ 通过 nodeRequire() 引用的第三方模块(绕过打包,生产环境会找不到):',
|
||||
)
|
||||
const grouped = groupByModule(thirdPartyNodeRequires)
|
||||
for (const [mod, items] of grouped) {
|
||||
console.log(` "${mod}" — 出现 ${items.length} 次:`)
|
||||
@@ -292,7 +328,7 @@ async function main() {
|
||||
}
|
||||
|
||||
if (bunRuntimeOnly.length > 0) {
|
||||
console.log("⚠️ Bun 运行时专用模块(Node.js 环境会失败):")
|
||||
console.log('⚠️ Bun 运行时专用模块(Node.js 环境会失败):')
|
||||
const grouped = groupByModule(bunRuntimeOnly)
|
||||
for (const [mod, items] of grouped) {
|
||||
console.log(` "${mod}" — 出现 ${items.length} 次`)
|
||||
@@ -301,9 +337,9 @@ async function main() {
|
||||
}
|
||||
|
||||
// 4. 总结
|
||||
console.log("─".repeat(50))
|
||||
console.log('─'.repeat(50))
|
||||
if (errors.length === 0 && warnings.length === 0) {
|
||||
console.log("✅ 构建产物完整性检查通过,未发现问题。")
|
||||
console.log('✅ 构建产物完整性检查通过,未发现问题。')
|
||||
} else {
|
||||
console.log(`📊 总计: ${errors.length} 个错误, ${warnings.length} 个警告`)
|
||||
if (errors.length > 0) {
|
||||
@@ -330,7 +366,7 @@ function groupByModule(items: Finding[]): Map<string, Finding[]> {
|
||||
return new Map([...map.entries()].sort((a, b) => b[1].length - a[1].length))
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error("Fatal error:", err)
|
||||
main().catch(err => {
|
||||
console.error('Fatal error:', err)
|
||||
process.exit(2)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user