From 9121d780f1158158e2ed62fab8541852fc069184 Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Mon, 7 Jul 2025 11:21:00 -0500 Subject: [PATCH] Allow hyphenated JSDoc tags JSDoc tags may contain hyphens. For example, `@TJS-type`, which is used by [`typescript-json-schema`](https://www.npmjs.com/package/typescript-json-schema). --- src/lib/converter/comments/blockLexer.ts | 2 +- src/lib/converter/comments/lineLexer.ts | 2 +- src/lib/converter/comments/rawLexer.ts | 2 +- src/lib/utils-common/validation.ts | 2 +- src/test/comments.test.ts | 12 ++++++++---- src/test/utils/options/default-options.test.ts | 6 +++++- 6 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/lib/converter/comments/blockLexer.ts b/src/lib/converter/comments/blockLexer.ts index 7bd0bb5af..52913989e 100644 --- a/src/lib/converter/comments/blockLexer.ts +++ b/src/lib/converter/comments/blockLexer.ts @@ -263,7 +263,7 @@ function* lexBlockComment2( if (lookahead !== pos + 1) { while ( lookahead < end && - /[a-z0-9]/i.test(file[lookahead]) + /[a-z0-9-]/i.test(file[lookahead]) ) { lookahead++; } diff --git a/src/lib/converter/comments/lineLexer.ts b/src/lib/converter/comments/lineLexer.ts index b7312f433..876494d77 100644 --- a/src/lib/converter/comments/lineLexer.ts +++ b/src/lib/converter/comments/lineLexer.ts @@ -179,7 +179,7 @@ function* lexLineComments2( if (lookahead !== pos + 1) { while ( lookahead < end && - /[a-z0-9]/i.test(file[lookahead]) + /[a-z0-9-]/i.test(file[lookahead]) ) { lookahead++; } diff --git a/src/lib/converter/comments/rawLexer.ts b/src/lib/converter/comments/rawLexer.ts index e8bc8d6bc..ff063dc11 100644 --- a/src/lib/converter/comments/rawLexer.ts +++ b/src/lib/converter/comments/rawLexer.ts @@ -176,7 +176,7 @@ function* lexCommentString2( if (lookahead !== pos + 1) { while ( lookahead < end && - /[a-z0-9]/i.test(file[lookahead]) + /[a-z0-9-]/i.test(file[lookahead]) ) { lookahead++; } diff --git a/src/lib/utils-common/validation.ts b/src/lib/utils-common/validation.ts index 8febb48d6..eca8886d9 100644 --- a/src/lib/utils-common/validation.ts +++ b/src/lib/utils-common/validation.ts @@ -120,5 +120,5 @@ export function optional(x: T): Optional { } export function isTagString(x: unknown): x is `@${string}` { - return typeof x === "string" && /^@[a-zA-Z][a-zA-Z0-9]*$/.test(x); + return typeof x === "string" && /^@[a-z][a-z0-9-]*$/i.test(x); } diff --git a/src/test/comments.test.ts b/src/test/comments.test.ts index 0d2d77405..8647b6372 100644 --- a/src/test/comments.test.ts +++ b/src/test/comments.test.ts @@ -186,7 +186,7 @@ describe("Block Comment Lexer", () => { }); it("Should recognize tags", () => { - const tokens = lex("/* @tag @a @abc234 */"); + const tokens = lex("/* @tag @a @abc234 @abc-234 */"); equal(tokens, [ { kind: TokenSyntaxKind.Tag, text: "@tag", pos: 3 }, @@ -194,6 +194,8 @@ describe("Block Comment Lexer", () => { { kind: TokenSyntaxKind.Tag, text: "@a", pos: 8 }, { kind: TokenSyntaxKind.Text, text: " ", pos: 10 }, { kind: TokenSyntaxKind.Tag, text: "@abc234", pos: 11 }, + { kind: TokenSyntaxKind.Text, text: " ", pos: 18 }, + { kind: TokenSyntaxKind.Tag, text: "@abc-234", pos: 19 }, ]); }); @@ -641,7 +643,7 @@ describe("Line Comment Lexer", () => { }); it("Should recognize tags", () => { - const tokens = lex("// @tag @a @abc234"); + const tokens = lex("// @tag @a @abc234 @abc-234"); equal(tokens, [ { kind: TokenSyntaxKind.Tag, text: "@tag", pos: 3 }, @@ -649,6 +651,8 @@ describe("Line Comment Lexer", () => { { kind: TokenSyntaxKind.Tag, text: "@a", pos: 8 }, { kind: TokenSyntaxKind.Text, text: " ", pos: 10 }, { kind: TokenSyntaxKind.Tag, text: "@abc234", pos: 11 }, + { kind: TokenSyntaxKind.Text, text: " ", pos: 18 }, + { kind: TokenSyntaxKind.Tag, text: "@abc-234", pos: 19 }, ]); }); @@ -993,12 +997,12 @@ describe("Raw Lexer", () => { }); it("Should not recognize tags", () => { - const tokens = lex("@123 @@ @ @tag @a @abc234"); + const tokens = lex("@123 @@ @ @tag @a @abc234 @abc-234"); equal(tokens, [ { kind: TokenSyntaxKind.Text, - text: "@123 @@ @ @tag @a @abc234", + text: "@123 @@ @ @tag @a @abc234 @abc-234", pos: 0, }, ]); diff --git a/src/test/utils/options/default-options.test.ts b/src/test/utils/options/default-options.test.ts index 5975bd99c..8b9ab552c 100644 --- a/src/test/utils/options/default-options.test.ts +++ b/src/test/utils/options/default-options.test.ts @@ -161,11 +161,15 @@ describe("Default Options", () => { describe("blockTags", () => { it("Should disallow non-tags", () => { - throws(() => opts.setValue("blockTags", ["@bad-non-tag"])); + throws(() => opts.setValue("blockTags", ["@bad_tag"])); + throws(() => opts.setValue("blockTags", ["@2bad"])); }); it("Should allow tags", () => { doesNotThrow(() => opts.setValue("blockTags", ["@good"])); + doesNotThrow(() => opts.setValue("blockTags", ["@good2"])); + doesNotThrow(() => opts.setValue("blockTags", ["@Good"])); + doesNotThrow(() => opts.setValue("blockTags", ["@good-tag"])); }); });