chore: 导入清理前的完整工程状态(含 Capacitor 原生壳,作为回滚备份点)

This commit is contained in:
toor
2026-10-21 11:50:10 +08:00
committed by trae-solo-agent
commit 8ded87a3a8
389 changed files with 52242 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
/**
* 校验 packages/data/recipe.csv:食材/厨具词典、取值、视频号、重复
*
* pnpm validate # 有错误时退出码为 1
* pnpm validate --json # 输出 JSON,供 AI / 脚本消费
* pnpm validate --base origin/main # 同时检查 id 有没有被改给别的菜或复用
*/
import { execFileSync } from 'node:child_process'
import fs from 'node:fs'
import process from 'node:process'
import { meat, staple, tools, vegetable } from '../apps/web/app/data/food'
import { recipeCsvFile } from '../packages/cook/src/utils/config'
import { parseRecipeCsv } from '../packages/cook/src/utils/csv'
import { validateRecipes } from '../packages/cook/src/utils/validate'
const csvPath = 'packages/data/recipe.csv'
// 迁移到 monorepo 之前的位置,对比旧基准分支时使用
const legacyCsvPath = 'app/data/recipe.csv'
const recipes = parseRecipeCsv(fs.readFileSync(recipeCsvFile, 'utf-8'))
function readBase() {
const index = process.argv.indexOf('--base')
const ref = index > -1 ? process.argv[index + 1] : undefined
if (!ref)
return undefined
const show = (path: string) => execFileSync('git', ['show', `${ref}:${path}`], { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] })
let csv: string
try {
csv = show(csvPath)
}
catch {
csv = show(legacyCsvPath)
}
// 基准版本还没有 id 列时 parseRecipeCsv 返回空数组,等于不做对比
return parseRecipeCsv(csv)
}
const { issues, stats } = validateRecipes(recipes, {
stuff: new Set([...vegetable, ...meat, ...staple].map(item => item.name)),
tools: new Set(tools.map(item => item.name)),
}, { base: readBase() })
const errors = issues.filter(i => i.level === 'error')
const warnings = issues.filter(i => i.level === 'warning')
if (process.argv.includes('--json')) {
console.log(JSON.stringify({ stats, issues }, null, 2))
}
else {
const inCI = !!process.env.GITHUB_ACTIONS
for (const issue of issues) {
const where = issue.line ? `第 ${issue.line} 行` : ''
const text = `${where}「${issue.name}」:${issue.message}`
const location = issue.line ? `file=${csvPath},line=${issue.line}` : `file=${csvPath}`
console.log(inCI ? `::${issue.level} ${location}::${text}` : `${issue.level === 'error' ? '✗' : '!'} ${text}`)
}
const percent = (n: number) => `${n}(${Math.round(n / stats.total * 100)}%)`
const summary = [
`### 菜谱数据校验`,
'',
`| 项目 | 数量 |`,
`| --- | --- |`,
`| 菜谱总数 | ${stats.total} |`,
`| 错误 | ${errors.length} |`,
`| 警告 | ${warnings.length} |`,
`| 缺难度 | ${percent(stats.missingDifficulty)} |`,
`| 缺做法 | ${percent(stats.missingMethods)} |`,
`| 缺视频 | ${percent(stats.missingVideo)} |`,
'',
].join('\n')
console.log(`\n${summary}`)
if (process.env.GITHUB_STEP_SUMMARY)
fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, summary)
}
process.exitCode = errors.length ? 1 : 0