Merge PR #7752: fix(coding-agent): enabled multiline matching in ts-no-tiny-functions condition (@zhang17-24)
This commit is contained in:
@@ -11,6 +11,10 @@
|
||||
### Fixed
|
||||
|
||||
- Fixed `/usage`, `/advisor status`, and every other panel command looking dead mid-turn. `presentCommandOutput` defers panels while the agent streams so a growing turn cannot bury them, but said nothing, and on a long multi-subagent turn the panel is minutes away. The deferral is now acknowledged in the status line. A non-terminal settle also flushes the queue: `isStreaming` is already false by then, so a command issued after an async fan-out settles used to mount ahead of the panels queued before it.
|
||||
### Fixed
|
||||
|
||||
- Fixed the bundled `ts-no-tiny-functions` TTSR rule never firing on one-line arrow functions in real files: the second alternative's `$` anchor only matched at the absolute end of input, so the trailing newline present in every real file suppressed the match. The condition now opens with the `(?m)` inline flag so the arrow body matches to the line end ([#6890](https://github.com/can1357/oh-my-pi/issues/6890)).
|
||||
|
||||
## [17.2.9] - 2026-08-05
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
description: "Do not extract 1-2 line functions that only wrap an expression — inline them"
|
||||
condition: "\\{\\s*return [^;{}\\n]+;?\\s*\\}|\\b(?:const|let|var)\\s+[\\w$]+\\s*=\\s*(\\([^)]*\\)|[a-zA-Z_$][\\w$]*)\\s*=>\\s*[^{\\n]+$"
|
||||
condition: "(?m)\\{\\s*return [^;{}\\n]+;?\\s*\\}|\\b(?:const|let|var)\\s+[\\w$]+\\s*=\\s*(\\([^)]*\\)|[a-zA-Z_$][\\w$]*)\\s*=>\\s*[^{\\n]+$"
|
||||
scope: "tool:edit(*.ts), tool:edit(*.tsx), tool:write(*.ts), tool:write(*.tsx)"
|
||||
interruptMode: never
|
||||
---
|
||||
|
||||
@@ -181,6 +181,57 @@ describe("builtin-defaults rule provider", () => {
|
||||
}),
|
||||
).toEqual([]);
|
||||
});
|
||||
it("opens every bundled regex condition that uses a bare line anchor with a translatable inline flag", async () => {
|
||||
// Without the (?m)/(?s) inline flags a bare ^ or $ anchors to the
|
||||
// absolute start/end of input, so a rule whose condition is anchored to
|
||||
// a line silently stops matching in real files (see #6890). Enforce the
|
||||
// pairing at load time so the failure class stays closed.
|
||||
const rules = await loadBuiltinRules();
|
||||
for (const rule of rules) {
|
||||
for (const condition of rule.condition ?? []) {
|
||||
const outsideCharClasses = condition.replace(/\[[^\]]*\]/g, "");
|
||||
const hasBareAnchor = /(^|[^\\])[\^$]/.test(outsideCharClasses);
|
||||
const opensWithTranslatableFlag = /^\(\?[ims]+\)/.test(condition);
|
||||
expect(
|
||||
hasBareAnchor ? opensWithTranslatableFlag : true,
|
||||
`${rule.name}: a condition with a bare ^ or $ anchor must open with a translatable inline flag`,
|
||||
).toBe(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("fires ts-no-tiny-functions on one-line arrow functions even with a trailing newline", async () => {
|
||||
const rules = await loadBuiltinRules();
|
||||
const rule = rules.find(r => r.name === "ts-no-tiny-functions");
|
||||
if (!rule) throw new Error("ts-no-tiny-functions rule missing");
|
||||
|
||||
const manager = new TtsrManager();
|
||||
expect(manager.addRule(rule)).toBe(true);
|
||||
const ctx: TtsrMatchContext = { source: "tool", toolName: "edit", filePaths: ["src/foo.ts"] };
|
||||
|
||||
// Real files end with a newline, so the arrow alternative must match
|
||||
// before the line terminator, not only at the absolute end of input.
|
||||
const hits = [
|
||||
"const getName = (u) => u.profile.name;\n",
|
||||
"const getName = (u) => u.profile.name;",
|
||||
"const a = 1;\nconst getName = (u) => u.profile.name;\nconst b = 2;",
|
||||
];
|
||||
for (const snippet of hits) {
|
||||
manager.resetBuffer();
|
||||
expect(
|
||||
manager.checkDelta(snippet, ctx).map(m => m.name),
|
||||
snippet,
|
||||
).toEqual(["ts-no-tiny-functions"]);
|
||||
}
|
||||
|
||||
// Multi-statement functions (block bodies) are not tiny wrappers.
|
||||
const misses = ["function f(v) { const x = v.a; return x; }", "const f = (v) => { const x = v.a; return x; };"];
|
||||
for (const snippet of misses) {
|
||||
manager.resetBuffer();
|
||||
expect(manager.checkDelta(snippet, ctx), snippet).toEqual([]);
|
||||
}
|
||||
});
|
||||
|
||||
it("go-new-expr matches value→pointer helpers (named + generic) but not real functions, only on *.go", async () => {
|
||||
const rules = await loadBuiltinRules();
|
||||
const rule = rules.find(r => r.name === "go-new-expr");
|
||||
|
||||
Reference in New Issue
Block a user