Enables the new `@let` syntax by default.
`@let` declarations are defined as:
1. The `@let` keyword.
2. Followed by one or more whitespaces.
3. Followed by a valid JavaScript name and zero or more whitespaces.
4. Followed by the `=` symbol and zero or more whitespaces.
5. Followed by an Angular expression which can be multi-line.
6. Terminated by the `;` symbol.
Example usage:
```
@let user = user$ | async;
@let greeting = user ? 'Hello, ' + user.name : 'Loading';
<h1>{{greeting}}</h1>
```
Fixes#15280.
PR Close#56715
These changes integrate let declarations into the template pipeline. This involves a few operations:
* Producing a `declareLet` instruction call at creation time to initialize the declaration.
* Producing a `storeLet` instruction call in the place of the let declaration, including the necessary `advance` calls beforehand.
* For let declarations used within their declaration view, moving the `const` to be placed right after the `storeLet` call to ensure the their value has been computed.
* For let declarations that are _only_ used in their declaration view, removing the `storeLet` call and inlining the expression into the constant statement.
PR Close#56299
Builds on top of the previous changes to add support for deferred blocks during partial compilation. To do this, the following changes had to be made:
* The metadata passed into `ɵɵngDeclareComponent` has an additional field called `deferBlockDependencies` which has an array of the dependency loading functions for each defer block in the template. During linking, the dependency functions are loaded by matching their template index to the index in the `deferBlockDependencies` array.
* There's a new `ɵɵngDeclareClassMetadataAsync` function that is created for components that have deferred dependencies. It gets transpiled to `setClassMetadataAsync` and works in the same way by capturing a dependency loading function and setting the metadata after the dependencies are resolved. It also has some extra fields for capturing the version which are standard in linker-generated code.
* Deferred import statements are now stripped in partial compilation mode, similar to full compilation.
PR Close#54908
Updates the type of the resolver function to be any `Expression` since JIT may receive a function reference rather than a `ArrowFunctionExpr`.
PR Close#54908
`ImportGenerator` is the abstraction used by the translator functions to
insert imports for `ExternalExpr` in an AST-agnostic way.
This was built specifically for the linker which does not use any of the
complex import managers- but rather re-uses `ngImport` or uses
`ngImport.Bla`.
This commit also switches the linker AST-agnostic generator to follow
the new signatures. This was rather trivial.
PR Close#54819
Moves the logic that creates the defer resolver function into `@angular/compiler` for consistency with the rest of the compilation APIs. Also renames some of the symbols to make it clearer what they're used for.
PR Close#54759
Currently we have the `deferrableDeclToImportDecl`, `deferBlocks`, `deferrableTypes` and `deferBlockDepsEmitMode` fields on the `R3ComponentMetadata` which is incorrect, because the interface is used both for JIT and AOT mode even though the information for those fields is AOT-specific. It will be problematic for partial compilation since the runtime will have a reference to the dependency loading function, but will not be able to provide any of the other information.
These changes make the following refactors:
1. It changes the defer-related information in `R3ComponentMetadata` to include only references to dependency functions which can be provided both in JIT and AOT.
2. Moves the AOT-specific defer analysis into the `ComponentResolutionData`.
3. Moves the construction the defer dependency function into the compilation phase of the `ComponentDecoratorHandler`.
4. Drops support for defer blocks from the `TemplateDefinitionBuilder`. This allows us to clean up some TDB-specific code and shouldn't have an effect on users since the TDB isn't used anymore.
PR Close#54759
`TemplateDefinitionBuilder` is the legacy template compiler, and was replaced by Template Pipeline as the default in v17.3.
This PR attempts to delete `TemplateDefinitionBuilder`, `ExpressionConverter`, and various helpers (i18n context, style builder, property visitors, etc).
Consider this a first pass: a lot of code has not yet been deleted (e.g. old TDB-specific test cases), and I'm sure I have missed additional helper code.
PR Close#54757
Currently we have the `deferrableDeclToImportDecl`, `deferBlocks`, `deferrableTypes` and `deferBlockDepsEmitMode` fields on the `R3ComponentMetadata` which is incorrect, because the interface is used both for JIT and AOT mode even though the information for those fields is AOT-specific. It will be problematic for partial compilation since the runtime will have a reference to the dependency loading function, but will not be able to provide any of the other information.
These changes make the following refactors:
1. It changes the defer-related information in `R3ComponentMetadata` to include only references to dependency functions which can be provided both in JIT and AOT.
2. Moves the AOT-specific defer analysis into the `ComponentResolutionData`.
3. Moves the construction the defer dependency function into the compilation phase of the `ComponentDecoratorHandler`.
4. Drops support for defer blocks from the `TemplateDefinitionBuilder`. This allows us to clean up some TDB-specific code and shouldn't have an effect on users since the TDB isn't used anymore.
PR Close#54700
Template pipeline is now the default template compiler.
A pair of source map tests is failing, related to DI in JIT mode; I will fix and re-enable these during the preview period.
PR Close#54571
When the linker is running using an unpublished version of angular, locally built, the version will be `0.0.0`.
When encountering this situation, the range that for the linker map support is considered to be `*.*.*` allowing
for the linker to work at build time with packages built with versioned angular.
Most notably this allows for us to properly use the linker in building our documentation site with the locally
built version of angular.
PR Close#54439
The Template Pipeline is a brand new backend for the Angular compiler, replacing `TemplateDefinitionBuilder`. It generates the Ivy instructions corresponding to an input template (or host binding). The Template Pipeline has an all-new design based on an intermediate representation compiled over many phases, which will allow us to experiment with compiler changes more easily in the future.
With this commit, the template pipeline can now be enabled in any project via the `useTemplatePipeline` TSConfig option. However, it is still disabled by default.
PR Close#54057
This commit ensures that libraries can use signal-based queries, and the
partial compilation output will capture their metadata.
The linker is updated to support parsing this.
Two notes:
1. Older linker versions are not capable of parsing this, so the minimum
version for signal-based queries is adjusted when such are used.
2. We only emit `isSignal` metadata for queries when signal queries are
used. This enables libraries to continue supporting older linker
versions, if signal-based queries are not used.
PR Close#53978
This commit adds extra logic to produce a diagnostic in case `@Component.deferredImports` contain types from imports that also bring eager symbols. This would result in retaining a regular import and generating a dynamic import, which would not allow to defer-load dependencies.
PR Close#53899
As we introduced the new partial output for signal inputs, we also need
to update the linker code to be able to parse this. This commit adds
this functionality.
In the follow-up commit, compliance tests for linking, partial output,
and full compilations are added.
PR Close#53808
The linker AST is abstracted to be agnostic of the underlying
implementation AST. i.e. TS AST or Babel AST.
This abstraction also intends to provide some type-safety-ness to
parsing of various partial declarations. This commit improves type
safety further by fixing that `AstValue'`s were not checked for
assignability of `T`- potentially hiding issues/unaccounted values.
Additionally, we fix that `getObject()` does not properly narrow
union types to actual object literals. This happend because e.g. arrays
are of type `object`. We can improve type safety here. Using `Record`
did not help as an array would still assign to that.
PR Close#53808
This commit captures the metadata on whether an input is signal based or
not, in the `.d.ts` of directives and components. This exposes this
information to consumers of the directives. This is needed because
libraries may use signal inputs, and we need to know whether bound
inputs to this library are signal-based or not- so that we can generate
proper type-checking code (account for `InputSignal` or not).
Additionally, this commit introduces a new structure for the partial
compilation output of directive inputs. With the current emit, inputs
are captured in a data structure that is equivalent to the internal data
structure passed to `defineDirective` (the full compilation output).
This worked fine as we only captured a few strings, but in ends up
being a bad practice because partial compilation output should NOT
capture internal data structures that might be specific to a certian
Angular core version. Instead, we introduce a new "future proof"
structure that:
- can hold additional metadata in backwards-compatible ways, like
`isSignal` or `isRequired`.
- can be parsed trivially using the `AstHost` for the linker, instead of
having to unwrap/parse an array structure.
The new structure is only emitted when we discover that some inputs are
signal based (or ultimately end up configuring input flags). This is
done for backwards compatibility, so that libraries without signal
inputs remain compatible with older linker versions. In the future,
this might be the only emit.
Compliance tests for this follow in future commits, when the linker
portion is also in place. This commit specialices on the code
generation. With the linker, and compliance test infrastructure fixed
(that is broken right now), we can test the full integration.
PR Close#53521
Enables the new `@` block syntax by default by removing the `enabledBlockTypes` flags. There are still some internal flags that allow special use cases to opt out of the block syntax, like during XML parsing and when compiling older libraries (see #51979).
PR Close#51994
Adds some logic to enable parsing of block syntax in the linker. Note that the syntax is only enabled on code compiled with Angular v17 or later.
PR Close#51979
Reworks the compiler to use the API introduced in #51816 to match triggers to the element nodes they point to. This will be used to generate the new instructions for `on interaction` and `prefetch on interaction`.
PR Close#51830
This commit brings the logic to calculate teh set of dependencies for each defer block. For each dependency we also identify whether it can be defer-loaded or not.
PR Close#51162
The new interface is discrete-unioned with the existing interface to cover the cases for local and global (i.e., full and partial) compilation modes.
This change of interface required some adjustmeents cross repo which explains the changes made to other files.
PR Close#50577
Adds the necessary compiler changes to support input transform functions. The compiler output has changed in the following ways:
### Directive handler
The directive handler now extracts a reference to the input transform function and it resolves the type of its first parameter. It also asserts that the type can be referenced in the compiled output and that it doesn't clash with any pre-existing `ngAcceptInputType_` members.
### .d.ts
In the generated declaration files the compiler now inserts an `ngAcceptInputType_` member for each input with a `transform` function. The member's type corresponds to the type of the first parameter of the function, e.g.
```typescript
// foo.directive.ts
@Directive()
export class Foo {
@Input({transform: (incomingValue: string) => parseInt(incomingValue)}) value: number;
}
// foo.directive.d.ts
export class Foo {
value: number;
static ngAcceptInputType_value: string;
}
```
### Type check block
If an input has `transform` function, the TCB will use the type of its first parameter for the setter type. This uses the same infrastructure as the `ngAcceptInputType_` members.
### Directive declaration
The generated runtime directive declaration call now includes the `transform` function in the `inputs` map, if the input is being transformed. The function will be picked up by the runtime in the next commit to do the actual transformation.
```typescript
// foo.directive.ts
@Directive()
export class Foo {
@Input({transform: (incomingValue: string) => parseInt(incomingValue)}) value: number;
}
// foo.directive.js
export class Foo {
ɵdir = ɵɵdefineDirective({
inputs: {
value: ['value', 'value', incomingValue => parseInt(incomingValue)]
}
});
}
```
PR Close#50225
This commit adds the `signals: boolean` property to the internal
directive/component metadata. This does not add it to the public API
yet, as the feature has no internal support other than compiler
detection.
PR Close#49981
The concept of "internal" and "adjacent" type expression used to be necessary to support
ngcc, as it had to process downleveled class declarations using an IIFE, where the class
name within the IIFE could be different from the outer class name. With the removal of
ngcc we no longer need to make this distinction, so this commit removes these concepts
entirely.
PR Close#49136
Adds support for marking a directive input as required. During template type checking, the compiler will verify that all required inputs have been specified and will raise a diagnostic if one or more are missing. Some specifics:
* Inputs are marked as required by passing an object literal with a `required: true` property to the `Input` decorator or into the `inputs` array.
* Required inputs imply that the directive can't work without them. This is why there's a new check that enforces that all required inputs of a host directive are exposed on the host.
* Required input diagnostics are reported through the `OutOfBandDiagnosticRecorder`, rather than generating a new structure in the TCB, because it allows us to provide a better error message.
* Currently required inputs are only supported during AOT compilation, because knowing which bindings are present during JIT can be tricky and may lead to increased bundle sizes.
Fixes#37706.
PR Close#49468
This reverts commit 13dd614cd1.
This breaks a g3 Typescript compilation tests where diagnostics are
expected for a missing input in the component.
PR Close#49467
Adds support for marking a directive input as required. During template type checking, the compiler will verify that all required inputs have been specified and will raise a diagnostic if one or more are missing. Some specifics:
* Inputs are marked as required by passing an object literal with a `required: true` property to the `Input` decorator or into the `inputs` array.
* Required inputs imply that the directive can't work without them. This is why there's a new check that enforces that all required inputs of a host directive are exposed on the host.
* Required input diagnostics are reported through the `OutOfBandDiagnosticRecorder`, rather than generating a new structure in the TCB, because it allows us to provide a better error message.
* Currently required inputs are only supported during AOT compilation, because knowing which bindings are present during JIT can be tricky and may lead to increased bundle sizes.
Fixes#37706.
PR Close#49453
This reverts commit 1a6ca68154.
This breaks tests in google3 which might be depending on private APIs. We
need to update these tests before we can land this PR.
PR Close#49449
Adds support for marking a directive input as required. During template type checking, the compiler will verify that all required inputs have been specified and will raise a diagnostic if one or more are missing. Some specifics:
* Inputs are marked as required by passing an object literal with a `required: true` property to the `Input` decorator or into the `inputs` array.
* Required inputs imply that the directive can't work without them. This is why there's a new check that enforces that all required inputs of a host directive are exposed on the host.
* Required input diagnostics are reported through the `OutOfBandDiagnosticRecorder`, rather than generating a new structure in the TCB, because it allows us to provide a better error message.
* Currently required inputs are only supported during AOT compilation, because knowing which bindings are present during JIT can be tricky and may lead to increased bundle sizes.
Fixes#37706.
PR Close#49304
This is the compile-time implementation of the `hostDirectives` feature plus a little bit of runtime code to illustrate how the newly-generated code will plug into the runtime. It works by creating a call to the new `ɵɵHostDirectivesFeature` feature whenever a directive has a `hostDirectives` field. Afterwards `ɵɵHostDirectivesFeature` will patch a new function onto the directive definition that will be invoked during directive matching.
For example, if we take the following definition:
```ts
@Directive({
hostDirectives: [HostA, {directive: HostB, inputs: ['input: alias']}]
})
class MyDir {}
```
Will compile to:
```js
MyDir.ɵdir = ɵɵdefineComponent({
features: [ɵɵHostDirectivesFeature([HostA, {
directive: HostB,
inputs: {
input: "alias"
}
}])]
});
```
The template type checking is implemented during directive matching by adding the host directives applied on the host to the array of matched directives whenever the host is matched in a template.
Relates to #8785.
PR Close#46868
When generating .d.ts metadata for NgModules, by default we emit type
references to their declarations, imports, and exports. However, this
information is not necessarily useful to consumers. References to private
directives (those that aren't exported by the NgModule) for example aren't
at all useful as they can only affect other components declared in the
NgModule. References to imports are of limited usefulness - they might be
helpful for an IDE to understand the DI structure of an application, but
aren't at all used by a downstream compiler.
Generating this metadata is not without cost. When an incremental build
system uses changes in inputs to determine when a rebuild is necessary, any
changes in .d.ts files might cause downstream targets to rebuild. If those
.d.ts changes are in the "private" side of the NgModule (imports or non-
exported directives/pipes), then these rebuilds are wholly unnecessary.
This commit introduces the `onlyPublishPublicTypingsForNgModules` flag for
the compiler. When this flag is set, the compiler will filter the emitted
references in NgModule .d.ts output and only reference those directives/
pipes that are exported from the NgModule (its public API surface). Omitting
the flag preserves the existing behavior of emitting all references, both
public and private.
This is especially useful for build systems such as Bazel.
PR Close#45894
This commit expands on the unified dependency tracking in the previous
commit and adds tracking of NgModule dependencies. These are not used for
standard components, but are emitted for standalone components to allow the
runtime to roll up providers from those NgModules into standalone injectors.
PR Close#45672
Previously, the compiler would represent template dependencies of a
component in its component definition through separate fields (`directives`,
`pipes`).
This commit refactors the compiler/runtime interface to use a single field
(`dependencies`). The runtime component definition object still has separate
`directiveDefs` and `pipeDefs`, which are calculated from the `dependencies`
when the definition is evaluated.
This change is also reflected in partially compiled declarations. To ensure
compatibility with partially compiled code already on NPM, the linker
will still honor the old form of declaration (with separate fields).
PR Close#45672
When `@angular/compiler` processes metadata and compiles a definition field,
it might also choose to return statements that are associated with that
definition, and should be included after the type being compiled. Currently,
the linker ignores these statements, as there are none generated that are
relevant in the linking operation.
A challenge to supporting such associated statements is that the linker
operates on "declare" expressions, and replaces those expressions with other
expressions. It does not have the capability to append statements after the
whole type. The linker actually faces this challenge with statements from
the `ConstantPool` as well, and solves this problem by generating an IIFE
expression that executes the statements and then returns the definition
expression.
Previously, an `EmitScope` processed the definition and converted it to an
expression, as well as collected constant statements from a `ConstantPool`.
A special `IifeEmitScope` implementation was used when emitting into a
context where top-level constant statements couldn't be added at all, and
uses the IIFE strategy in this case.
This commit adds blanket support for associated statements to the linker
using this IIFE strategy. The main `EmitScope` now uses the IIFE strategy to
emit associated statements, and `IifeEmitScope` has been renamed to
`LocalEmitScope`. Now, the `LocalEmitScope` represents constant statements
as associated statements to the main `EmitScope` implementation, so they
get included in the IIFE as well.
Tests are adjusted/added to cover this new behavior. This is a refactoring
commit because no live generated code is affected - there are no cases where
associated statements are present in linked definitions today.
PR Close#45024
The `compileNgModule` operation previously supported a flag `emitInline`,
which controlled whether template scoping information for the NgModule was
emitted directly into the compiled NgModule definition, or whether an
associated statement was generated which patched the information onto the
NgModule definition. Both options are useful in different contexts.
This commit changes this flag to an enum (and renames it), which allows for
a third option - do not emit any template scoping information. This option
is added to better represent the actual behavior of the Angular Linker,
which sometimes configures `compileNgModule` to use the side-effectful
statement generation but which does not actually emit such associated
statements. In other words, the linker effectively does not generate
scoping information for NgModules at all (in some configurations) and this
option more directly expresses that behavior.
This is a refactoring as no generated code is changed as a result of
introducing this flag, due to the linker's behavior of not emitting
associated statements.
PR Close#45024
This commit implements the first phase of standalone components in the Angular
compiler. This mainly includes the scoping rules for standalone components
(`@Component({imports})`).
Significant functionality from the design is _not_ implemented by this PR,
including:
* imports of standalone components into NgModules.
* the provider aspect of standalone components
Future commits will address these issues, as we proceed with the design of
this feature.
PR Close#44812
This commit removes the View Engine runtime. Itself, this change is
relatively straightforward, but it represents the final step in a multi-year
journey. It's only possible due to the hard work of many current and former
team members and collaborators, who are too numerous to list here.
Co-authored-by: Alan Agius <alan.agius4@gmail.com>
Co-authored-by: Andrew Kushnir <akushnir@google.com>
Co-authored-by: Andrew Scott <atscott01@gmail.com>
Co-authored-by: Andrew Seguin <andrewjs@google.com>
Co-authored-by: Cédric Exbrayat <cedric@ninja-squad.com>
Co-authored-by: Charles Lyding <19598772+clydin@users.noreply.github.com>
Co-authored-by: Dave Shevitz <dshevitz@google.com>
Co-authored-by: Doug Parker <dgp1130@users.noreply.github.com>
Co-authored-by: Dylan Hunn <dylhunn@gmail.com>
Co-authored-by: Emma Twersky <emmatwersky@google.com>
Co-authored-by: George Kalpakas <kalpakas.g@gmail.com>
Co-authored-by: Igor Minar <iminar@google.com>
Co-authored-by: Jeremy Elbourn <jelbourn@google.com>
Co-authored-by: Jessica Janiuk <jessicajaniuk@google.com>
Co-authored-by: JiaLiPassion <JiaLi.Passion@gmail.com>
Co-authored-by: Joey Perrott <josephperrott@gmail.com>
Co-authored-by: Joost Koehoorn <joost.koehoorn@gmail.com>
Co-authored-by: Kristiyan Kostadinov <crisbeto@abv.bg>
Co-authored-by: Madleina Scheidegger <mscheid@google.com>
Co-authored-by: Mark Thompson <2554588+MarkTechson@users.noreply.github.com>
Co-authored-by: Minko Gechev <mgechev@gmail.com>
Co-authored-by: Paul Gschwendtner <paulgschwendtner@gmail.com>
Co-authored-by: Pawel Kozlowski <pkozlowski.opensource@gmail.com>
Co-authored-by: Pete Bacon Darwin <pete@bacondarwin.com>
Co-authored-by: Wagner Maciel <wagnermaciel@google.com>
Co-authored-by: Zach Arend <zachzach@google.com>
PR Close#43884
When a partially compiled component or directive is "linked" in JIT mode, the body
of its declaration is evaluated by the JavaScript runtime. If a class is referenced
in a query (e.g. `ViewQuery` or `ContentQuery`) but its definition is later in the
file, then the reference must be wrapped in a `forwardRef()` call.
Previously, query predicates were not wrapped correctly in partial declarations
causing the code to crash at runtime. In AOT mode, this code is never evaluated
but instead transformed as part of the build, so this bug did not become apparent
until Angular Material started running JIT mode tests on its distributable output.
This change fixes this problem by noting when queries are wrapped in `forwardRef()`
calls and ensuring that this gets passed through to partial compilation declarations
and then suitably stripped during linking.
See https://github.com/angular/components/pull/23882 and https://github.com/angular/components/issues/23907
PR Close#44113