- Extracts and documents code that will be common to interpolation instructions
- Ensures that binding indices are updated at the proper time during compilation
- Adds additional tests
Related #30011
PR Close#30129
The `renderStringify` function is used in a lot of performance-sensitive places, however it contains a megamorphic read which is used primarily for error messages. These changes introduce a new function that can be used to stringify output for errors and removes the megamorphic read from `renderStringify`.
This PR resolves FW-1286.
PR Close#30082
Fixes view and content queries not being inherited in Ivy, if the base class hasn't been annotated with an Angular decorator (e.g. `Component` or `Directive`).
Also reworks the way the `ngBaseDef` is created so that it is added at the same point as the queries, rather than inside of the `Input` and `Output` decorators.
This PR partially resolves FW-1275. Support for host bindings will be added in a follow-up, because this PR is somewhat large as it is.
PR Close#30015
Fixes Ivy throwing an error because it tries to generate styling instructions for empty `style` and `class` bindings.
This PR resolves FW-1274.
PR Close#30024
Previously, we had a bug where directive matching could fail if the directive
attribute was bound and followed a certain number of classes. This is because
in the matching logic, we were treating classes like normal attributes. We
should instead be skipping classes in the attribute matching logic. Otherwise
classes will match for directives with attribute selectors, and as we are
iterating through them in twos (when they are stored as name-only, not in
name-value pairs), it may throw off directive matching for any bound attributes
that come after. This commit changes the directive matching logic to skip
classes altogether.
PR Close#30002
We only set ng-reflect properties on directive input bindings.
This PR ensures that we also add ng-reflect properties on unbound inputs for backwards compatibility.
FW-1266 #resolve
PR Close#29973
Previous to this change, we assumed embedded views could only be created after
their parent template node had completed processing. As a result, we only set
up query logic for containers after directives on the node were created.
However, this assumption didn't take into account the case where a directive
on a template node could create views in its constructor.
This commit fixes query logic to work with views created in constructors.
In that case, we need to create a query container before the new view is
rendered so query results in the view aren't lost. But since the query container
is created before directives have completed processing, we also have to ensure
that query results gathered later on the template node are inserted before that
query container. Otherwise, query results in embedded views will clobber query
results on template nodes.
This splice mode may be slightly slower than the normal matching for queries on
containers, but we should only fall back to this strategy in the edge case where
views are created in constructors. (We should encourage developers to create
views in ngOnInit instead).
PR Close#29983
Prior to this change, components created via TestBed.createComponent in the same test were placed into the same root context, which caused problems in conjunction with fixture.autoDetectChanges usage in the same test. Specifically, change detection was triggered immediately for created component (starting from the 2nd one) even if it was not required/desired. This commit makes Ivy and VE behavior consistent: now every component created via TestBed.createComponent is isolated from each other. Current solution uses host element id naming convention, which is not ideal, but helps avoid public API surface changes at this point (we might revisit this approach later).
Note: this commit also adds extra tests to verify bootstrap and change detection behavior in case of multiple components in `bootstrap` array in @NgModule, to make sure this behavior is aligned between Ivy and VE.
PR Close#29981
The `TNode.cleanup` data structure can contain sequences of 4-element
sequence of entries (event handlers, directive outputs) mixed with
2-element sequence of entries (QueryList cleanup). Before this fix
we would always skip 4 elements in the `TNode.cleanup` while looking
up event handler cleanups. 4-element skips are not correct in case
of query cleanup presence and this commit corrects the algorithm to
jump 4 or 2 elements depending on a type of cleanup encountered.
PR Close#29957
If a component has its definition set by defineComponent (as opposed to
JIT getter), then it will generate a factory that uses directiveInject()
to retrieve its dependencies. This can be problematic in test code because
tests could use the injection utility before bootstrapping the component,
and directiveInject() relies on the view having been created.
This commit tweaks directiveInject() to fall back to inject() if the view
has not been created. This will allow injection to work in tests even if
it is called before the component is bootstrapped.
PR Close#29948
Previous to this commit, providing a component or directive in a test
module without @Injectable() would throw because the injectable factory
would not be found. Providing components in tests in addition to declaring
or importing them is not necessary, but it should not throw an error.
This commit ensures factory data is saved when component defs and directive
defs are created, which allows them to be processed by the module injector.
Note that bootstrapping is still required for this setup to work because
directiveInject() does not support cases where the view has not been
created. This case will be handled in a future commit.
PR Close#29945
We had a bug where event.preventDefault() was not always called if listeners
were coalesced. This is because we were overwriting the previous listener's
result every time we called the next listener, so listeners early in the chain
that returned false would be ignored and preventDefault would not be called.
This commit fixes that issue, so now preventDefault() is called if any listener
in a coalesced chain returns false. This brings us in line with View Engine
behavior.
PR Close#29934
Overriding multi provider values (providers with `multi: true` flag) via TestBed require additional handling: all existing multi-provider values for the same token should be removed from the override list, so that they are not included into the final value of a given provider. This commit adds this logic to make sure we handle multi providers correctly.
PR Close#29919
Because the styling context may be stored in a different location
and be apart of a sub array, reading the styling context each time
a host binding is evaluated is costly. This patch ensures that the
active styling context is cached so that multiple interactions with
styling bindings can easily retrieve the styling context efficiently.
PR Close#29818
Plural ICU expressions depend on the locale (different languages have different plural forms). Until now the locale was hard coded as `en-US`.
For compatibility reasons, if you use ivy with AOT and bootstrap your app with `bootstrapModule` then the `LOCALE_ID` token will be set automatically for ivy, which is then used to get the correct plural form.
If you use JIT, you need to define the `LOCALE_ID` provider on the module that you bootstrap.
For `TestBed` you can use either `configureTestingModule` or `overrideProvider` to define that provider.
If you don't use the compat mode and start your app with `renderComponent` you need to call `ɵsetLocaleId` manually to define the `LOCALE_ID` before bootstrap. We expect this to change once we start adding the new i18n APIs, so don't rely on this function (there's a reason why it's a private export).
PR Close#29249
Prior to this change, element attributes annotated with i18n- prefix were removed from element attribute list and processed separately by i18n-specific logic. This behavior is causing issues with directive matching, since attributes are not present in the list of attrs for matching purposes. This commit updates i18n logic to retain attributes in the main attribute list, thus allowing directive matching logic to work correctly.
PR Close#29856
In order to be backwards compatible with View Engine, Ivy should log
errors by default in the TestBed error handler rather than re-throwing
them. Re-throwing the errors is a breaking change that causes issues with
libraries like ngrx that have async behavior and custom error handling.
This logging approach has issues (for both VE and Ivy) because it can allow
tests to pass inappropriately if errors are thrown inside listeners. However,
since re-throwing would be breaking and requires a larger redesign, we should
wait until post-Ivy.
PR Close#29853
The `Δ` caused issue with other infrastructure, and we are temporarily
changing it to `ɵɵ`.
This commit also patches ts_api_guardian_test and AIO to understand `ɵɵ`.
PR Close#29850
So far using runtime i18n with ivy meant that you needed to use Closure and `goog.getMsg` (or a polyfill). This PR changes the compiler to output both closure & non-closure code, while the unused option will be tree-shaken by minifiers.
This means that if you use the Angular CLI with ivy and load a translations file, you can use i18n and the application will not throw at runtime.
For now it will not translate your application, but at least you can try ivy without having to remove all of your i18n code and configuration.
PR Close#28689
Currently in Ivy we pass both the raw and parsed selectors to the projectionDef instruction, because the parsed selectors are used to match most nodes, whereas the raw ones are used to match against nodes with the ngProjectAs attribute. The raw selectors add a fair bit of code that won't be used in most cases, because ngProjectAs is somewhat rare.
These changes rework the compiler not to output the raw selectors in the projectionDef, but to parse the selector in ngProjectAs and to store it on the TAttributes. The logic for matching has also been changed so that it matches the pre-parsed ngProjectAs selector against the list of projection selectors.
PR Close#29578
- Adds the instructions
- Adds tests for all instructions
- Adds TODO to remove all tests when we are able to test this with TestBed after the compiler is updated
PR Close#29576
Fixes the creation mode block not being run on components which have been detached from change detection.
This PR resolves FW-1217.
Fixes#29645.
PR Close#29741
Fixes Ivy not throwing an error if it runs into an invalid property binding on a container node (e.g. `<div *ngFor="let row of rows">` instead of `<div *ngFor="let row if rows">`).
This PR resolves FW-1219.
PR Close#29691
The new styling algorithm in angular is designed to evaluate host
bindings stylinh priority in order of directive evaluation order. This,
however, does not work with respect to parent/sub-class directives
because sub-class host bindings are run after the parent host bindings
but still have priority. This patch ensures that the host styling bindings
for parent and sub-class components/directives are executed with respect
to the styling algorithm prioritization.
Jira Issue: FW-1132
PR Close#29602
Prior to this change, any provider that was independently resolved using
its InjectableDef would not be considered when destroying the module it
was requested from. This commit provides a fix for this issue by storing
the resolved provider in the module's list of provider definitions.
Fixes#28927
PR Close#28943
Simply adds a `debug` property to the array of create opcodes while inside
`readCreateOpCodes` in i18n. This `debug` property has a property called `operations`
that is a human-readable list of operations that will be performed, as derived
from the op codes themselves, and the view it's acting upon.
PR Close#29348
- moves all publicly exported instructions to their own files
- refactors namespace instructions to set state in `state.ts`
- no longer exports * from `instructions.ts`.
- `instructions.ts` renamed to `shared.ts` (old `shared.ts` contents folded in to `instructions.ts`)
- updates `all.ts` to re-export from public instruction files.
PR Close#29646
- Adds `property` instruction
- Does _NOT_ add compiler changes to accommodate `property` instruction, that will be a follow up PR.
- Updates `select` instruction to set the selected index in state.
- Adds dev mode assertions around the selected index state.
Related #29527
PR Close#29513
When an @NgModule is imported more than once in the testing module (for
example it appears in the imports of more than one module, or if it's
literally listed multiple times), then TestBed had a bug where the
providers for the module would be overridden many times.
This alone was problematic but would not break tests. However, the original
value of the providers field of the ngInjectorDef was saved each time, and
restored in the same order. Thus, if the provider array was [X], and
overrides were applied twice, then the override array would become
[X, X'] and then [X, X', X, X']. However, on the second override the state
[X, X'] would be stored as original. The array would then be restored to
[X] and then [X, X'].
Each test, therefore, would continue to double the size of the providers
array for the module, eventually exhausting the browser's memory.
This commit adds a Set to track when overrides have been applied to a module
and refrain from applying them more than once.
PR Close#29571
Prior to this change, recompilation of AOT-compiled components in TestBed may fail when template override is requested. That was happening due to the `styleUrls` field defined for a Component, thus switching its state to "requires resolution" (i.e. having external resources) at compile time. This change avoids this issue by storing styles and resetting `styleUrls` field before recompilation. Once compilation is done, saved styles are patched back onto Component def.
PR Close#29555
- Adds `property` instruction
- Does _NOT_ add compiler changes to accommodate `property` instruction, that will be a follow up PR.
- Updates `select` instruction to set the selected index in state.
- Adds dev mode assertions around the selected index state.
Related #29527
PR Close#29513
This commit removes code duplication where we had 2 versions of a
`flatten` utility. Moreover this change results in queries using
a non-recursive version of `flatten` which should result in a better
performance of query refresh operations.
PR Close#29547
Prior to this change, Ivy version of TestBed was not designed to support the logic to avoid recompilations - most of the Components/Directives/Pipes were recompiled for each test, even if there were no overrides defined for a given Type. Additional checks to avoid recompilation were introduced in one of the previous commits (0244a2433e), but there were still some corner cases that required attention. In order to support the necessary logic better, Ivy TestBed was rewritten/refactored. Main results of this rewrite are:
* no recompilation for Components/Directives/Pipes without overrides
* the logic to restore state between tests (isolate tests) was improved
* transitive scopes calculation no longer performs recompilation (it works with compiled defs)
As a result of these changes we see reduction in memory consumption (3.5-4x improvement) and pefromance increase (4-4.5x improvement).
PR Close#29483
The API changes are due to enabling strict checks in TypeScript (via `strict: true`).
The payload size changes in `polyfills.js` are due to more browser APIs being patched in recent versions (e.g. `fetch`, `customElement v1`).
PR Close#28219
In View Engine, we used to generate empty QueryLists for content queries on root
components (though we did not actually support populating these lists). We need
to keep this behavior in Ivy for backwards compatibility. Otherwise, components
that are sometimes used as root will fail if they are relying on content query
results to always be defined.
PR Close#29514
In some cases ivy expects projectable nodes to be passed in a different order
to ViewEngine. Specifically, ivy expects the catch-all ("*") to be at index
0, whereas ViewEngine expects it to be at its position at which it was parsed
in the template.
This commit adds one test that breaks under ivy and others that just describe
more accurately what happens in corner cases.
PR Close#27791
This patch is the first of a few patches which separates the
styling logic between template bindings (e.g. <div [style])
from host bindings (e.g. @HostBinding('style')). This patch
in particular introduces a series of host-specific styling
instructions and changes the existing set of template styling
instructions not to accept directives. The underyling code (which
communicates with the styling algorithm) still works as it did
before.
This PR also separates the styling instruction code into a separate
file and moves over all other instructions into an dedicated
instructions directory.
PR Close#29292
Prior to this change, we always recompile all Components/Directives/Pipes even if they were AOT-compiled and had no overrides. This is causing problems in case we try to recompile a Component with "templateUrl" or "styleUrls" (which were already resolved in case of AOT) and generally this unnecessary work that TestBed was doing is not required. This commit adds extra logic to check whether a Component/Directive/Pipe already have compiled NG def (like ngComponentDef) and whether there are no overrides present - in this case recompilation is skipped. Recompilation is also skipped in case a Component/Directive has only Provider overrides - in this situation providers resolver function is patched to reflect overrides. Provider overrides are very common in g3, thus this code path ensures no full recompilation.
PR Close#29294
Just updating comments in query-related things to make it easier for the next person that has to grok this for the first time.
Also adds a demo from @mhevery to one of the query specs
Related #29031
PR Close#29342
Just updating comments in query-related things to make it easier for the next person that has to grok this for the first time.
Also adds a demo from @mhevery to one of the query specs
Related #29031
PR Close#29342
Fixes host listeners being inherited twice, if the sub class has its own `propMetadata`. This is related to #29170 which fixed something similar, however all of the test cases there had a super class with some metadata and a sub class that didn't have any. The issue manifested itself in the `MatTreeToggle` which inherits a listener from the `CdkTreeToggle` and adds an extra `Input` of its own, causing the listener to be added twice.
PR Close#29353
Angular Ivy interprets inline static style/class attribute values as instructions that
are processed whilst an element gets created. Because these inline style values are
referenced by style/class bindings, their inline style values are applied at a later
stage. Despite them being eventually applied, their values should be applied earlier
before any directives are instantiated so that directive code can rely on any inline
style/class changes.
This patch ensures that all static style/class attribute values are applied (rendered)
on the element before directives are instantiated.
Jira Issue: FW-1133
PR Close#29269
Following my previous change for placeholders removal, some special code that was used to find the last created node was no longer needed and had wrong interactions with the *ngFor directive.
Removing it fixed the issue.
PR Close#29308
When injecting with `@Attribute`, namespaced attributes should not match (in order to have feature parity with View Engine).
This PR resolves FW-1137
PR Close#29257
BREAKING CHANGE:
Certain elements (like `<tr>` or `<col>`) require parent elements to be of a certain type by the HTML specification
(ex. <tr> can only be inside <tbody> / <thead>). Before this change Angular template parser was auto-correcting
"invalid" HTML using the following rules:
- `<tr>` would be wrapped in `<tbody>` if not inside `<tbody>`, `<tfoot>` or `<thead>`;
- `<col>` would be wrapped in `<colgroup>` if not inside `<colgroup>`.
This meachanism of automatic wrapping / auto-correcting was problematic for several reasons:
- it is non-obvious and arbitrary (ex. there are more HTML elements that has rules for parent type);
- it is incorrect for cases where `<tr>` / `<col>` are at the root of a component's content, ex.:
```html
<projecting-tr-inside-tbody>
<tr>...</tr>
</projecting-tr-inside-tbody>
```
In the above example the `<projecting-tr-inside-tbody>` component culd be "surprised" to see additional
`<tbody>` elements inserted by Angular HTML parser.
PR Close#29219
Previously, ngtsc would resolve forward references while evaluating the
bootstrap, declaration, imports, and exports fields of NgModule types.
However, when generating the resulting ngModuleDef, the forward nature of
these references was not taken into consideration, and so the generated JS
code would incorrectly reference types not yet declared.
This commit fixes this issue by introducing function closures in the
NgModuleDef type, similarly to how NgComponentDef uses them for forward
declarations of its directives and pipes arrays. ngtsc will then generate
closures when required, and the runtime will unwrap them if present.
PR Close#29198
Prior to this change default selector for Components was not applied in case selector is missing or defined as an empty string. This update aligns this behavior between Ivy and VE: now default selector is used for Components when it's needed. Directives with empty selector are not allowed and trigger a compile-time error in both Ivy and VE.
PR Close#29239
Currently with ViewEngine, if someone runs the platform's
`bootstrapModule` method in order to boostrap a module in
JIT mode, external component resources are properly resolved
*automatically*.
Currently with Ivy, the developer would need to manually call
`resolveComponentResources` in order to asynchronously fetch
the determined external component resources. In order to make
this backwards compatible with ViewEngine, and also since
platforms can already specify a `ResourceLoader` compiler
provider, we need to automatically resolve all external
component resources on module bootstrap.
--
Since the `ResourceLoader` is part of the `@angular/compiler`,
because ViewEngine performed the factory creation in the compiler,
we can't access the `ResourceLoader` token from within core.
In order to workaround this without introducing a breaking change,
we just proxy the `ResourceLoader` token to `core` through the
compiler facade. In the future, we should be able to move the
`ResourceLoader` to core when ViewEngine code no longer exists in
the `@angular/compiler`.
PR Close#29083
Dynamic nodes are created at the end of the view stack, but we were removing all the placeholders between `i18nStart` and the last created node index, instead of removing everything between `i18nStart` and `i18nEnd`. This caused errors when dynamic nodes where created in multiple i18n blocks because we would remove all of the dynamic nodes created in the previous i18n blocks.
PR Close#29252
Prior to this commit, i18n instructions (i18n, i18nStart) were generated before listener instructions. As a result, event listeners were attached to the wrong element (text node, not the parent element). This change updates the order of instructions and puts i18n ones after listeners, to make sure listeners are attached to the right elements.
PR Close#29173
The content projection mechanism is static, in that it only looks at the static
template nodes before directives are matched and change detection is run.
When you have a selector-based content projection the selection is based
on nodes that are available in the template.
For example:
```
<ng-content selector="[some-attr]"></ng-content>
```
would match
```
<div some-attr="..."></div>
```
If you have an inline-template in your projected nodes. For example:
```
<div *ngIf="..." some-attr="..."></div>
```
This gets pre-parsed and converted to a canonical form.
For example:
```
<ng-template [ngIf]="...">
<div some-attr=".."></div>
</ng-template>
```
Note that only structural attributes (e.g. `*ngIf`) stay with the `<ng-template>`
node. The other attributes move to the contained element inside the template.
When this happens in ivy, the ng-template content is removed
from the component template function and is compiled into its own
template function. But this means that the information about the
attributes that were on the content are lost and the projection
selection mechanism is unable to match the original
`<div *ngIf="..." some-attr>`.
This commit adds support for this in ivy. Attributes are separated into three
groups (Bindings, Templates and "other"). For inline-templates the Bindings
and "other" types are hoisted back from the contained node to the `template()`
instruction, so that they can be used in content projection matching.
PR Close#29041
This commit adds a new `AttributeMarker` type that will be used, in a
future commit, to mark attributes as coming from an inline-template
expansion, rather than the element that is being contained in the template.
PR Close#29041
Some tests in exports spec rely on the exact output of innerHTML. In IE11 the order of attributes might change, thus causing tests to fail (in case an element contains more than one attribute). This commit avoids innerHTML usage and performs the necessary checks via element properties.
PR Close#29127
Some of the export tests had assertions that relied on capitalization
of attributes in the DOM. IE treats capitalization somewhat differently,
so our SauceLabs tests were failing.
This commit tweaks the tests so that the assertions do not rely on
attributes to be capitalized or not.
PR Close#29125
Angular supports having a component extend off of a parent component.
When this happens, all annotation-level data is inherited including styles
and classes. Up until now, Ivy only paid attention to static styling
values on the parent component and not the child component. This patch
ensures that both the parent's component and child component's styling
data is merged and rendered accordingly.
Jira Issue: FW-1081
PR Close#29015
Currently we only reset the `Attached` flag of a view if it is detached through its parent, however this means that if a root view is destroyed, its flag will never be reset. This manifested itself in one of the Material tests where we were destroying the root view.
This PR resolves FW-1130.
PR Close#29064
Currently if a user accidentally calls ViewContainerRef.insert() with
a view that has already been attached, we do not clean up the references
properly, so we create a view tree with a cycle. This causes an infinite
loop when the view is destroyed.
This PR ensures that we fall back to ViewContainerRef.move() behavior
if we try to insert a view that is already attached. This fixes the
cycle and honors the user intention.
PR Close#29047