From 893cbede9c2ad283bc796d66b7209ac1d8c9829f Mon Sep 17 00:00:00 2001 From: Qing Date: Wed, 4 Nov 2026 08:56:00 +0800 Subject: [PATCH] fix(todo): only count real comment markers around TODO keywords (#1128) The comment filter accepted `#`, `--`, `;` and `%` anywhere before the keyword, so `foo(); TODO`, `if (a % 2) TODO`, `i--; TODO`, URLs and strings produced items. Inline openers (// /* ", + " ; TODO", // line-start ini comment + " % TODO", // line-start LaTeX comment + '""" TODO', // Python docstring + "''' TODO", + "x = 1; // TODO", // marker after whitespace, not just line start + "x (* TODO *)", // OCaml trailing comment + "x {- TODO -}", // Haskell trailing comment + // IDEA's default pattern matches anywhere inside a comment, so mentions count too: + "/** 业务类别:WORK_NOTICE 工作通知,TODO 待办。 */", // documents an enum value + "// fixed the TODO bug", + "/* see the TODO list */", + ]; + const drop = [ + "foo(); TODO", // statement separator + "if (a % 2) TODO", // modulo + "i--; TODO", // postfix decrement + 'let s = "a#b"; TODO', // # inside a string, no preceding space + "x = a--b; TODO", // -- with no preceding space + "see http://example.com TODO", // // inside a URL + '"//"; TODO', // // inside a string + "f(*) TODO", // OCaml-style wildcard + "a * b; TODO", // infix multiplication + ]; + + it.each(keep)("keeps %s", (line) => expect(looksLikeComment(`${line.slice(0, line.indexOf("TODO"))}`)).toBe(true)); + it.each(drop)("drops %s", (line) => expect(looksLikeComment(`${line.slice(0, line.indexOf("TODO"))}`)).toBe(false)); + + it("falls back to the lenient rule on truncated lines", () => { + // A 600-char shell line truncated by the backend: the window starts + // mid-line, so the leading rule cannot apply — any marker counts. + expect(looksLikeComment("very long code # remainder ", true)).toBe(true); + expect(looksLikeComment("very long code % remainder ", true)).toBe(true); + expect(looksLikeComment("i-- ", true)).toBe(true); + }); +}); + describe("query", () => { it("builds the keyword regex from enabled patterns", () => { expect(todoRegexSource(S)).toBe("\\b(TODO|FIXME|HACK|XXX)\\b.*");