diff --git a/src/lexer/NestedComment.ts b/src/lexer/NestedComment.ts index 983f0e3f28..4db128f329 100644 --- a/src/lexer/NestedComment.ts +++ b/src/lexer/NestedComment.ts @@ -2,8 +2,6 @@ import { RegExpLike } from './TokenizerEngine.js'; const START = /\/\*/uy; // matches: /* -const MIDDLE = /([^/*]|\*[^/]|\/[^*])+/uy; // matches text NOT containing /* or */ -const END = /\*\//uy; // matches: */ /** * An object mimicking a regular expression, @@ -15,29 +13,37 @@ export class NestedComment implements RegExpLike { public exec(input: string): string[] | null { let result = ''; let match: string | null; - let nestLevel = 0; if ((match = this.matchSection(START, input))) { result += match; - nestLevel++; } else { return null; } - while (nestLevel > 0) { - if ((match = this.matchSection(START, input))) { - result += match; - nestLevel++; - } else if ((match = this.matchSection(END, input))) { - result += match; + let nestLevel = 1; + // start at the last index, break if we find a closing */ that matches + for (let i = this.lastIndex; i < input.length; i++) { + if (input[i] === '*' && input[i + 1] === '/') { nestLevel--; - } else if ((match = this.matchSection(MIDDLE, input))) { - result += match; + result += '*/'; + i++; + if (nestLevel === 0) { + this.lastIndex = i; + return [result]; + } else if (nestLevel < 0) { + return null; + } + } else if (input[i] === '/' && input[i + 1] === '*') { + nestLevel++; + result += '/*'; + i++; } else { - return null; + result += input[i]; } } - + if (nestLevel > 0) { + return null; + } return [result]; } diff --git a/test/features/comments.ts b/test/features/comments.ts index 47b51ac957..4394123cbf 100644 --- a/test/features/comments.ts +++ b/test/features/comments.ts @@ -239,6 +239,12 @@ export default function supportsComments(format: FormatFn, opts: CommentsConfig `); }); + // Regression test for https://github.com/sql-formatter-org/sql-formatter/issues/747 + it('handles block comments with /** and **/ patterns', () => { + const sql = `/** This is a block comment **/`; + expect(format(sql)).toBe(sql); + }); + if (opts.hashComments) { it('supports # line comment', () => { const result = format('SELECT alpha # commment\nFROM beta');