__NG_ELEMENT_ID__ static fields are a part of how the Ivy node injector
works. In order to survive closure minification correctly, they need to
be annotated with @nocollapse.
PR Close#28050
When an @NgModule decorator executes, the module is added to a queue in
render3/jit/module.ts. Reading an ngComponentDef property causes this queue
to be flushed, ensuring that the component gets the correct module scope
applied.
In before_each.ts, a global beforeEach is added to all Angular tests which
calls TestBed.resetTestingModule() prior to running each test. This in turn
clears the module compilation queue (which is correct behavior, as modules
declared within the test should not leak outside of it via the queue).
So far this is okay. But before the first test runs, the module compilation
queue is full of modules declared in global scope. No definitions have been
read, so no flushes of the queue have been triggered. The global beforeEach
triggers a reset of the queue, aborting all of the in-progress global
compilation, breaking those classes when they're later used in tests.
This commit adds logic to TestBedRender3 to respect the state of the module
queue before the TestBed is first initialized or reset. The queue is flushed
prior to such an operation to ensure global compilation is allowed to finish
properly.
With this fix, a platform-server test now passes (previously the <my-child>
element was not detected as a component, because the encompassing module
never finished compilation.
FW-887 #resolve
PR Close#28033
An @NgModule with an 'id' property has its type registered in a global map
of modules by id. This happens during compilation of the module.
In Ivy, modules are first compiled when the @NgModule decorator executes.
In tests, they might be passed again through the TestBed's compiler,
resulting in a second compilation and registration.
Before this fix, this second registration would cause an error, as the id
was previously registered. This commit makes the registration idempotent,
so if the same module type is being registered for the same id then no
error is thrown.
Testing strategy: future commits change the way the TestBed compiles
modules, causing tests to become sensitive to this bug if not fixed.
PR Close#28033
Previously, we had the logic to schedule a change detection tick
inside markViewDirty(). This is fine when used in markDirty(),
the user-facing API, because it should always schedule change
detection. However, this doesn't work when used in markForCheck()
because historically markForCheck() does not trigger change
detection.
To be backwards compatible, this commit moves the scheduling
logic out of markViewDirty() and into markDirty(), so
markForCheck no longer triggers a tick.
PR Close#28048
Libraries that create components dynamically using component factories,
such as `@angular/upgrade` need to pass blocks of projected content
through to the `ComponentFactory.create()` method. These blocks
are extracted from the content by matching CSS selectors defined in
`<ng-content select="..">` tags found in the component's template.
The Angular compiler collects these CSS selectors when compiling a component's
template, and exposes them via the `ComponentFactory.ngContentSelectors`
property.
This change ensures that this property is filled correctly when the
component factory is created by compiling a component with the Ivy engine.
PR Close#27867
When a pipe returns an instance of WrappedValue we should "invalidate" value
of a binding where the pipe in question is used.
Before this change we've always wrtten the invalidation value (NO_CHANGE) to
the binding root this invalidating the first binding in a LView. This commit
corrects the binding index calculation so the binding with a pipe is invalidated.
PR Close#28044
exportAs in @Directive metadata supports multiple values, separated by
commas. Previously it was treated as a single value string.
This commit modifies the compiler to understand that exportAs is a
string[]. It stops short of carrying the multiple values through to the
runtime. Instead, it only emits the first one. A future commit will modify
the runtime to accept all the values.
PR Close#28001
Currently the ImportManager class handles various rewriting actions of
imports when compiling @angular/core. This is required as code compiled
within @angular/core cannot import from '@angular/core'. To work around
this, imports are rewritten to get core symbols from a particular file,
r3_symbols.ts.
In this refactoring, this rewriting logic is moved out of the ImportManager
and put behind an interface, ImportRewriter. There are three implementers
of the interface:
* NoopImportRewriter, used for compiling all non-core packages.
* R3SymbolsImportRewriter, used when ngtsc compiles @angular/core.
* NgccFlatImportRewriter, used when ngcc compiles @angular/core (special
logic is needed because ngcc has to rewrite imports in flat bundles
differently than in non-flat bundles).
This is a precursor to using this rewriting logic in other contexts besides
the ImportManager.
PR Close#27998
TestBed used to have its own implementation of the `transitiveScopesFor` function, customized for TestBed needs (to compile NgModules). This change unifies the `transitiveScopesFor` function usage by importing it from the `jit/module.ts` script and adding extra argument to configure its behavior (how to compile NgModule), so that TestBed can leverage it.
PR Close#27860
Previously the canInsertNativeNode and getRenderParent functions had almost
_exaclty_ the same logic. What was worse that getRenderParent was calling
canInsertNativeNode thus executing the same, non-trivial logic twice.
This commit merges canInsertNativeNode and getRenderParent into one function.
Now getRenderParent will return a native parent or null if a node can't be
inserted (content projection, root of a view that is not inserted etc.).
PR Close#28011
Previously presence and type of a parent tNode was split among
canInsertNativeNode, canInsertNativeChildOfView and canInsertNativeChildOfElement.
This commit centralises the logic in canInsertNativeNode thus simplifying
the overall logic and making canInsertNativeChildOfElement trivial.
PR Close#28011
This commit adds sanitization for `elementProperty` and `elementAttribute` instructions used in `hostBindings` function, similar to what we already have in the `template` function. Main difference is the fact that for some attributes (like "href" and "src") we can't define which SecurityContext they belong to (URL vs RESOURCE_URL) in Compiler, since information in Directive selector may not be enough to calculate it. In order to resolve the problem, Compiler injects slightly different sanitization function which detects proper Security Context at runtime.
PR Close#27939
Previously the appendChild / removeChild could take null as an argument for
a child to be added / removed. This is difficult to understand since the
mentioned methods are noop if a child is null.
This commit clarifies the appendChild / removeChild signature to systematically
require a child node to be added removed. It turns out that null could be passed
only for a very specific i18n cases so now we guard a call to removeChild with
an explicit check on the i18n side.
PR Close#27987
This update introduces support for global object (window, document, body) listeners, that can be defined via host listeners on Components and Directives.
PR Close#27772
`i18nAttributes` was throwing an error when it was called multiple times in the create part of the template function with the same index, for example when we create multiple components with the same template. It shouldn't throw in this case, and just use the cache when available.
FW-903 #resolve
PR Close#27911
Fixes Ivy's `QueryList` not being an instance of the exported ViewEnginer `QueryList`.
Also reworks `first`, `last` and `length` to be regular properties, rather than setters. Reworking `length` was required to be able to extend the ViewEngine `QueryList`, but I reworked `first` and `last` as well since getters generate a lot more code when transpiled to ES5.
These changes fix FW-706.
PR Close#27942
`R3TestBed` allows consumers to configure a "testing module", declare components, override various metadata, etc. To do this, it implements its own JIT compilation, where components/directives/modules have Ivy definition fields generated based on testing metadata. It results in tests interfering with each other. One test might override something in a component that another test tries to use normally, causing failures.
In order to resolve this problem, we store current components/directives/modules defs before applying overrides and re-compiling. Once the test is complete, we restore initial defs, so the next tests interact with "clean" components.
PR Close#27786
This PR assures that content projection works if an <ng-content> tag is
placed inside an <ng-template> in one component and that <ng-template>
is inserted into a different component. It fixes a bug where the
projection instruction code would walk up the insertion tree to find
selector data instead of the declaration tree.
PR Close#27783
Prior to this change, ICU extraction logic was not taking into account nested bindings (that look like this: �0:1�) and only accounted for top level bindings (like this �0�). As a result, ICUs were not parsed and remained as text in the output. Now the extraction logic (regular expressions) take into account the nested bindings format as well.
PR Close#27914
Some of the animation tests have been failing because animation gets
triggered multiple times. The reason for this is that the compiler was
generating static attribute bindings in addition to dynamic bindings.
This created multiple writes to the animation render which failed the
tests.
PR Close#27805
Forward refs in some places (like imports/export/providers/viewProviders/queries) were not resolved before passing to compilation phase. Now we resolve missing refs before invoking compile function.
PR Close#27737
Prior to this commit, we had two different modes for change detection
execution for Ivy, depending on whether you called `bootstrap()` or
`renderComponent()`. In the former case, we would complete creation
mode for all components in the tree before beginning update mode for
any component. In the latter case, we would run creation mode and
update mode together for each component individually.
Maintaining code to support these two different execution orders was
unnecessarily complex, so this commit aligns the two bootstrapping
mechanisms to execute in the same order. Now creation mode always
runs for all components before update mode begins.
This change also simplifies our rendering logic so that we use
`LView` flags as the source of truth for rendering mode instead of
`rf` function arguments. This fixed some related bugs (e.g. calling
`ViewRef.detectChanges` synchronously after the view's creation
would create view nodes twice, view queries would execute twice, etc).
PR Close#27744
We invoked `hostBindings` function in Create and Update modes with different element index due to the fact that we did not subtract HEADER_OFFSET from the index before passing it to `hostBindings` function in Create mode. Now we subtract HEADER_OFFSET value before invoking `hostBindings`, which makes Ceate and Update calls consistent.
PR Close#27694
Context discovery was only available on elements. This PR adds support for containers and ICU expressions.
FW-378 #resolve
FW-665 #comment linker integration tests
PR Close#27644
`NgModule` requires that `Component`s/`Directive`s/`Pipe`s are listed in
declarations, and that each `Component`s/`Directive`s/`Pipe` is declared
in exactly one `NgModule`. This change adds runtime checks to ensure
that these sementics are true at runtime.
There will need to be seperate set of checks for the AoT path of the
codebase to verify that same set of semantics hold. Due to current
design there does not seem to be an easy way to share the two checks
because JIT deal with references where as AoT deals with AST nodes.
PR Close#27604
While creating FESM files, rollup usually drops all unused symbols.
All *__POST_R3__ are unused unless ngcc rewires stuff. To prevent this DCE
we reexport them as private symbols. If ngcc is not used, these symbols will
be dropped when we optimize an application bundle.
PR Close#27438
Prior to this change, we were unable to match directives using `ng-template` tags (for example the following selector would not work even though there might be some <ng-template>s in a template: `ng-template[directiveA]`. As a result, that broke some components that relies on such selectors to work. In order to resolve the problem, we now pass tag name to the `template` instruction (where we passed `null` before) and this tag name is used for matching at runtime. This update should also help support projecting containers, because the tag name is required to properly match such elements.
PR Close#27636
In Ivy, a pure call to `setClassMetadata` is inserted to retain the
information that would otherwise be lost while eliding the Angular
decorators. In the past, the Angular constructor decorators were
wrapped inside of an anonymous function which was only evaluated once
`ReflectionCapabilities` was requested for such metadata. This approach
prevents forward references from inside the constructor parameter
decorators from being evaluated before they are available.
In the `setClassMetadata` call, the constructor parameters were not wrapped
within an anonymous function, such that forward references were evaluated
too early, causing runtime errors.
This commit changes the `setClassMetadata` call to pass the constructor
parameter decorators inside of an anonymous function again, such that
forward references are not resolved until requested by
`ReflectionCapabilities`, therefore avoiding the early reads of forward refs.
PR Close#27561
Currently the `ViewRef.destroy` method assumes that its index inside the view container will always be valid, however if it has been removed already, it'll be -1 which will throw an error.
The error manifested itself in one of the unit tests where a view had been detached during the test and then `TestBed` attempted to destroy its `ComponentRef` which ended threw an `Error during cleanup of component`.
PR Close#27585
Since Renderer is shared across root and child views, we need to avoid `destroy` method invocation for child views and only invoke is for root view when needed. Prior to this change, the `destroy` function was called whenever child view was destroyed, thus causing errors at runtime.
PR Close#27592
Previously in Ivy, host bindings did not work if they shared a public name
with an Input because they used the `elementProperty` instruction as is.
This instruction was originally built for inside component templates, so it
would either set a directive input OR a native property. This is the
correct behavior for inside a template, but for host bindings, we always
want the native properties to be set regardless of the presence of an Input.
This change adds an extra argument to `elementProperty` so we can tell it to
ignore directive inputs and only set native properties (if it is in the
context of a host binding).
PR Close#27589
In `ViewRef.detectChanges`, we are passing `ViewRef.context` into `detectChanges` to trigger change detection. This only makes sense for component `ViewRefs` (i.e. injected `ChangeDetectorRefs`) because with embedded views, `context` is not a component instance where the view has been monkey-patched. It's a just a normal object, so the view will be undefined.
In order to resolve this problem, we now invoke `detectChangesInternal` and also pass `LView` (to make sure we always have a view available).
PR Close#27521
We had two `NodeInjector` classes: one in `view_compatibility` and one in `di`. We replaced the one in `di` with the one from `view_compatibility` and reconciled their differences.
PR Close#27541
Prior to this change, animation properties were defined as element attributes, which caused errors at runtime. Now all animation-related attributes are defined as element properties.
Also as a part of this update, we start to account for bindings used in animations, which was previously missing.
PR Close#27496
Analogously to directives, the `ngInjectableDef` field in .d.ts files is
annotated with the type of service that it represents. If the service
contains required generic type arguments, these must be included in
the .d.ts file.
PR Close#27037
(FW-777)
When an Injector is provided, R3Injector instantiates it by calling its
constructor instead of its factory, not resolving dependencies.
With this fix, the ngInjectorDef is checked and the factory is correctly
used if it is found.
PR Close#27456
When detaching a view by its index via `ViewContainerRef.detach(index)`, in `ViewEngine` we used to return a new `ViewRef` ([for reference](https://github.com/angular/angular/blob/master/packages/core/src/view/refs.ts#L227)), however in Ivy we return the same `ViewRef` which means that its internal `_viewContainerRef` is never reset and we'll throw an error if the consumer tried to attach it to the `ApplicationRef`. These changes return a new `ViewRef` in order to match the original behavior.
These changes also add the same errors as `ViewEngine` when attempting to attach a view that is attached already. This was the original goal of this PR, however it ended up uncovering the issues with the `ViewRef`.
PR Close#27437
Prior to this change, the number of host vars stored for directives with `hostBindings` in expando block was incorrect for inherited directives (in case both parent and child directive have `hostBindings` defined). Now if we identify that we already added a `hostBinding` into expando block, we just increase the corresponding number of host binding vars
PR Close#27392
In Angular, it used to be an accepted practice to use strings as dependency
injection tokens. E.g. {provide: 'test', useValue: 'provided'}. However,
the Ivy node injection system did not support this. The Ivy DI system
attempts to patch a Bloom bit index onto each type registered with it, and
this patch operation does not work for a string token.
This commit adds string token support to the bloom filter system by
reserving bit 0 for string tokens. This eliminates the need for each string
token to store its own Bloom bit, at the expense of slightly more expensive
lookups of string tokens.
PR Close#27383
Previously the concept of multiple directives with the same selector was
not supported by ngtsc. This is due to the treatment of directives for a
component as a Map from selector to the directive, which is an erroneous
representation.
Now the directives for a component are stored as an array which supports
multiple directives with the same selector.
Testing strategy: a new ngtsc_spec test asserts that multiple directives
with the same selector are matched on an element.
PR Close#27298
BREAKING CHANGE:
The public API for `DebugNode` was accidentally too broad. This change removes
1. Public constructor. Since `DebugNode` is a way for Angular to communicate information
on to the developer there is no reason why the developer should ever need to
Instantiate the `DebugNode`
2. We are also removing `removeChild`, `addChild`, `insertBefore`, and `insertChildAfter`.
All of these methods are used by Angular to constructor the correct `DebugNode` tree.
There is no reason why the developer should ever be constructing a `DebugNode` tree
And these methods should have never been made public.
3. All properties have been change to `readonly` since `DebugNode` is used by Angular
to communicate to developer and there is no reason why these APIs should be writable.
While technically breaking change we don’t expect anyone to be effected by this change.
PR Close#27223
This fixes an issue where a value would hide the type.
```
export interface Foo {
someMethod(): void;
}
export const Foo: Function = ...;
```
In the above example the `Foo` constant will hide the `interface Foo` symbol.
This change properly saves the interface in addition to the type.
PR Close#27223
A recent commit (probably 2c7386c) has changed the import graph of the
DI types in core, and somehow results in the ngc compiler deciding to
re-export core DI types from application factories which tangentially
use inject(). This is not really surprising; ngc's import graph can be
very unstable.
However, this results in a re-export of InjectFlags surviving JS
compilation. InjectFlags was a const enum, akin to an interface in TS,
with no runtime repesentation. This causes a warning to be emitted by
Webpack when it sees the re-export of InjectFlags.
This commit avoids the issue by removing 'const' from the declaration
of InjectFlags, causing it to have a runtime value. This is a temporary
fix. The real fix will be for ngc to no longer write exports of const
enums.
Testing strategy: manually verified. Due to the problem only manifesting
when recompiling after a change and then running Webpack, there is no
existing framework via which this could be easily tested with an
integration test. Additionally, the potential for this issue is gone in
Ivy, so this solution is only temporarily needed.
Fixes#27251.
PR Close#27279
Currently we store the `_appRef` when a `ViewRef` is attached, however we don't use it for anything. These changes use it to detach the view from the `ApplicationRef` when it is destroyed. These changes also fix that the `ComponentRef` doesn't remove its `ViewRef` on destroy.
PR Close#27276