Files
dsh-purge2/scripts/ensure-profile-bundle.mjs
叫我小杨同学andClaude 6533b08004 fix: cordis.patch.yml 为 [] 时替换而非追加,修复宿主启动解析失败(#191)
宿主生成的 profile 层 cordis.patch.yml 可能整体只有一个空 flow 序列 [],
那本身就是一个完整 YAML 文档。旧实现无条件在文件尾追加 `- insert:`,
结果是第二个文档,宿主启动解析报
"end of the stream or a document separator is expected" 直接崩掉
(macOS DSH Desktop 0.2.1-rc.4)。

- 新增 classifyPatchBody() 判断数据部分形态:empty / empty-flow /
  block-seq / flow-seq / unknown,只看最后一个文档的根节点
- 空 flow 序列([] 或 [ ],可带 --- 前缀)→ 把整行替换成 insert 块,
  绝不追加成第二个文档
- 空文件 / 只有注释和空行 → 写 insert 块,注释保留
- 正常块序列 → 沿用旧的追加行为,前导空行规则不变
- 非空 flow 序列(宿主/用户内容)以及认不准的形态 → 不动,
  返回 { ok: false, wrote: false },宁可留着也别写坏
- postinstall 脚本区分「跳过」和「已有」,跳过时打印说明
- profileHasPurgeBodyInsert() 检测逻辑未动
- 新增 9 条用例(形态分类 / 空文件 / 只有注释 / 注释+[] / ---+[] /
  块序列追加 / 非空 flow 不写 / 已有本体行零写入 / 替换后幂等),
  版本 1.1.83

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-30 12:26:23 +08:00

90 lines
2.8 KiB
JavaScript

#!/usr/bin/env node
/**
* 装进 DSH profile 时补两笔(#154):
* 1. dsh.profile.bundles
* 2. 用户层 cordis.patch.yml 的本体 insert
* pnpm add / dsh plugin add 都不会自己写 insert;市场会写,已有则跳过。
* 在插件仓库里跑 pnpm install 则整段跳过。
*/
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import {
PURGE_NAME as NAME,
ensureProfileBodyInsert,
ensureProfileBundles,
ensurePnpmAllowBuild,
profileHasPurgeBodyInsert,
} from "../lib/profile-insert.js";
export { profileHasPurgeBodyInsert };
function readJson(fp) {
try {
return JSON.parse(fs.readFileSync(fp, "utf8"));
} catch {
return null;
}
}
function isProfilePkg(pkg) {
if (!pkg || typeof pkg !== "object") return false;
if (typeof pkg.name === "string" && pkg.name.startsWith("dsh-profile-")) return true;
return Array.isArray(pkg.dsh?.profile?.bundles);
}
function findProfileDir() {
const seeds = [process.env.INIT_CWD, process.env.npm_config_local_prefix, process.cwd()].filter(Boolean);
for (const seed of seeds) {
let dir = path.resolve(seed);
for (let i = 0; i < 8; i += 1) {
if (isProfilePkg(readJson(path.join(dir, "package.json")))) return dir;
const parent = path.dirname(dir);
if (parent === dir) break;
dir = parent;
}
}
return "";
}
function ensureProfileInsert(profileDir) {
const result = ensureProfileBodyInsert(profileDir);
if (result.wrote) {
process.stdout.write(`dsh-purge: wrote body insert (${result.path})\n`);
} else if (result.ok === false) {
// 宿主 / 用户自己的 cordis.patch.yml 内容,宁可不动也别写坏(#191)
process.stdout.write(`dsh-purge: skipped body insert, unrecognized patch body (${result.path})\n`);
} else {
process.stdout.write(`dsh-purge: insert already in ${result.path}\n`);
}
return result.wrote;
}
function main() {
const profileDir = findProfileDir();
if (!profileDir) return;
const fp = path.join(profileDir, "package.json");
const pkg = readJson(fp);
if (!pkg) {
process.stderr.write(`dsh-purge: cannot read ${fp}\n`);
process.exit(1);
}
const bundles = ensureProfileBundles(profileDir);
process.stdout.write(bundles.wrote
? `dsh-purge: appended to bundles (${profileDir})\n`
: `dsh-purge: already in bundles (${profileDir})\n`);
try {
ensureProfileInsert(profileDir);
const pnpm = ensurePnpmAllowBuild(profileDir);
if (pnpm.wrote) process.stdout.write(`dsh-purge: allowed pnpm build for ${NAME}\n`);
} catch (e) {
process.stderr.write(`dsh-purge: insert failed: ${e && e.message ? e.message : e}\n`);
process.exit(1);
}
}
const invoked = process.argv[1] ? path.resolve(process.argv[1]) : "";
if (invoked === fileURLToPath(import.meta.url)) main();