Files
MailUI4Agents/client/electron/test/align-refs.test.mjs
JianFeeeee 8390890646 跨端: feat(对齐): 参照物版本登记(CalendarView.tsx @d78f19f,变了即红)+ 圆角按语义配对(数值来源不同另行登记)
pi 2026-09-14 骨架开工前两件。

1. **对齐参照物要有版本号**:WebUI `CalendarView.tsx` 可能同时在动(gui-lab 有未合入改动),
   照工作副本画完之后参照物一变,这版就成了"照一份没人认领的草案对齐的",而**没人能判它对不对**。
   新增 `docs/ALIGN-REFS.json`(blob 哈希 + 登记于哪个 commit + "以哪次为准")
   + 判据 `test/align-refs.test.mjs`:哈希变了即红,报错按 §14 写明
   「正确修法 = 读差异→判断骨架要不要改→再更新登记」与
   「最常见的错误修法 = 把新哈希抄进去(那是把闸门降级成状态记录)」。变异确认会红。
   当前登记:`d78f19f`「日历页面补上圆角」,工作副本干净 —— 若另有未合入的,合入后再对一次。

2. **圆角必须走令牌,且跨端按语义配对**:鸿蒙侧已有 `Theme.ets:105/107` 的
   `radiusCard`/`radiusControl`(**系统**资源),WebUI 是 `--radius-card: 0.875rem` /
   `--radius-control: 0.5rem`。⇒ 端**语义对齐、数值来源不同**,所以登记写成"按语义配对",
   并且判据要求每条都写明"按语义还是按数值"(否则下一个人会直接去比数字)。
   数值差异本身按形态差异进余额:`radius-card-numeric-divergence`(等设备并排看再决定以谁为准)。
   鸿蒙侧不许把 14 / 0.875 抄成裸数字 —— 与当初 14 处 Material 调色板清零同一形态,量纲换成长度。
2026-09-14 17:46:20 +08:00

67 lines
4.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { spawnSync } from 'node:child_process';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { prose } from './lib/read.mjs';
/*
★ 对齐参照物必须有**版本号**(pi 2026-09-14 §1)。
WebUI 的 `CalendarView.tsx` 可能同时在动(gui-lab 有未合入的改动)。照工作副本画完之后,
参照物一变,这一版就成了"照一份没人认领的草案对齐的" —— 而且**没人能判它对不对,
因为参照物没有版本号**。所以把参照物的 blob 哈希登记在 `docs/ALIGN-REFS.json`,
**它一变就红**,逼一次"重新核对再更新登记"。
报错按 §14 写"正确修法 + 最常见的错误修法":正确修法是**重新核对对齐**(读差异、改骨架、再更新登记),
**不是**把新哈希抄进去 —— 那是把这条判据降级成"记录当前状态",它就不再是闸门了。
*/
const HERE = dirname(fileURLToPath(import.meta.url));
const ROOT = join(HERE, '..', '..', '..');
test('★ 对齐参照物的版本必须与登记一致(变了就重新核对,不是抄新哈希)', () => {
const reg = JSON.parse(prose(join(ROOT, 'docs', 'ALIGN-REFS.json')));
assert.ok(Array.isArray(reg.refs) && reg.refs.length > 0, '登记里至少要有一个参照物');
const drifted = [];
for (const r of reg.refs) {
const res = spawnSync('git', ['hash-object', r.path], { cwd: ROOT, encoding: 'utf8' });
assert.equal(res.status, 0, `要能算 ${r.path} 的 blob 哈希:${res.stderr}`);
const now = res.stdout.trim();
if (now !== r.blob) drifted.push({ id: r.id, path: r.path, registered: r.blob.slice(0, 12), now: now.slice(0, 12), at: r.atCommit });
}
assert.deepEqual(drifted, [],
`对齐参照物变了,登记还是旧的:\n ${drifted.map(d => `${d.id}(${d.path}):登记 ${d.registered}(@${d.at})→ 现在 ${d.now}`).join('\n ')}\n` +
`**正确修法**:读一遍参照物的差异 → 判断骨架要不要跟着改(并说明改了哪里)→ 再把登记的 blob/commit 更新。\n` +
`**最常见的错误修法**:把新哈希抄进去就完事 —— 那是把这条判据降级成"记录当前状态",\n` +
`它就不再是闸门,"照一份没人认领的草案对齐"这件事会静默发生。`);
// 每一条都要有出处(哪个 commit)与它对齐的是什么,否则"版本号"只是个数字
for (const r of reg.refs) {
assert.ok(r.atCommit && r.atCommitSubject, `参照物 ${r.id} 必须写明登记于哪个 commit(否则无人能判断对齐目标)`);
assert.ok(r.note && r.note.trim(), `参照物 ${r.id} 必须写明"以哪次为准"`);
}
});
/*
★ 圆角也是"裸值"那一族:从 `index.css` 抄一个数字进 `.ets`,今天看起来一样,
等 WebUI 改一次半径,鸿蒙这边**没有任何东西会红**(与当初 14 处 Material 调色板同一形态,
量纲从颜色换成长度)。所以:**鸿蒙侧圆角必须来自 Theme.ets 令牌**,
且语义配对登记在 ALIGN-REFS.json 里(数值来源不同属于形态差异,另行登记)。
*/
test('★ 圆角走令牌:鸿蒙侧必须有 radius 令牌,且每一条语义都在登记里配了对', () => {
const reg = JSON.parse(prose(join(ROOT, 'docs', 'ALIGN-REFS.json')));
const theme = prose(join(ROOT, 'client', 'harmony', 'entry', 'src', 'main', 'ets', 'common', 'Theme.ets'));
assert.match(theme, /radiusCard/, 'Theme.ets 必须有卡片圆角令牌(不许在页面里写裸数字)');
assert.match(theme, /radiusControl/, 'Theme.ets 必须有控件圆角令牌');
assert.ok(Array.isArray(reg.radius) && reg.radius.length >= 2, '圆角的语义配对要登记');
for (const r of reg.radius) {
assert.ok(r.semantic && r.webui && r.harmony, `圆角条目必须写明语义、WebUI 侧与鸿蒙侧出处`);
assert.match(r.webui, /--radius-/, `WebUI 侧要指向变量(不是抄来的数字):${r.semantic}`);
assert.match(r.harmony, /Theme\.ets/, `鸿蒙侧要指向令牌出处:${r.semantic}`);
assert.ok(r.judgement && r.judgement.includes('语义'), `${r.semantic} 必须写明按语义对齐还是按数值对齐(否则下一个人会去比数字)`);
}
});