In order to serialize and hydrate i18n blocks, we need to be able to walk an AST for the translated message. This AST is generated during normal parsing of the message.
PR Close#54724
For model signals we introduced some sniffing on the return type of a
`.subscribe` invocation- allowing for subscribe to _just_ return a
callback directly to unsubscribe.
This works in practice, but the positive `tCleanup` indices have more
meaning, especially in the context of `DebugElement`. A positive index
indicates a DOM event- so we need to revert this change. This now
surfaced as we made `EventEmitter` return a function + the subscription
via a proxy that ended up `typeof function` --> and broke some tests
where debug element incorrectly invoked non-dom outputs as dom
listeners. We don't need this change with current unsubscribe function
concept.
PR Close#54650
Currently the `makeProgram` utility from `ngtsc/testing` does not use
the test host by default- optimizing for source file caching.
Additionally, the host can be updated to attempt caching of the `.d.ts`
files from `@angular/core`— whether that's fake core, or the real core-
is irrelevant. We are never caching if these changes between tests, so
correctness is guaranteed.
This commit reduces the type check test times form 80s to just 11
seconds, faster than what it was before with `fake_core`. The ngtsc
tests also run significantly faster. From 40s to 30s
PR Close#54650
The `inject` global augmentation from upgrade tests, leak into
all source files for IDEs, making it easy to run into issues
when actually trying to deal with `inject` from Angular core for DI.
PR Close#54650
Technically `model()` and `output()` already need to be defined in an
injection context- because `OutputRef` requires this.
To improve the error messaging, this commit asserts this as part of the
top-level entry functions for `model()` and `output()`. Without this
change, the error would mention the `_createOutputRef` internal
function.
PR Close#54650
An `EventEmitter` is a construct owned by Angular that should be
used for outputs as of right now.
As we are introducing the new `OutputRef` interface for the new output
function APIs, we also think `EventEmitter` should implement
`OutputRef`— ensuring all "known" outputs follow the same contract.
This commit ensures `EventEmitter` implements an `OutputRef`
Note: An output ref captures the destroy ref from the current injection
context for clean-up purposes. This is also done for `EventEmitter` in a
backwards compatible way:
- not requiring an injection context. EventEmitter may be used
elsewhere.
- not cleaning up subscriptions/completing the emitter when the
directive/component is destroyed. This would be a change in behavior.
Note 2: The dependency on `DestroyRef` causes it to be retained in all
bundling examples because ironically `NgZone` uses `EventEmitter`- not
for outputs. The code is pretty minimal though, so that should be
acceptable.
`EventEmitter` will now always retain `NgZone. This increases the
payload size slightly around 800b for AIO. Note that the other increases
were coming from previous changes. This commit just pushed it over the
threshold.
PR Close#54650
A model signal is technically an output, at runtime and conceptually.
This commit re-uses the shared output ref logic and ensures the
interfaces match.
PR Close#54650
This commit introduces an addition to `output()` and
`outputFromObservable`()` —called `outputToObservable()`.
The helper lives in the RxJS interop package and allows agnostic
programmatic subscriptions to `OutputRef`s by converting the output
to an observable with `.pipe` etc.
The function is ideally used in all places where you subscribe to an
output programmatically. Those outputs in the future, with the new APIs,
may not be actual RxJS constructs, but abstract `OutputRef`'s that
simply expose a `.subscribe` method. The helper allows you to
agnostically convert outputs to RxJS observables that you can safely
interact with.
The observables are also completed automatically, if possible, when the
owning directive/component is destroyed— Something that is not
guaranteed right now.
PR Close#54650
Introduces a second API in addition to the new `output()` function.
The new function `outputFromObservable()` can be used to declare outputs
using the new `OutputRef` API and `output()` API, while using a custom
RxJS observable as data source.
This is something that is currently possible in Angular and we would
like to keep possible- even though we never intended to support custom
observables aside from RxJS-based `EventEmitter`.
The interop bridges the gap and allows you to continue using
`Subject`, `ReplaySubject`, `BehaivorSubjct,` - or cold custom
observables for outputs. You can still trigger logic only when
the output is subscribed- unlike with imperative `emit`s of
`EventEmitter` or the new `OutputEmitterRef`.
A notable difference is that you need two class members where you
previously could access the `Subject` directly. This is an intentional
trade-off we've made to ensure that all new outputs implement the
`OutputRef` interface and we are exposing a minimal API surface to
consumers of components that currently access the output
programmatically.
PR Close#54650
This commit allows us to detect initializer APIs like
`outputFromObservable` that are declared in different modules- not
necessarily `@angular/core`.
PR Close#54650
This commit exposes the new `output()` API with numerous benefits:
- Symmetrical API to `input()`, `model()` etc.
- Fixed types for `EventEmitter.emit`— current `emit` method of
`EventEmitter` is broken and accepts `undefined` via `emit(value?: T)`
- Removal of RxJS specific concepts from outputs. error channels,
completion channels etc. We now have a simple consistent
interface.
- Automatic clean-up of subscribers upon directive/component destory-
when subscribed programmatically.
```ts
@Directive({..})
export class MyDir {
nameChange = output<string>(); // OutputEmitterRef<string>
onClick = output(); // OutputEmitterRef<void>
}
```
Note: RxJS custom observable cases will be handled in future commits via
explicit helpers from the interop.
PR Close#54650
This commit creates the proposed `OutputRef` interface along
with `OutputEmitterRef`:
- `OutputRef` is the consistent interface for all Angular outputs.
- `OutputEmitterRef` is an extension for emitting values. Like
`EventEmitter`.
- subscriptions are cleaned up automatically upon directive/component
destroy.
- emitting is an error when destroyed
- subscribing programmatically is an error when already destroyed.
This commit will also implement the shared output ref runtime construct,
that can be used by `output()`, `outputFromObservable()` and `model()`.
We will manage subscriptions in a simple way, manually, without RxJS.
PR Close#54650
This commit replaces `fake_core` with the real `@angular/core`
output. See previous commit for reasons.
Overall, this commit:
* Replaces references of `fake_core`
* Fixes tests that were testing Angular compiler detection that _would_
already be flagged by type-checking of TS directly. We keep these
tests for now, and add `@ts-ignore` to verify the Angular checks, in
case type checking is disabled in user applications- but it's worth
considering to remove these tests. Follow-up question/non-priority.
* Adds `@ts-ignore` to the tests for `defer` 1P because the property is
marked as `@internal` and now is (correctly) causing failures in the
compiler test environment.
* Fixes a couple of tests with typos, wrong properties etc that
previously weren't detected! A good sign.
PR Close#54650
As part of improving test safety of the compiler, I've noticed that
we have a special pass for detecting external `ModuleWithProviders`
where we detect the module type from an object literal.
This literal is structured like the following: `{ngModule: T}`. The
detection currently takes `T` directly, but in practice it should be
`typeof T` to satisfy the `ModuleWithProviders` type that is accepted
as part of `Component#imports`.
This commit adds support for this, so that we can fix the unit test
in preparation for using the real Angular core types in ngtsc tests.
PR Close#54650
In https://github.com/angular/angular/pull/54591, a `BUILD.bazel` file was created in `aio/content/cli/help/BUILD.bazel`, this however breaks the automatic CLI help pages updates as prior to this change, the `help` directory was being deleted. See: 17346e89da
This commit, updates the process to delete only the JSON files and copying the new files.
PR Close#54697
This adds documentation regarding the latest changes to framework merge tools. It specifically covers the requires: TGP label and separate sync for primitives.
PR Close#54664
Previously, the language service relied on deep imports such as `@angular/compiler/render3/...`. This is bad form, because that creates a dependency on the package's internal structure. Additionally, this is not compatible with google3.
In this PR, I replace all the deep imports with shallow imports, in some cases adding the missing symbol to the `compiler.ts` exports.
PR Close#54695
This commit updates TestBed logic to take into account situations when dependencies loaded within `@defer` blocks may import NgModules with providers. For such components, we invoke provider override function, which recursively inspects and applies the necessary changes.
PR Close#54667
In zone-full applications, this is already true because effects are
scheduled inside a microtask and tracked by ZoneJS. When not using
zones, this should stay consistent on principle and for testability
reasons. A general pattern with zoneless testing will be to update state
and `await` some promise (i.e. `fixture.whenStable`, which will be
linked to `ApplicationRef.isStable`).
PR Close#53835
The current behavior of `autoDetect` in `ComponentFixture` does not
match production very well. It has several flaws that make it an
insufficient change detection mechanism:
* It runs change detection for the component under test _after_ views
attached to the `ApplicationRef`. This can cause real behavior
differences that break in production, because tests can observe view
refreshes in the incorrect order (for example, a dialog refreshing
before the component which opened it).
* Because of the above ordering, render hooks registered during change
detection of the fixture views _will not execute at all_ because
`ApplicationRef.tick` already happen.
* It does not rerun change detection on the view tree if there are more
dirty views to refresh after the render hooks complete.
* It effectively hides/swallows errors from change detection inside the
`onMicrotaskEmpty` subscription by not reporting them to the error
handler. Instead, this error ends up being unhandled in the
subscription and rxjs throws these in a `setTimeout`.
All of the above are problematic but this commit _does not_ fix the
final point. Ideally, we can land this in a future change but this
requires additional internal fixes. In the meantime, we have to juggle
special-case handling of the component fixture views within
`ApplicationRef.tick` using some special events to retain current
behavior and avoid errors from the fixture propagating to the `ErrorHandler`.
breaking note for future when isG3 flag condition is removed for v18:
The `ComponentFixture.autoDetect` feature now executes
change detection for the fixture within `ApplicationRef.tick`. This more
closely matches the behavior of how a component would refresh in
production. The order of component refresh in tests may be slightly
affected as a result, especially when dealing with additional components
attached to the application, such as dialogs. Tests sensitive to this
type of change (such as screenshot tests) may need to be updated.
PR Close#54354