In some cases the `debugName` transform generates a spread into the signal function parameters. This can cause compiler errors, because the functions don't have rest parameters.
These changes work around it by adding a `@ts-ignore` above it.
This commit refactors the template type checking metadata interfaces to use detached, serializable metadata rather than retaining direct references to ts.Node or ts.Declaration instances.
A new tcb_adapter translates traditional TypeScript AST-bound metadata into these decoupled structures. This abstraction lays the groundwork for supporting native preprocessors (such as Rust or ts-go) which serialize metadata over JSON rather than passing live TypeScript objects.
Key changes:
- Introduced TcbDirectiveMetadata, TcbComponentMetadata, TcbReferenceMetadata, and TcbPipeMetadata to replace TypeCheckableDirectiveMeta where appropriate.
- Substituted deep TS compilation AST references with string module names and source spans to preserve out-of-band diagnostic capabilities.
- Detached generic typeParameters and transformType properties into synthesized, standalone TS mappings.
- Updated generateTypeCheckBlock and corresponding Operations to consume the new metadata.
The Angular compiler unconditionally adds a debug name transform for signals
which generates a conditional on `ngDevMode` (e.g., `ngDevMode ? { debugName: "xyz" } : []`).
During testing, `ngDevMode` is true, so the true branch executes but the
false branch is never executed. Consequently, coverage tools report the
false branch as an untested line/branch, preventing 100% test coverage.
This commit adds a synthetic `/* istanbul ignore next */` comment to the
generated false branch so that Istanbul ignores it. We only include the
istanbul comment (instead of additionally including c8) to focus on the
established standard for Angular CLI/Karma coverage while maintaining
compatibility with modern Vitest setups, since @vitest/coverage-v8 now
natively respects the fallback istanbul comment.
Fixes#64583
This is a follow-up to #67381 which introduced a subtle bug where depending on the type checking configuration, we may put an object literal directly in the TCB body which the TS compiler ends up interpreting as a block. These changes resolve the issue by always wrapping the literal in parentheses.
TypeScript has functionality that automatically escapes quotes in string literals. These changes update the places where we may need to do the same ourselves.
inputs & outputs cannot be binded to 2 different directives/components properties
Eg
```
data = model();
dataChange = output(); // throws because model already emits on the `dataChange` output
userSomething = input({alias 'user'});
user = input(); // throws because userSomething already binds to the `user` input
````
fixes#65844
BREAKING CHANGE: The compiler will throw when there a when inputs, outputs or model are binding to the same input/outputs.
Add help link to extended template diagnostic messages to provide
users with additional guidance and documentation resources. This
enhancement improves developer experience by making it easier to
understand and resolve complex template issues through direct
access to relevant Angular documentation with detailed examples
and explanations for each diagnostic type.
Wrap `@defer` trigger expressions (`when`, `prefetch when`, `hydrate when`)
in a conditional context within the TCB to enable TypeScript's TS2774
diagnostic for detecting functions used without invocation.
Previously, signals and functions passed to `when` triggers without
parentheses would silently evaluate to truthy, causing unexpected behavior.
Now the compiler reports an error when a function is used as a condition
without being called.
Supports binding `null` to a `<input type=number>`.
- Binding in `null` clears the input
- Binding in `NaN` also clears the input
- When the user clears the input, the model is set to `null`
- The model is _never_ set to `NaN` based on user interaction. It is
either set to `null` if the user cleared the input, or is unchanged
and a parse error added if the user entered an invalid number like
"42e"
PR Close#66917
The `isTypeOnly` property was deprecated in TypeScript and replaced by `phaseModifier`.
Updates the check to use `phaseModifier`, which is the recommended API for detecting type-only imports.
Additionally, removes the unused `metadata` parameter from the `NgModuleExtractor`
Based on the discussion in #66294: now that we support arrow functions in event listeners, developers may write out something like `(click)="() => expr"` which will be a no-op. These changes update the existing diagnostic for uninvoked expressions in listeners to account for it.
Refactors the `ɵɵcontrolCreate` and `ɵɵcontrol` instructions to delegate control logic to the forms package via new `ɵngControlCreate` and `ɵngControlUpdate` lifecycle hooks. Previously, the logic for binding form state to native elements and custom controls was hardcoded within `@angular/core`.
**Compiler Changes:**
- Introduces a new compilation phase `specializeControlProperties` (in `control_directives.ts`).
- This phase detects properties named `formField` and specializes them into `ControlCreate` and `Control` IR opcodes.
- These opcodes emit `ɵɵcontrolCreate` and `ɵɵcontrol` instructions, respectively.
**Runtime Changes:**
- `ɵɵcontrolCreate` acts as the creation phase. It locates the control directive and invokes its `ɵngControlCreate` method.
- `ɵɵcontrol` acts as the update phase, and invokes the control directive's `ɵngControlUpdate` method (if present).
- Introduces a `passThroughInput` configuration in `ControlFeature`. This specifies the input name (e.g., `formField`) that triggers the control. If the runtime detects that this input is bound to multiple targets (e.g., the `FormField` directive *and* the host component), the control is flagged as "pass-through". In this state, `ɵngControlCreate` returns a no-op update function, deferring responsibility to the other consumer (e.g., the component managing the field itself).
**Forms Changes:**
- `FormField` directive implements `ɵngControlCreate` and `ɵngControlUpdate`.
- Inside this hook, `FormField` determines the type of control it is attached to (Native, CVA, or Custom Signal Control) and delegates to the appropriate handler (`nativeControlCreate`, `cvaControlCreate`, or `customControlCreate`).
- Consolidates all form binding logic within `@angular/forms/signals`, enabling support for new `FormValueControl` and `FormCheckboxControl` interfaces.
- Reorganizes the codebase by moving `FormField` from `api/` to `directive/` and splitting the binding logic into semantic pieces:
- `control_native.ts`, `control_cva.ts`, and `control_custom.ts` contain the specific handlers for each control type.
- `native.ts` and `select.ts` provide helpers for native element discovery and select-specific synchronization.
- `bindings.ts` manages the tracking and application of property/attribute bindings.
When synthesizing an import corresponding with a .tsx file, the extension
would not be removed unlike regular .ts files. Adjust the import generators
to also drop any .tsx extension from module specifiers.
Closes#66262
```ts
@Component(...)
class Outer {
constructor() {
@Component(...)
class Inner {}
}
}
```
previous behavior was that IVy transformation was only applied to `Inner`, thus breaking `Outer` transformation.
Error message links now point to the archived documentation site (v*.angular.dev)
so that referenced content matches the framework version in use.
See angular#44650
PR Close#66374
This completes the rename started in #66136. `[field]` is too generic of
a selector for the forms system to own, and likely to cause naming
collisions with existing components. Therefore it is being renamed to
`[formField]`
Updates the template type checker to support arrow functions. The main challenge was getting the current infrastructure not to rewrite references to arrow function parameters.
Previously, object literal keys in the TCB did not have source spans attached. This made it difficult for the Language Service to distinguish between keys and values, leading to incorrect completion contexts and diagnostic locations.
This commit ensures that source spans are properly attached to the keys in the TCB.