Skip to content

fix(parser): report incomplete @let declarations like Angular - #529

Merged
Brooooooklyn merged 2 commits into
voidzero-dev:mainfrom
Cayan:test-let-declarations-from-angular
Oct 4, 2026
Merged

Brooooooklyn merged 2 commits into
voidzero-dev:mainfrom
Cayan:test-let-declarations-from-angular

Conversation

@Cayan

@Cayan Cayan commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Ports the seven @let cases from Angular's compiler specs that the conformance fixtures extract with empty assertions, and fixes the parser gap two of them exposed.

Fix: the HTML parser skipped IncompleteLet tokens (they fell through to the default arm), so @let foo = bar with no closing ; produced no error and no node. It now does what Angular's _consumeIncompleteLet does: it reports Incomplete @let declaration "foo". @let declarations must be written as `@let <name> = <value>;` and, when the declaration has a name, keeps a LetDeclaration node with an empty value. The lexer's IncompleteLet token now ends at the end of the consumed value instead of at the name, matching Angular's span.

Two lexer paths also produced no IncompleteLet token at all, so the new parser arm could never report them:

  • @let followed by EOF or a non-whitespace, non-identifier char (@let, @let;, @let-) fell back to plain text. Angular's _consumeLetDeclaration emits INCOMPLETE_LET for any non-whitespace character after @let.
  • @let foo bar and @let foo (whitespace after the name with no =) consumed the text and emitted nothing. Upstream marks the same start token INCOMPLETE_LET, so the token span ends at the name.

Tests, one per upstream case and named after its it() title:

  • ml_parser/lexer_spec.ts: escaped quotes in a string, function calls in the value, a complex expression
  • ml_parser/html_parser_spec.ts: the error for an incomplete let declaration, the locations of an incomplete let declaration
  • render3/r3_template_transform_spec.ts: syntax errors in the value, a let declaration with no value

Plus four regression tests for the newly covered lexer paths (@let foo bar = 123;, @let foo, @let, @let;), which have no upstream spec case.

The lexer and transform cases already pass on main; only the HTML parser cases needed the parser fix. For the syntax-error case, Angular's message carries a Parser Error: prefix that this crate does not add to any expression error, so the test matches the message without it.

Evidence:

  • cargo test -p oxc_angular_compiler: 2940 passed, 0 failed. cargo fmt --check is clean. Angular conformance: 1264/1264.
  • Replacing the new parser arm with a plain advance() fails both HTML parser tests. Moving the IncompleteLet span end back to the name fails the locations test. Disabling the backslash-escape skip in the lexer's quote scan, or no longer treating " as a quote, fails the escaped-quotes and complex-expression tests. Reverting either lexer fix fails the new regression tests.

Cayan and others added 2 commits October 4, 2026 00:26
- The HTML parser skipped `IncompleteLet` tokens, so `@let foo = bar` without
  a closing `;` produced no error and no node. It now reports Angular's
  "Incomplete @let declaration" error and, when the declaration has a name,
  keeps a node with an empty value, as Angular's `_consumeIncompleteLet` does.
- The lexer's `IncompleteLet` token now spans to the end of the consumed
  value, matching Angular's token location.
- Port the seven `@let` cases from Angular's lexer, HTML parser and template
  transform specs that the conformance fixtures extract with no assertions.
Two more paths produced no INCOMPLETE_LET token, so the new parser arm
could never report them:

- `@let` followed by EOF or any non-whitespace, non-identifier char
  (`@let;`, `@let-`) fell back to plain text. Angular's
  _consumeLetDeclaration emits INCOMPLETE_LET for any non-whitespace
  following character, not only identifier chars.
- `@let foo bar` and `@let foo` (a space after the name with no `=`)
  consumed "@let foo " and emitted nothing. Upstream marks the start
  token INCOMPLETE_LET, so the span ends at the name.
@Brooooooklyn
Brooooooklyn merged commit 772d57d into voidzero-dev:main Oct 4, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants