fix(#2150): line-anchor + word-boundary the UI hint regex (review L1/L2)
Review found the hint value (yes|no) matched prefixes ('nope'/'not' read as
'no') and the hint regex was unanchored, so a mid-line prose mention like 'see
**UI hint**: no above' was treated as the authoritative metadata line. Line-
anchor (^ + m flag) so only a real hint line counts; word-boundary on the value
so nope/not do not mean no. Adds coverage for hint:yes over a pure-backend body
and the nope fall-through.
This commit is contained in:
@@ -81,8 +81,10 @@ export function checkUiPresence(text: string): UiPresenceResult {
|
|||||||
// authoritative declaration of whether the phase has a UI surface — progress.md
|
// authoritative declaration of whether the phase has a UI surface — progress.md
|
||||||
// and new-project.md already parse this line (`UI hint.*yes`). The bare token
|
// and new-project.md already parse this line (`UI hint.*yes`). The bare token
|
||||||
// `UI` in the line itself must not count as a UI indicator, and the declaration
|
// `UI` in the line itself must not count as a UI indicator, and the declaration
|
||||||
// overrides token-sniffing.
|
// overrides token-sniffing. Line-anchored (`m`) so a mid-line prose mention is
|
||||||
const hintMatch = normalised.match(/\*\*UI hint\*\*\s*:\s*(yes|no)/i);
|
// not treated as the metadata line; word-boundary on the value so `nope`/`not`
|
||||||
|
// do not match `no`.
|
||||||
|
const hintMatch = normalised.match(/^\s*\*\*UI hint\*\*\s*:\s*(yes|no)\b/im);
|
||||||
const hint = hintMatch ? hintMatch[1].toLowerCase() : null;
|
const hint = hintMatch ? hintMatch[1].toLowerCase() : null;
|
||||||
|
|
||||||
// Strip ANY `**UI hint**:` line before token-sniffing so a hint without a
|
// Strip ANY `**UI hint**:` line before token-sniffing so a hint without a
|
||||||
|
|||||||
@@ -96,6 +96,18 @@ describe('checkUiPresence', () => {
|
|||||||
'a phase that explicitly declares UI hint: yes must be flagged as UI');
|
'a phase that explicitly declares UI hint: yes must be flagged as UI');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('#2150 `**UI hint**: yes` over a pure-backend body still flags UI', () => {
|
||||||
|
const result = checkUiPresence('**UI hint**: yes\n\nBackend API refactor.\n');
|
||||||
|
assert.strictEqual(result.hasUI, true, 'hint:yes is authoritative even with no UI tokens');
|
||||||
|
assert.deepStrictEqual(result.tokens, []);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('#2150 hint value is whole-word matched (nope/not do not mean no)', () => {
|
||||||
|
const result = checkUiPresence('**UI hint**: nope\n\nBuild a dashboard component.\n');
|
||||||
|
assert.strictEqual(result.hasUI, true,
|
||||||
|
'a malformed hint value like "nope" must not be read as "no"; fall through to token-sniffing');
|
||||||
|
});
|
||||||
|
|
||||||
test('#2150 a hint line without yes/no is stripped (bare UI token does not fire)', () => {
|
test('#2150 a hint line without yes/no is stripped (bare UI token does not fire)', () => {
|
||||||
// A malformed hint (`UI hint: maybe`) must not false-positive on the bare
|
// A malformed hint (`UI hint: maybe`) must not false-positive on the bare
|
||||||
// `UI` token in the line itself; other UI tokens elsewhere still detect.
|
// `UI` token in the line itself; other UI tokens elsewhere still detect.
|
||||||
|
|||||||
Reference in New Issue
Block a user