chore(format): 撤销误入提交的整体重排,并关闭本仓库的格式化器

# 发生了什么

pi-lens 内置「安全格式化」:它会自动安装 biome 并对**编辑过的文件**跑
`biome format --write`。本机原先没有任何 biome 配置,于是 biome 用它自己的
默认值 —— tab 缩进 + 双引号 —— 把文件整体重写。

我在 19a3161 那次提交里用了 `git add -A`,把这批与功能无关的重排一起扫了进去:
约 7000 行改动散落在 20 个文件上,使那次提交无法审查,还掩盖了
server/internal/handler/permission.go 的一处删行(实为文件末尾空行,无代码丢失)。

# 为什么是「关掉」而不是「配置成我们的风格」

试过把缩进/引号/lineWidth 全部对齐本仓库习惯(biome.json + space/2/single/
lineWidth 120):`biome format --write` 仍然改动 17 个文件。原因是本仓库从未按
biome 的规则排版过 —— 注释按语义换行、数组与调用按可读性手工折行,
这些无法由格式化器还原。也就是说只要格式化器开着,每次编辑都会产生与内容无关的
大面积 diff,把真正的改动埋掉。

因此 biome.jsonc 里 formatter 与 linter 都关闭:本仓库的静态检查由
tsc / go vet / tree-sitter / ast-grep 与各自测试套件承担,不引入会改动无关行的
自动修复。

(pi-lens 这一版把 format 服务的 enabled 硬编码为 true,没有配置开关,
所以只能在仓库侧用 biome 配置让它不动文件;已验证 `biome format --write`
对这些文件零改动。)

# 本提交内容

把 19a3161 里除「有意改动」外的 20 个文件还原到重排前的样子。
19a3161 中真正有意的改动是 deploy/install.sh 的扩展注册与
plugins/pi-mail-bridge/extension/index.ts 新文件,两者原样保留。

验证:Go 全量、三桥插件(320/362/409)、前端 196 全绿;
`biome format --write` 对还原后的文件零改动。
This commit is contained in:
2026-09-11 12:03:51 +08:00
parent 19a3161ee4
commit 429149e118
21 changed files with 5603 additions and 6668 deletions

View File

