To further modernize and improve the performance of the i18n digest generation,
The 64-bit aspects of the process now use the native `BigInt` instead of a
custom JavaScript implementation. This removes the need for the big_integer
helper code and associated tests as the code was not used anywhere else in the
framework. Only the `BigInt` constructor, `BigInt.asUintN` function, and
`.toString` function are currently used. `BigInt` literals can unfortunately
not yet be used due to the bazel test devmode setup which compiles the TypeScript
code at an EcmaScript level that does not yet support the literals.
Browser support information:
- BigInt constructor: https://caniuse.com/mdn-javascript_builtins_bigint_bigint
- BigInt asUintN: https://caniuse.com/mdn-javascript_builtins_bigint_asuintn
- BigInt toString: https://caniuse.com/mdn-javascript_builtins_bigint_tostring
PR Close#48321
Reworks the pure functions to use arrow functions with an implicit return instead of function expressions. This allows us to shave off some bytes for each pure function, because we can avoid some of the syntax.
PR Close#51668
These changes build on top of #51514 to add support for advanced expressions inside the `track` parameter of `for` loop blocks. There are two different outputs that the compiler can generate:
1. If the tracking function only references the item or `$index`, the compiler generates a pure arrow function as a constant references in the `repeaterCreate` instruction.
2. If the tracking function has references to properties outside of the `for` loop block, the compiler will rewrite those references to go through `this` and generate a function declaration. The runtime will `bind` the declaration to the current component instance so that the rewritten `this` references are resolved correctly.
Advanced tracking expression come with the following limitations to ensure the best possible performance:
1. They can only reference the item, `$index` and properties directly on the component instance. This means that there'll be an error when accessing this like local template variables and references. While we could get this to work, we would have to traverse the context tree at runtime which will degrade the performance of the loop, because it's a linear time operation that is performed on each comparison. Furthermore, allowing local references would require us re-evaluate the list when any one of them has changed.
2. Pipes aren't allowed inside the tracking function.
3. Object literals and pipes used inside the tracking expression will be recreated on each invocation.
PR Close#51618
Adds an instruction that allows us to access the containing component instance directly instead of having to traverse the context tree. This will be necessary for the tracking function of `for` loop blocks.
PR Close#51618
When `preserveWhitespaces` is enabled, `switch` blocks can end up with content inside their main block due to the indentation that is usually used for the nested cases. This was tripping up the validation that doesn't allow content inside the main block of `switch`.
These changes update the validation to ignore empty text nodes.
PR Close#51570
With the new control flow and defer blocks it'll be common for several template instructions to be declare one after another. These changes add support for chaining to the `template` instruction which will allow us to save some bytes.
PR Close#51546
Adds the initial implementation to generate the instructions for the `for` loop block.
**Note:** the expressions we support in the `track` paramateter are currently limited to tracking by identity or index, or a specific property of the item. Supporting more advanced expression will require additional work that I'll do in a follow-up PR.
PR Close#51514
`switch` blocks are part of the new control flow syntax. This commit adds support for processing them, and emitting the appropriate templates and conditional instructions.
PR Close#51518
Component compilation and host binding compilation previously used separate compilation emit functions. This was a bit messy, because we had to manage the relative orders of both phase lists. Indeed, there was already some inconsistency between the precise orders!
This commit refactors the emit functions to share the same phase list, and thus guarantees they will always be in the same order.
PR Close#51498
`syntheticHostListener` and `listener` have ordering dependencies. We reuse the existing ordering phase, and generalize it to also order create mode instructions.
PR Close#51498
Animation listeners on host bindings result in a special `syntheticHostListener` instruction. We can now emit this instruction.
Additionally, the naming phase for events has been slightly refactored to smoothly incorporate whether the event is from a host listener, as well as whether it is an animation listener.
PR Close#51498
For host bindings, `TemplateDefinitionBuilder` seems to use a different binding ordering, in which style bindings come after all the property bindings. We approximate that by treating `hostProperty` differently from `property` in the ordering phase.
PR Close#51498
The template pipeline is already capable of parsing and processing class and style attributes on templates. We now extend that functionality to host bindings.
The parser, for some reason, splits out class and style attributes into a `specialAttributes` field. We merge them back into the main attributes map, and allow the template pipeline to process them normally.
PR Close#51498
TemplateDefinitionBuilder only extracts host attributes if they are text attributes. For example, `[attr.foo]="'my-value'"` is not extracted despite being a string literal, because it is not a text attribute.
PR Close#51498
Host property bindings can be animation bindings, and should be ingested and emitted as such, as well as being processed by the renaming phase.
PR Close#51498
Host bindings can apply static attributes. These will be extracted to a `hostAttrs` field on the host binding function's metadata.
In order to achieve this, we add an `attributes` field to the host binding job. Then, we peform attribute exraction on host bindings. We finally populate the `attributes` field directly, instead of relying on a `consts` array.
PR Close#51498
Convert `CompilationJob` into a abstract class in order to extract common code. Separate host binding jobs and units, in order to allow for more code sharing.
PR Close#51498
Adds a new phase to resolve element placeholders in i18n messages.
This requires adding the i18n message to element ops, which means the
creation of i18n start/end ops can now be done in a separate phase
instead of during ingestion.
PR Close#51353
Creates a new `ExtractedMessageOp` which is consumed by the const
collection pahse to serialize the i18n message into the consts array.
Also adds support to the consts array for initialization statements.
PR Close#51353
Adds i18n block start & end ops, as well as a new phase to construct the
i18n message variable to be added to the consts array.
Co-authored-by: Alex Rickabaugh <alx+alxhub@alxandria.net>
Co-authored-by: Dylan Hunn <dylhunn@gmail.com>
PR Close#51353
This commit adds an initial implementation of the `{#defer}` block runtime, which supports the `when` conditions. More conditions and basic prefetching support will be added in followup PRs.
PR Close#51347
Extends the compiler to add support for generating arrow functions in the output AST. This will be required for the `for` control flow block and we can potentially leverage it in other places to reduces the amount of generated code.
PR Close#51436
Adds the logic to generate the instructions for `if` blocks. There are two primary use cases we need to account for:
A conditional that doesn't use the `as` parameter of the `if` block. To support it we generate a nested ternary expression that evaluates to the index of the template whose condition is truthy. If the block doesn't have an `else` branch, we pass in a special `-1` value which means that no view will be rendered.
Example with an `else`:
```ts
// {#if expr}
// ...
// {:else if otherExpr} ...
// {:else} ...
// {/if}
if (rf & 1) {
ɵɵtemplate(0, App_Conditional_0_Template, 0, 0);
ɵɵtemplate(1, App_Conditional_1_Template, 0, 0);
ɵɵtemplate(2, App_Conditional_2_Template, 0, 0);
}
if (rf & 2) {
ɵɵconditional(0, ctx.expr ? 0 : ctx.otherExpr ? 1 : 2);
}
```
Example without an `else`:
```ts
// {#if expr}
// ...
// {:else if otherExpr} ...
// {/if}
if (rf & 1) {
ɵɵtemplate(0, App_Conditional_0_Template, 0, 0);
ɵɵtemplate(1, App_Conditional_1_Template, 0, 0);
}
if (rf & 2) {
ɵɵconditional(0, ctx.expr ? 0 : ctx.otherExpr ? 1 : -1);
}
```
If a conditional captures it's value in an alias (e.g. `{#if expr; as foo}`) we need to assign the value to a temporary variable before passing it along to `conditional`.
```ts
// {#if expr; as alias}...{/if}
if (rf & 1) {
ɵɵtemplate(0, App_Conditional_0_Template, 1, 0);
}
if (rf & 2) {
let App_contFlowTmp;
ɵɵconditional(0, (App_contFlowTmp = ctx.expr) ? 0 : -1, App_contFlowTmp);
}
```
PR Close#51380
Angular 16.1 introduced the input transform feature, requiring the partial compilation output to be extended
with a reference to the input transform function. This has resulted in a subtle breaking change, where older
versions of the Angular linker can no longer consume libraries that have started to use this feature.
We do try to support using a 16.1 library from an Angular 16.0 application, but if a library actually
adopts a new feature then this is no longer possible. In such cases, it is desirable to report a message
telling the user that their version of the Angular compiler is too old, as determined by the `"minVersion"`
property that is present in each partial declaration. This version would still indicate that the declaration
required at least Angular 14.0 to be compiled, but this is not accurate once input transforms are being
used. Consequently, this error would not be reported, causing a less informative error once the input transform
was being observed.
Fixes#51411
PR Close#51413
This commit updates TestBed to wait for async component metadata resolution before compiling components.
Async metadata is added by the compiler in case a component uses defer blocks, which contain deferrable
symbols.
PR Close#51182
This commit updates compiler logic to generate the `setClassMetadataAsync` calls for components that used defer blocks. The `setClassMetadataAsync` function loads deferrable dependencies and invokes the `setClassMetadata` synchronously once everything is loaded. This change is needed to avoid eager references to deferrable symbols in component metadata in generated code.
PR Close#51182
Fixes that we weren't processing `when` conditions correctly which led to a compilation error when a pipe is used inside the expression.
PR Close#51368
A factory generator function called "i0.ɵɵgetComponentDepsFactory" is added to generate a factory function for component dependencies. This function will use the deps tracker to calculate the component's dependencies.
For standalone components the component imports (if exists) will be passed to this function. Alternatively this function can grab the imports directly from the decorate, but such extraaction needs some runtime logic which overlapps with what the trait compiler is doing. So better to pass the imports directly to this function at compile time.
PR Close#51089
Fixes that if a directive/pipe is used after a nested `defer` block, we weren't tracking it as lazy anymore. This was due to the fact that we were resetting the `isInDeferBlock` to false every time instead of the previous value.
PR Close#51262
Adds validations for the following invalid deferred block structures:
* Duplicated triggers.
* Multiple `minimum` parameters on `placeholder` and `loading` blocks.
* Multiple `after` parameters on `loading` blocks.
PR Close#51262
Stores the `deferred` block triggers as a map instead of an array, because triggers can't be duplicated and because having to search through an array will be inconvenient later on.
I've also added a `DeferredBlock.visitAll` method to deduplicate the logic from the various visitor implementations.
PR Close#51262