fix(syntax): allow block comments between members

`skipTrivia` skipped `// line comments` but not `/* block comments */`, so one
written between two page or component members failed with a bare "Unexpected
character '/'". Block comments inside a braced body already worked, which made
the failure look arbitrary: the same comment parsed or did not depending on
whether it happened to sit inside a block.

`startsWithBlockComment` now skips only whitespace and line comments, so
`props {}` keeps refusing block comments with its own explained error rather
than silently swallowing one and dropping the declaration after it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-22 06:50:51 +05:30
co-authored by Claude Opus 5
parent 2c50a07ed2
commit 98a46091b5
2 changed files with 86 additions and 4 deletions
+35 -4
View File
@@ -163,8 +163,13 @@ export class Lexer {
pos = 0;
constructor(public readonly src: string) {}
/** Skip whitespace and `// line comments`. */
private skipTrivia(): void {
/**
* Skip whitespace and `// line comments`, but NOT block comments.
*
* Kept separate from `skipTrivia` so `startsWithBlockComment` can still see a
* block comment that `skipTrivia` would otherwise consume.
*/
private skipWhitespaceAndLineComments(): void {
const { src } = this;
while (this.pos < src.length) {
const c = src[this.pos]!;
@@ -180,9 +185,35 @@ export class Lexer {
}
}
/** True when the next non-trivia characters open a block comment. */
/**
* Skip whitespace, line comments and block comments.
*
* Block comments used to be skipped only inside a braced body, so one written
* between two members failed with a bare "Unexpected character '/'" -- the
* same comment parsed or did not depending on where it sat.
*/
private skipTrivia(): void {
const { src } = this;
while (this.pos < src.length) {
this.skipWhitespaceAndLineComments();
if (src[this.pos] === "/" && src[this.pos + 1] === "*") {
const close = src.indexOf("*/", this.pos + 2);
this.pos = close === -1 ? src.length : close + 2;
continue;
}
break;
}
}
/**
* True when the next non-trivia characters open a block comment.
*
* Deliberately skips only whitespace and line comments: `props {}` refuses
* block comments with an explained error, and that check must run before
* `skipTrivia` would swallow the comment and drop a declaration silently.
*/
startsWithBlockComment(): boolean {
this.skipTrivia();
this.skipWhitespaceAndLineComments();
return this.src[this.pos] === "/" && this.src[this.pos + 1] === "*";
}