diff --git a/packages/comments/src/__tests__/lib.test.ts b/packages/comments/src/__tests__/lib.test.ts index e08b8195..1932e5b8 100644 --- a/packages/comments/src/__tests__/lib.test.ts +++ b/packages/comments/src/__tests__/lib.test.ts @@ -95,6 +95,37 @@ describe("parseAndTransformComments", () => { expect(/@returns something/.test(res)).toBe(true); }); + it("does not treat a scoped package name as a JSDoc tag", () => { + const input = + [ + "/**", + " * We match on the error code. If a future", + " * @auth0/auth0-react release reshapes the description, the check still fires.", + " */", + ].join("\n") + "\n"; + const { transformed } = parseAndTransformComments(input, { + width: 80, + wrapLineComments: true, + mergeLineComments: true, + }); + // No period injected mid-sentence. + expect(transformed).not.toMatch(/future\./); + // Sentence joined, scoped package kept inline as prose. + expect(transformed).toMatch(/future @auth0\/auth0-react/); + }); + + it("still treats real JSDoc tags as tags after the scoped-package fix", () => { + const input = + "/**\n * Does a thing.\n * @param x in\n * @returns out\n */\n"; + const { transformed } = parseAndTransformComments(input, { + width: 80, + wrapLineComments: true, + mergeLineComments: true, + }); + expect(transformed).toMatch(/^ \* @param x in$/m); + expect(transformed).toMatch(/^ \* @returns out$/m); + }); + it("handles heading-like lines with colon and visually indented code & numeric lists", () => { const input = [ "/**", diff --git a/packages/comments/src/lib.ts b/packages/comments/src/lib.ts index 0a8cd532..c245b480 100644 --- a/packages/comments/src/lib.ts +++ b/packages/comments/src/lib.ts @@ -165,7 +165,14 @@ function isListLike(line: string): boolean { } function isTagLine(line: string): boolean { - return /^@/.test(line.trim()); + /** + * A JSDoc/TSDoc tag is `@name` (optionally hyphenated) and is never + * immediately followed by `/`. The negative lookahead excludes scoped npm + * package specifiers like `@auth0/auth0-react` or `@versini/ui-main` that can + * legitimately open a wrapped prose line; treating those as tags severs the + * sentence and injects a spurious period. + */ + return /^@[A-Za-z][\w-]*(?![\w/-])/.test(line.trim()); } function isHeadingLike(line: string): boolean {