Previously, a template's context name would only be included in an embedded
template function if the element that the template was declared on has a
tag name. This is generally true for elements, except for `ng-content`
that does not have a tag name. By omitting the context name the compiler
could introduce duplicate template function names, which would fail at runtime.
This commit fixes the behavior by always including the context name in the
template function's name, regardless of tag name.
Resolves FW-1272
PR Close#30025
Previously, ngcc would insert new imports at the beginning of the file, for
convenience. This is problematic for imports that have side-effects, as the
side-effects imposed by such imports may affect the behavior of subsequent
imports.
This commit teaches ngcc to insert imports after any existing imports. Special
care has been taken to ensure inserted constants will still follow after the
inserted imports.
Resolves FW-1271
PR Close#30029
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, all of a program's files would be copied into the __ivy_ngcc__
folder where ngcc then writes its modifications into. The set of source files
in a program however is much larger than the source files contained within
the entry-point of interest, so many more files were copied than necessary.
Even worse, it may occur that an unrelated file in the program would collide
with an already existing source file, resulting in incorrectly overwriting
a file with unrelated content. This behavior has actually been observed
with @angular/animations and @angular/platform-browser/animations, where
the former package would overwrite declaration files of the latter package.
This commit fixes the issue by only copying relevant source files when cloning
a bundle's content into __ivy_ngcc__.
Fixes#29960
PR Close#30020
Previously, during the evaluation of a function call where no argument
was provided for a parameter that has a default value, the default value
would be taken from the context of the caller, instead of the callee.
This commit fixes the behavior by resolving the default value of a
parameter in the context of the callee.
PR Close#29888
Previously, ngtsc's static evaluator did not take spread operators into
account when evaluating function calls, nor did it handle rest arguments
correctly. This commit adds support for static evaluation of these
language features.
PR Close#29888
Template type-checking is enabled by default in the View Engine compiler.
The feature in Ivy is not quite ready for this yet, so this flag will
temporarily control whether templates are type-checked in ngtsc.
The goal is to remove this flag after rolling out template type-checking in
google3 in Ivy mode, and making sure the feature is as compatible with the
View Engine implementation as possible.
Initially, the default value of the flag will leave checking disabled.
PR Close#29698
Previously, Template.templateAttrs was introduced to capture attribute
bindings which originated from microsyntax (e.g. bindings in *ngFor="...").
This means that a Template node can have two different structures, depending
on whether it originated from microsyntax or from a literal <ng-template>.
In the literal case, the node behaves much like an Element node, it has
attributes, inputs, and outputs which determine which directives apply.
In the microsyntax case, though, only the templateAttrs should be used
to determine which directives apply.
Previously, both the t2_binder and the TemplateDefinitionBuilder were using
the wrong set of attributes to match directives - combining the attributes,
inputs, outputs, and templateAttrs of the Template node regardless of its
origin. In the TDB's case this wasn't a problem, since the TDB collects a
global Set of directives used in the template, so it didn't matter whether
the directive was also recognized on the <ng-template>. t2_binder's API
distinguishes between directives on specific nodes, though, so it's more
sensitive to mismatching.
In particular, this showed up as an assertion failure in template type-
checking in certain cases, when a directive was accidentally matched on
a microsyntax template element and also had a binding which referenced a
variable declared in the microsyntax. This resulted in the type-checker
attempting to generate a reference to a variable that didn't exist in that
scope.
The fix is to distinguish between the two cases and select the appropriate
set of attributes to match on accordingly.
Testing strategy: tested in the t2_binder tests.
PR Close#29698
This commit adds support for template type-checking a pipe binding which
previously was not handled by the type-checking engine. In compatibility
mode, the arguments to transform() are not checked and the type returned
by a pipe is 'any'. In full type-checking mode, the transform() method's
type signature is used to check the pipe usage and infer the return type
of the pipe.
Testing strategy: TCB tests included.
PR Close#29698
The template type-checking engine previously would assemble a type-checking
program by inserting Type Check Blocks (TCBs) into existing user files. This
approach proved expensive, as TypeScript has to re-parse and re-type-check
those files when processing the type-checking program.
Instead, a far more performant approach is to augment the program with a
single type-checking file, into which all TCBs are generated. Additionally,
type constructors are also inlined into this file.
This is not always possible - both TCBs and type constructors can sometimes
require inlining into user code, particularly if bound generic type
parameters are present, so the approach taken is actually a hybrid. These
operations are inlined if necessary, but are otherwise generated in a single
file.
It is critically important that the original program also include an empty
version of the type-checking file, otherwise the shape of the two programs
will be different and TypeScript will throw away all the old program
information. This leads to a painfully slow type checking pass, on the same
order as the original program creation. A shim to generate this file in the
original program is therefore added.
Testing strategy: this commit is largely a refactor with no externally
observable behavioral differences, and thus no tests are needed.
PR Close#29698
This commit adds support in the template type-checking engine for handling
the logical not operation and the safe navigation operation.
Safe navigation in particular is tricky, as the View Engine implementation
has a rather inconvenient flaw. View Engine checks a safe navigation
operation `a?.b` as:
```typescript
(a != null ? a!.b : null as any)
```
The type of this expression is always 'any', as the false branch of the
ternary has type 'any'. Thus, using null-safe navigation throws away the
type of the result, and breaks type-checking for the rest of the expression.
A flag is introduced in the type-checking configuration to allow Ivy to
mimic this behavior when needed.
Testing strategy: TCB tests included.
PR Close#29698
View Engine's implementation of naive template type-checking is less
advanced than the current Ivy implementation. As a result, Ivy catches lots
of typing bugs which VE does not. As a result, it's necessary to tone down
the Ivy template type-checker in the default case.
This commit introduces a mechanism for doing that, by passing a config to
the template type-checking engine. Through this configuration, particular
checks can be loosened or disabled entirely.
Testing strategy: TCB tests included.
PR Close#29698
Previously the template type-checking code only considered the metadata of
directive classes actually referenced in the template. If those directives
had base classes, any inputs/outputs/etc of the base classes were not
tracked when generating the TCB. This resulted in bindings to those inputs
being incorrectly attributed to the host component or element.
This commit uses the new metadata package to follow directive inheritance
chains and use the full metadata for a directive for TCB generation.
Testing strategy: Template type-checking tests included.
PR Close#29698
Previously, metadata registration (the recording of collected metadata
during analysis of directives, pipes, and NgModules) was only used to
produce the `LocalModuleScope`, and thus was handled by the
`LocalModuleScopeRegistry`.
However, the template type-checker also needs information about registered
directives, outside of the NgModule scope determinations. Rather than
reuse the scope registry for an unintended purpose, this commit introduces
new abstractions for metadata registration and lookups in a separate
'metadata' package, which the scope registry implements.
This paves the way for a future commit to make use of this metadata for the
template type-checking system.
Testing strategy: this commit is a refactoring which introduces no new
functionality, so existing tests are sufficient.
PR Close#29698
Previously, bindings to [class] and [style] were treated like any other
property binding. That is, they would result in type-checking code that
attempted to write directly to .class or .style on the element node.
This is incorrect, however - the mapping from Angular's [class] and [style]
onto the DOM properties is non-trivial.
For now, this commit avoids the issue by only checking the expressions
themselves and not the assignment to the element properties.
Testing strategy: TCB tests included.
PR Close#29698
Previously the template type-checking engine processed templates in a linear
manner, and could not handle '#' references within a template. One reason
for this is that '#' references are non-linear - a reference can be used
before its declaration. Consider the template:
```html
{{ref.value}}
<input #ref>
```
Accommodating this required refactoring the type-checking code generator to
be able to produce Type Check Block (TCB) code non-linearly. Now, each
template is processed and a list of TCB operations (`TcbOp`s) are created.
Non-linearity is modeled via dependencies between operations, with the
appropriate protection in place for circular dependencies.
Testing strategy: TCB tests included.
PR Close#29698
This commit adds support for the generation of type-checking expressions for
forms which were previously unsupported:
* array literals
* map literals
* keyed property accesses
* non-null assertions
Testing strategy: TCB tests included.
Fixes#29327
FW-1218 #resolve
PR Close#29698
This commit adds a test suite for the Type Check Block generation which
doesn't require running the entire compiler (specifically, it doesn't even
require the creation of a ts.Program).
PR Close#29698
This commit adds registration of AOT compiled NgModules that have 'id'
properties set in their metadata. Such modules have a call to
registerNgModuleType() emitted as part of compilation.
The JIT behavior of this code is already in place.
This is required for module loading systems (such as g3) which rely on
getModuleFactory().
PR Close#29980
Previously, ngtsc would fail to resolve `forwardRef` calls if they
contained additional parenthesis or casts. This commit changes the
behavior to first unwrap the AST nodes to see past such insignificant
nodes, resolving the issue.
Fixes#29639
PR Close#29886
Previously, only static evaluation of `Array.slice` was implemented in
ngtsc's static evaluator. This commit adds support for `Array.concat`.
Closes#29835
PR Close#29887
The config path is an optional argument to `ts.parseJsonConfigFileContent`. When passed, it is added to the returned object as `options.configFilePath`, and `tsc` itself passes it in.
The new TS 3.4 [incremental](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html) build functionality relies on this property being present: 025d826339/src/compiler/emitter.ts (L56-L57)
When using The compiler-cli `readConfiguration` the config path option isn't passed, preventing consumers (like @ngtools/webpack) from obtaining a complete config object.
This PR fixes this omission and should allow JIT users of @ngtools/webpack to set the `incremental` option in their tsconfig and have it be used by the TS program.
I tested this in JIT and saw a small decrease in build times in a small project. In AOT the incremental option didn't seem to be used at all, due to how `ngc` uses the TS APIs.
Related to https://github.com/angular/angular-cli/issues/13941.
PR Close#29872
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
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
Previously we always walked the whole folder tree looking for
entry-points before we tested whether a target package had been
processed already. This could take >10secs!
This commit does a quick check of the target package before doing
the full walk which brings down the execution time for ngcc in this
case dramatically.
```
$ time ./node_modules/.bin/ivy-ngcc -t @angular/common/http/testing
Compiling @angular/core : fesm2015 as esm2015
Compiling @angular/core : fesm5 as esm5
Compiling @angular/core : esm2015 as esm2015
Compiling @angular/core : esm5 as esm5
Compiling @angular/common/http : fesm2015 as esm2015
Compiling @angular/common/http : fesm5 as esm5
Compiling @angular/common/http : esm2015 as esm2015
Compiling @angular/common/http : esm5 as esm5
Compiling @angular/common/http/testing : fesm2015 as esm2015
Compiling @angular/common/http/testing : fesm5 as esm5
Compiling @angular/common/http/testing : esm2015 as esm2015
Compiling @angular/common/http/testing : esm5 as esm5
real 0m19.766s
user 0m28.533s
sys 0m2.262s
```
```
$ time ./node_modules/.bin/ivy-ngcc -t @angular/common/http/testing
The target entry-point has already been processed
real 0m0.666s
user 0m0.605s
sys 0m0.113s
```
PR Close#29740
Previously, if a matching rootDir ended with a slash then the path
returned from `logicalPathOfFile()` would not start with a slash,
which is inconsistent.
PR Close#29627
The defineInjector function specifies its providers and imports array to
be optional, so if no providers/imports are present these keys may be
omitted. This commit updates the compiler to only generate the keys when
necessary.
PR Close#29598
Prior to this change, a module's imports and exports would be used verbatim
as an injectors' imports. This is detrimental for tree-shaking, as a
module's exports could reference declarations that would then prevent such
declarations from being eligible for tree-shaking.
Since an injector actually only needs NgModule references as its imports,
we may safely filter out any declarations from the list of module exports.
This makes them eligible for tree-shaking once again.
PR Close#29598
Prior to this change, all module metadata would be included in the
`defineNgModule` call that is set as the `ngModuleDef` field of module
types. Part of the metadata is scope information like declarations,
imports and exports that is used for computing the transitive module
scope in JIT environments, preventing those references from being
tree-shaken for production builds.
This change moves the metadata for scope computations to a pure function
call that patches the scope references onto the module type. Because the
function is marked pure, it may be tree-shaken out during production builds
such that references to declarations and exports are dropped, which in turn
allows for tree-shaken any declaration that is not otherwise referenced.
Fixes#28077, FW-1035
PR Close#29598
With the new API, where you can choose to only process the first
matching format, it is possible to process an entry-point multiple
times, if you pass in a different format each time.
Previously, ngcc would always try to process the typings files for
the entry-point along with processing the first format of the current
execution of ngcc. But this meant that it would be trying to process
the typings a second time.
Now we only process the typings if they have not already been
processed as part of processing another format in another
even if it was in a different execution of ngcc.
PR Close#29657
In ES2015, classes could have been emitted as a variable declaration
initialized with a class expression. In certain situations, an intermediary
variable suffixed with `_1` is present such that the variable
declaration's initializer becomes a binary expression with its rhs being
the class expression, and its lhs being the identifier of the intermediate
variable. This structure was not recognized, resulting in such classes not
being considered as a class in `Esm2015ReflectionHost`.
As a consequence, the analysis of functions/methods that return a
`ModuleWithProviders` object did not take the methods of such classes into
account.
Another edge-case with such intermediate variable was that static
properties would not be considered as class members. A testcase was added
to prevent regressions.
Fixes#29078
PR Close#29119
Currently there is no support in ngtsc for imports of the form:
```
import * as core from `@angular/core`
export function forRoot(): core.ModuleWithProviders;
```
This commit modifies the `ReflectionHost.getImportOfIdentifier(id)`
method, so that it supports this kind of return type.
PR Close#27675
This commit introduces a mechanism for incremental compilation to the ngtsc
compiler.
Previously, incremental information was used in the construction of the
ts.Program for subsequent compilations, but was not used in ngtsc itself.
This commit adds an IncrementalState class, which tracks state between ngtsc
compilations. Currently, this supports skipping the TypeScript emit step
when the compiler can prove the contents of emit have not changed.
This is implemented for @Injectables as well as for files which don't
contain any Angular decorated types. These are the only files which can be
proven to be safe today.
See ngtsc/incremental/README.md for more details.
PR Close#29380
This commit adds support for compiling the same program repeatedly in a way
that's similar to how incremental builds work in a tool such as the CLI.
* support is added to the compiler entrypoint for reuse of the Program
object between compilations. This is the basis of the compiler's
incremental compilation model.
* support is added to wrap the CompilerHost the compiler creates and cache
ts.SourceFiles in between compilations.
* support is added to track when files are emitted, for assertion purposes.
* an 'exclude' section is added to the base tsconfig to prevent .d.ts
outputs from the first compilation from becoming inputs to any subsequent
compilations.
PR Close#29380
This commit adds a `tracePerformance` option for tsconfig.json. When
specified, it causes a JSON file with timing information from the ngtsc
compiler to be emitted at the specified path.
This tracing system is used to instrument the analysis/emit phases of
compilation, and will be useful in debugging future integration work with
@angular/cli.
See ngtsc/perf/README.md for more details.
PR Close#29380