@ -10,179 +10,127 @@
* - 空回答不能被当成「答了」
*/
import { test } from "node:test";
import assert from "node:assert/strict";
import { test } from 'node:test';
import assert from 'node:assert/strict';
import {
flattenQuestions,
answersFromDecision,
isBlankAnswer,
hasOptions,
optionLabels,
questionTitle,
} from "../lib/user-question.js";
flattenQuestions,
answersFromDecision,
isBlankAnswer,
hasOptions,
optionLabels,
questionTitle,
} from '../lib/user-question.js';
test("单问题单选项:忠实映射问题与选项", () => {
const flat = flattenQuestions([
{
id: "q1",
question: "用哪种方案?",
header: "选择",
options: [{ label: "方案 A" }, { label: "方案 B" }],
},
]);
assert.equal(flat.question, "选择: 用哪种方案?");
assert.deepEqual(flat.options, ["方案 A", "方案 B"]);
assert.equal(flat.multiSelect, false);
test('单问题单选项:忠实映射问题与选项', () => {
const flat = flattenQuestions([{
id: 'q1',
question: '用哪种方案?',
header: '选择',
options: [{ label: '方案 A' }, { label: '方案 B' }],
}]);
assert.equal(flat.question, '选择: 用哪种方案?');
assert.deepEqual(flat.options, ['方案 A', '方案 B']);
assert.equal(flat.multiSelect, false);
});
test("单问题多选multiSelect 透传", () => {
const flat = flattenQuestions([
{
id: "q1",
question: "要哪些?",
options: [{ label: "a" }, { label: "b" }],
multiSelect: true,
},
]);
assert.equal(flat.multiSelect, true);
test('单问题多选multiSelect 透传', () => {
const flat = flattenQuestions([{
id: 'q1',
question: '要哪些?',
options: [{ label: 'a' }, { label: 'b' }],
multiSelect: true,
}]);
assert.equal(flat.multiSelect, true);
});
test("多问题选项取并集且去重保序multiSelect 置真", () => {
const flat = flattenQuestions([
{
id: "q1",
question: "前端?",
options: [{ label: "React" }, { label: "Vue" }],
},
{
id: "q2",
question: "后端?",
options: [{ label: "Vue" }, { label: "Go" }],
},
]);
assert.deepEqual(
flat.options,
["React", "Vue", "Go"],
"重复 label 只出现一次",
);
assert.equal(
flat.multiSelect,
true,
"多问题必须允许多选,否则无法同时回答两题",
);
assert.match(flat.context, /前端?/);
assert.match(flat.context, /后端?/);
test('多问题选项取并集且去重保序multiSelect 置真', () => {
const flat = flattenQuestions([
{ id: 'q1', question: '前端?', options: [{ label: 'React' }, { label: 'Vue' }] },
{ id: 'q2', question: '后端?', options: [{ label: 'Vue' }, { label: 'Go' }] },
]);
assert.deepEqual(flat.options, ['React', 'Vue', 'Go'], '重复 label 只出现一次');
assert.equal(flat.multiSelect, true, '多问题必须允许多选,否则无法同时回答两题');
assert.match(flat.context, /前端?/);
assert.match(flat.context, /后端?/);
});
test("无选项题options 为空,正文提示直接填写", () => {
const flat = flattenQuestions([{ id: "q1", question: "你的名字?" }]);
assert.deepEqual(flat.options, []);
assert.match(flat.context, /直接填写|没有预设选项/);
test('无选项题options 为空,正文提示直接填写', () => {
const flat = flattenQuestions([{ id: 'q1', question: '你的名字?' }]);
assert.deepEqual(flat.options, []);
assert.match(flat.context, /直接填写|没有预设选项/);
});
test("空问题列表:抛错而不是造一封没有内容的信", () => {
assert.throws(() => flattenQuestions([]), /至少需要一个/);
assert.throws(() => flattenQuestions(undefined), /至少需要一个/);
test('空问题列表:抛错而不是造一封没有内容的信', () => {
assert.throws(() => flattenQuestions([]), /至少需要一个/);
assert.throws(() => flattenQuestions(undefined), /至少需要一个/);
});
test("单问题回写:选项进 selected备注进 custom", () => {
const qs = [
{ id: "q1", question: "选哪个", options: [{ label: "A" }, { label: "B" }] },
];
const ans = answersFromDecision(qs, "A", "再确认下");
assert.deepEqual(ans.answers, [
{ id: "q1", selected: ["A"], custom: "再确认下" },
]);
test('单问题回写:选项进 selected备注进 custom', () => {
const qs = [{ id: 'q1', question: '选哪个', options: [{ label: 'A' }, { label: 'B' }] }];
const ans = answersFromDecision(qs, 'A', '再确认下');
assert.deepEqual(ans.answers, [{ id: 'q1', selected: ['A'], custom: '再确认下' }]);
});
test("单问题多选回写:多行决策拆成多个 selected", () => {
const qs = [
{
id: "q1",
question: "选哪些",
options: [{ label: "A" }, { label: "B" }],
multiSelect: true,
},
];
const ans = answersFromDecision(qs, "A\nB", "");
assert.deepEqual(ans.answers[0].selected, ["A", "B"]);
assert.equal(ans.answers[0].custom, undefined, "空备注不该变成空 custom");
test('单问题多选回写:多行决策拆成多个 selected', () => {
const qs = [{ id: 'q1', question: '选哪些', options: [{ label: 'A' }, { label: 'B' }], multiSelect: true }];
const ans = answersFromDecision(qs, 'A\nB', '');
assert.deepEqual(ans.answers[0].selected, ['A', 'B']);
assert.equal(ans.answers[0].custom, undefined, '空备注不该变成空 custom');
});
test("无选项题回写:答案进 customselected 为空", () => {
const qs = [{ id: "q1", question: "名字?" }];
const ans = answersFromDecision(qs, "", "张三");
assert.deepEqual(ans.answers, [{ id: "q1", selected: [], custom: "张三" }]);
test('无选项题回写:答案进 customselected 为空', () => {
const qs = [{ id: 'q1', question: '名字?' }];
const ans = answersFromDecision(qs, '', '张三');
assert.deepEqual(ans.answers, [{ id: 'q1', selected: [], custom: '张三' }]);
});
test("无选项题只有决策文本时:文本进 custom否则答案永远为空", () => {
const qs = [{ id: "q1", question: "名字?" }];
const ans = answersFromDecision(qs, "李四", undefined);
assert.deepEqual(ans.answers, [{ id: "q1", selected: [], custom: "李四" }]);
test('无选项题只有决策文本时:文本进 custom否则答案永远为空', () => {
const qs = [{ id: 'q1', question: '名字?' }];
const ans = answersFromDecision(qs, '李四', undefined);
assert.deepEqual(ans.answers, [{ id: 'q1', selected: [], custom: '李四' }]);
});
test("多问题回写:选择按 label 归属分配到各自的问题(不张冠李戴)", () => {
const qs = [
{
id: "q1",
question: "前端?",
options: [{ label: "React" }, { label: "Vue" }],
},
{
id: "q2",
question: "后端?",
options: [{ label: "Go" }, { label: "Rust" }],
},
];
const ans = answersFromDecision(qs, "Vue\nGo", "都行");
assert.deepEqual(ans.answers[0].selected, ["Vue"], "q1 只拿前端的选择");
assert.deepEqual(ans.answers[1].selected, ["Go"], "q2 只拿后端的选择");
assert.equal(ans.answers[0].custom, "都行", "备注归第一个问题");
assert.equal(ans.answers[1].custom, undefined, "备注不重复分发");
test('多问题回写:选择按 label 归属分配到各自的问题(不张冠李戴)', () => {
const qs = [
{ id: 'q1', question: '前端?', options: [{ label: 'React' }, { label: 'Vue' }] },
{ id: 'q2', question: '后端?', options: [{ label: 'Go' }, { label: 'Rust' }] },
];
const ans = answersFromDecision(qs, 'Vue\nGo', '都行');
assert.deepEqual(ans.answers[0].selected, ['Vue'], 'q1 只拿前端的选择');
assert.deepEqual(ans.answers[1].selected, ['Go'], 'q2 只拿后端的选择');
assert.equal(ans.answers[0].custom, '都行', '备注归第一个问题');
assert.equal(ans.answers[1].custom, undefined, '备注不重复分发');
});
test("多问题里认不出的 label不匹配任何问题不猜测放行", () => {
const qs = [
{ id: "q1", question: "a", options: [{ label: "X" }] },
{ id: "q2", question: "b", options: [{ label: "Y" }] },
];
const ans = answersFromDecision(qs, "Z", "");
assert.deepEqual(
ans.answers[0].selected,
[],
"认不出的 label 不得被塞进任意问题",
);
assert.deepEqual(ans.answers[1].selected, []);
test('多问题里认不出的 label不匹配任何问题不猜测放行', () => {
const qs = [
{ id: 'q1', question: 'a', options: [{ label: 'X' }] },
{ id: 'q2', question: 'b', options: [{ label: 'Y' }] },
];
const ans = answersFromDecision(qs, 'Z', '');
assert.deepEqual(ans.answers[0].selected, [], '认不出的 label 不得被塞进任意问题');
assert.deepEqual(ans.answers[1].selected, []);
});
test("answers 的 id 与问题一一对应", () => {
const qs = [
{ id: "alpha", question: "a", options: [{ label: "X" }] },
{ id: "beta", question: "b" },
];
const ans = answersFromDecision(qs, "X", "note");
assert.deepEqual(
ans.answers.map((a) => a.id),
["alpha", "beta"],
);
test('answers 的 id 与问题一一对应', () => {
const qs = [{ id: 'alpha', question: 'a', options: [{ label: 'X' }] }, { id: 'beta', question: 'b' }];
const ans = answersFromDecision(qs, 'X', 'note');
assert.deepEqual(ans.answers.map((a) => a.id), ['alpha', 'beta']);
});
test("空回答判定:有选项的问题什么都没选 = 空", () => {
const qs = [{ id: "q1", question: "a", options: [{ label: "X" }] }];
assert.equal(isBlankAnswer(qs, "", ""), true);
assert.equal(isBlankAnswer(qs, "X", ""), false);
assert.equal(isBlankAnswer(qs, "", "自由文本"), false, "自由文本也算答了");
test('空回答判定:有选项的问题什么都没选 = 空', () => {
const qs = [{ id: 'q1', question: 'a', options: [{ label: 'X' }] }];
assert.equal(isBlankAnswer(qs, '', ''), true);
assert.equal(isBlankAnswer(qs, 'X', ''), false);
assert.equal(isBlankAnswer(qs, '', '自由文本'), false, '自由文本也算答了');
});
test("hasOptions / optionLabels / questionTitle 的边界", () => {
assert.equal(hasOptions({}), false);
assert.equal(hasOptions({ options: [] }), false);
assert.equal(hasOptions({ options: [{ label: "a" }] }), true);
assert.deepEqual(
optionLabels({ options: ["a", { label: "b" }, { description: "x" }] }),
["a", "b"],
);
assert.equal(questionTitle({ question: "只问一句" }), "只问一句");
assert.equal(questionTitle({}), "(未提供问题)");
test('hasOptions / optionLabels / questionTitle 的边界', () => {
assert.equal(hasOptions({}), false);
assert.equal(hasOptions({ options: [] }), false);
assert.equal(hasOptions({ options: [{ label: 'a' }] }), true);
assert.deepEqual(optionLabels({ options: ['a', { label: 'b' }, { description: 'x' }] }), ['a', 'b']);
assert.equal(questionTitle({ question: '只问一句' }), '只问一句');
assert.equal(questionTitle({}), '(未提供问题)');
});