Repository navigation
feat: support @boundary/@error blocks and ++/-- in event listeners (#700) - #713
Conversation
Angular 22.2 added @boundary/@error blocks and 22.3.0-next added ++/-- in event listeners. Move the reference submodule so their specs are extracted, and regenerate the fixtures and snapshot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Angular 22.3 lexes `++`/`--` as operators instead of reporting an error. `+`/`-` now go through one `scan_plus_or_minus` (like upstream `scanPlusOrMinus`), which the template-literal scanner shares, so the longest operator wins: `a+++b` is `a`, `++`, `+`, `b`. Ported from angular/angular 7b9c65691c. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add `Increment`/`Decrement` to the output `UnaryOperator` and an `is_prefix` flag to `UnaryOperatorExpr`, and print postfix operators after their operand (upstream ec69ef76e8). ngc prints through TypeScript's printer, which keeps `- --a` apart and parenthesizes a unary operand of a member access. Our emitter prints JavaScript directly, so it now does the same: a space between a prefix `+`/`-` and an operand starting with the same character (`---a` would parse as `--(-a)`), and parentheses around a unary receiver of a property, keyed read or call (`(a++).b`, `(-a).toFixed()`). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Angular 22.3 allows the increment and decrement operators in event listener statements and inside arrow functions; anywhere else they are a binding error. Port the parser and template pipeline parts: - `Unary` gets `Increment`/`Decrement` operators and an `is_prefix` flag (upstream `Unary.createPrefixUpdate` / `createPostfixUpdate`). - `parse_prefix` reads `++a`/`--a`, `parse_call_chain` reads `a++`/`a--` after the member/call chain, and `validate_increment_decrement_target` reports `Bindings cannot contain assignments` outside actions, `The '?.' operator cannot be used in the assignment` for safe reads and `The expression cannot be used in the assignment` for anything but a property or keyed read (parentheses and `!` are looked through, as in upstream `unwrapWriteTarget`). Invalid updates parse to an empty expression, like upstream. - `++`/`--` on the left of `**` is allowed (JS update expressions). - A token left over after an expression is quoted in the chain error (`Unexpected token '.'`), as upstream does. - The IR `UnaryExpr`, ingest, name resolution and reify carry the operator and `is_prefix` through to the output AST. - The conformance unparser/serializer print postfix operators and keep adjacent prefix operators apart (`- -foo`, `+ ++foo`). Conformance: every `++`/`--` lexer, parser and serializer spec passes (1292 -> 1429 of 1456). Emit tests compare with ngc 22.3.0-next.4 output, including the `r3_view_compiler/operators.ts` compliance case, nested views, host listeners, arrow functions in bindings and partial output round-tripped through the linker. Ported from angular/angular 76e5beb931 and 6ea13efc20. The linker part (ead4f0f56d, postfix in the Babel AST factory) needs no port: our linker runs the same pipeline and emitter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…zed update tag - `++;`, `foo(++)`, `[++]` now report `Unexpected token X` as Angular's `parsePrimary` does, instead of compiling to `undefined`. - An invalid update inside a pipe (`a++ | json`, `a | foo:b++`) no longer adds a second `Unexpected token |` / `Unexpected end of expression` error. - `(count++)\`x\`` keeps its parentheses, as ngc prints it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port Angular 22.3's `@boundary` block and its `@error` blocks. Parser and R3 AST: - lex `@boundary` as a block and connect `@error` blocks to it - add `R3BoundaryBlock` / `R3BoundaryErrorBlock` - parse `@error` parameters (`let` aliases, `when` condition) with the same messages and spans as `createBoundaryBlock` Template pipeline: - `BoundaryCreate` / `BoundaryErrorCreate` create ops and a `Boundary` update op, plus a `BoundaryState` expression - new phases `generateBoundaryConditions` and `resolveBoundaries`, in the same place as upstream - `$error` aliases read `bnd.error` in the parent view and the error view context inside the `@error` view - reify to `ɵɵboundaryCreate`, `ɵɵconditionalBranchCreate`, `ɵɵboundaryUpdate` and `ɵɵgetBoundary` Conformance: the r3_transform boundary spec now passes (1293/1456). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 27 output tests checked against ngc 22.3.0-next.4 (the 7 compliance goldens plus edge cases: nesting, @if/@for/@defer, @let, local refs, listeners, svg, i18n, ng-template, sibling boundaries) - each one is also compiled in partial mode and linked; the linked template must match the full output - diagnostics with exact messages and spans from `parseTemplate` - a pipe used only in a `when` condition Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
whitespace - The boundary state variable is now initialized with a separate `GetBoundary` IR expression (Angular's `ng.getBoundary(SlotLiteralExpr)`), so resolve_boundaries no longer rewrites it into `const bnd_rN = bnd_rN` inside arrow functions. - resolve_boundaries fills its map in `unit.ops()` order (arrow functions, create, update), so the update list's variable wins as in Angular. - `when` conditions are moved into `processed` instead of cloned. Visitors reach them twice through `BoundaryUpdateOp::when_exprs`, like Angular's shared nodes: one arrow function per condition, var counts and usage counts unchanged, and a pipe in a condition is created twice on one slot, as ngc does. - Single-use `bnd` inlining skips reads inside hoisted arrow functions when counting and replaces them too, as Angular's shared `bnd.error` node does. - `@error` parameters use JavaScript's `\s` / `trim` (U+FEFF yes, U+0085 no). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2f324aac0b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…gation `(count++)?.toString()` with legacy optional chaining ran `count++` in both the null check and the read. Treat update operators as having side effects so the value goes into a temporary. ngc has the same bug here; we don't copy it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An i18n block inside an @error view lost its element placeholders, because the i18n phases never walked into BoundaryErrorCreate views. ngc skips them too and crashes on such templates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e05297f323
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Revert e05297f, which made i18n inside an @error view compile by guessing at output ngtsc doesn't produce. ngtsc 22.3.0-next.4 fails on every template where an i18n message has an element or block placeholder with no value: an i18n block around a @boundary, or element placeholders in an i18n block inside an @error view. Match that: such a placeholder is now a compile error instead of an empty string. i18n that ngtsc compiles (text, interpolation, ICU, attributes, the primary view) is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 50a86eda86
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
ngtsc 22.3.0-next.4 reads `count++ / 2` as the start of a regular expression and fails with the same lexer error we give. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Keep them coming! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Keep it up! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Closes #700
Adds the two new Angular 22 template features. Output is checked against ngc 22.3.0-next.4.
@boundary { } @error { }54ed62d240and the v22.3.0-next.4 sources: block parsing and checks, IR ops,boundary_conditionsandresolve_boundariesphases, slots/vars/naming, reify.@error (let e; when …), several@errorblocks,$error/$reset, nesting, and use inside@for/@if/@defer.whencondition match ngc. This includes one ngc quirk we copy for parity: a pipe inwhenis created twice in the same slot.++/--7b9c65691c,76e5beb931,ec69ef76e8,6ea13efc20.Bindings cannot contain assignments. Bad targets (a?.b++,5++,foo()++) give the same errors as upstream.(-count).toFixed()used to lose its parentheses (which changed what it did). It now keeps them, as ngc does.Reference submodule
v22.3.0-next.4so the specs for both features get extracted.++/--and@boundaryspecs pass. The 26 that fail are other new 22.3 features left for follow-ups:@content,<?xml ?>, template-literal error messages, regex escaped slash,<script>in custom namespaces, CSS nesting.Known gaps (same as today for
=)@let(i++) is not rejected. ngc's type checker rejects it.@if (…)conditions don't report++errors.@boundary, or element placeholders in an i18n block inside@error, is a compile error. ngtsc 22.3.0-next.4 fails on the same templates, so we match it instead of guessing. i18n that ngtsc compiles there (text,{{x}}, ICU, attributes, the primary view) works.(count++)?.xin legacy?.mode stores the update in a temp. ngtsc runscount++twice here; we don't copy that.Tests
boundary_test.rs: all 7 upstreamr3_view_compiler_boundariesgoldens, plus edge cases, diagnostics and a linker round-trip.increment_decrement_test.rs: theoperators.tsgolden, plus precedence, errors and the linker.cargo test --all-features: 4187 passed. napipnpm test: 572 passed.🤖 Generated with Claude Code