When ngtsc comes across a source file during partial evaluation, it
would determine all exported symbols from that module and evaluate their
values greedily. This greedy evaluation strategy introduces unnecessary
work and can fall into infinite recursion when the evaluation result of
an exported expression would circularly depend on the source file. This
would primarily occur in CommonJS code, where the `exports` variable can
be used to refer to an exported variable. This variable would be
resolved to the source file itself, thereby greedily evaluating all
exported symbols and thus ending up evaluating the `exports` variable
again. This variable would be resolved to the source file itself,
thereby greedily evaluating all exported symbols and thus ending u
evaluating the `exports` variable again. This variable would be
resolved to the source file itself, thereby greedily evaluating all
exported symbols and thus ending up evaluating the `exports` variable
again. This variable would be resolved to the source file itself,
thereby greedily evaluating all exported symbols and thus ending up
evaluating the `exports` variable again. This went on for some time
until all stack frames were exhausted.
This commit introduces a `ResolvedModule` that delays the evaluation of
its exports until they are actually requested. This avoids the circular
dependency when evaluating `exports`, thereby fixing the issue.
Fix#33734
PR Close#33772
The template type checker generates code to check directive inputs and
outputs, whose name may contain characters that can not be used as
identifier in TypeScript. Prior to this change, such names would be
emitted into the generated code as is, resulting in invalid code and
unexpected template type check errors.
This commit fixes the bug by representing the potentially invalid names
as string literal instead of raw identifier.
Fixes#33590
PR Close#33741
NgModule compilation in JIT mode (that is also used in TestBed) caches module scopes on NgModule defs (using `transitiveCompileScopes` field). Module overrides (defined via TestBed.overrideModule) may invalidate this data by adding/removing items in `declarations` list. This commit forces TestBed to recalculate transitive scopes in case module overrides are present, so TestBed always gets the most up-to-date information.
PR Close#33787
This change enables "var(--my-var)" to pass through the style sanitizer.
After consulation with our security team, allowing these doesn't create
new attack vectors, so the sanitizer doesn't need to strip them.
Fixes parts of #23485 related to the sanitizer, other use cases discussed
there related to binding have been addressed via other changes to the
class and style handling in the runtime.
Closes#23485
PR Close#33841
This commit transforms the setClassMetadata calls generated by ngtsc from:
```typescript
/*@__PURE__*/ setClassMetadata(...);
```
to:
```typescript
/*@__PURE__*/ (function() {
setClassMetadata(...);
})();
```
Without the IIFE, terser won't remove these function calls because the
function calls have arguments that themselves are function calls or other
impure expressions. In order to make the whole block be DCE-ed by terser,
we wrap it into IIFE and mark the IIFE as pure.
It should be noted that this change doesn't have any impact on CLI* with
build-optimizer, which removes the whole setClassMetadata block within
the webpack loader, so terser or webpack itself don't get to see it at
all. This is done to prevent cross-chunk retention issues caused by
webpack's internal module registry.
* actually we do expect a short-term size regression while
https://github.com/angular/angular-cli/pull/16228
is merged and released in the next rc of the CLI. But long term this
change does nothing to CLI + build-optimizer configuration and is done
primarly to correct the seemingly correct but non-function PURE annotation
that builds not using build-optimizer could rely on.
PR Close#33337
NgModules in Ivy have a definition which contains various different bits
of metadata about the module. In particular, this metadata falls into two
categories:
* metadata required to use the module at runtime (for bootstrapping, etc)
in AOT-only applications.
* metadata required to depend on the module from a JIT-compiled app.
The latter metadata consists of the module's declarations, imports, and
exports. To support JIT usage, this metadata must be included in the
generated code, especially if that code is shipped to NPM. However, because
this metadata preserves the entire NgModule graph (references to all
directives and components in the app), it needs to be removed during
optimization for AOT-only builds.
Previously, this was done with a clever design:
1. The extra metadata was added by a function called `setNgModuleScope`.
A call to this function was generated after each NgModule.
2. This function call was marked as "pure" with a comment and used
`noSideEffects` internally, which causes optimizers to remove it.
The effect was that in dev mode or test mode (which use JIT), no optimizer
runs and the full NgModule metadata was available at runtime. But in
production (presumably AOT) builds, the optimizer runs and removes the JIT-
specific metadata.
However, there are cases where apps that want to use JIT in production, and
still make an optimized build. In this case, the JIT-specific metadata would
be erroneously removed. This commit solves that problem by adding an
`ngJitMode` global variable which guards all `setNgModuleScope` calls. An
optimizer can be configured to statically define this global to be `false`
for AOT-only builds, causing the extra metadata to be stripped.
A configuration for Terser used by the CLI is provided in `tooling.ts` which
sets `ngJitMode` to `false` when building AOT apps.
PR Close#33671
The Ivy template type-checker is capable of inferring the type of a
structural directive (such as NgForOf<T>). Previously, this was done with
fullTemplateTypeCheck: true, even if strictTemplates was false. View Engine
previously did not do this inference, and so this causes breakages if the
type of the template context is not what the user expected.
In particular, consider the template:
```html
<div *ngFor="let user of users as all">
{{user.index}} out of {{all.length}}
</div>
```
As long as `users` is an array, this seems reasonable, because it appears
that `all` is an alias for the `users` array. However, this is misleading.
In reality, `NgForOf` is rendered with a template context that contains
both a `$implicit` value (for the loop variable `user`) as well as a
`ngForOf` value, which is the actual value assigned to `all`. The type of
`NgForOf`'s template context is `NgForContext<T>`, which declares `ngForOf`'s
type to be `NgIterable<T>`, which does not have a `length` property (due to
its incorporation of the `Iterable` type).
This commit stops the template type-checker from inferring template context
types unless strictTemplates is set (and strictInputTypes is not disabled).
Fixes#33527.
PR Close#33537
This commit changes the reporting of watch mode diagnostics for ngtsc to use
the same formatting as non-watch mode diagnostics. This prints rich and
contextual errors even in watch mode, which previously was not the case.
Fixes#32213
PR Close#33862
Previously, the ngtsc compiler attempted to reuse analysis work from the
previous program during an incremental build. To do this, it had to prove
that the work was safe to reuse - that no changes made to the new program
would invalidate the previous analysis.
The implementation of this had a significant design flaw: if the previous
program had errors, the previous analysis would be missing significant
information, and the dependency graph extracted from it would not be
sufficient to determine which files should be re-analyzed to fill in the
gaps. This often meant that the build output after an error was resolved
would be wholly incorrect.
This commit switches ngtsc to take a simpler approach to incremental
rebuilds. Instead of attempting to reuse prior analysis work, the entire
program is re-analyzed with each compilation. This is actually not as
expensive as one might imagine - analysis is a fairly small part of overall
compilation time.
Based on the dependency graph extracted during this analysis, the compiler
then can make accurate decisions on whether to emit specific files. A new
suite of tests is added to validate behavior in the presence of source code
level errors.
This new approach is dramatically simpler than the previous algorithm, and
should always produce correct results for a semantically correct program.s
Fixes#32388Fixes#32214
PR Close#33862
Originally, QueryList implemented Iterable and provided a Symbol.iterator
on its prototype. This caused issues with tree-shaking, so QueryList was
refactored and the Symbol.iterator added in its constructor instead. As
part of this change, QueryList no longer implemented Iterable directly.
Unfortunately, this meant that QueryList was no longer assignable to
Iterable or, consequently, NgIterable. NgIterable is used for NgFor's input,
so this meant that QueryList was not usable (in a type sense) for NgFor
iteration. View Engine's template type checking would not catch this, but
Ivy's did.
As a fix, this commit adds the declaration (but not the implementation) of
the Symbol.iterator function back to QueryList. This has no runtime effect,
so it doesn't affect tree-shaking of QueryList, but it ensures that
QueryList is assignable to NgIterable and thus usable with NgFor.
Fixes#29842
PR Close#33536
Previously, the compiler assumed that all TS files logically within a
project existed under one or more "root directories". If the TS compiler
option `rootDir` or `rootDirs` was set, they would dictate the root
directories in use, otherwise the current directory was used.
Unfortunately this assumption was unfounded - it's common for projects
without explicit `rootDirs` to import from files outside the current
working directory. In such cases the `LogicalProjectStrategy` would attempt
to generate imports into those files, and fail. This would lead to no
`ReferenceEmitStrategy` being able to generate an import, and end in a
compiler assertion failure.
This commit introduces a new strategy to use when there are no `rootDirs`
explicitly present, the `RelativePathStrategy`. It uses simpler, filesystem-
relative paths to generate imports, even to files above the current working
directory.
Fixes#33659Fixes#33562
PR Close#33828
This commit adds the ability to change directories using the compiler's
internal filesystem abstraction. This is a prerequisite for writing tests
which are sensitive to the current working directory.
In addition to supporting the `chdir()` operation, this commit also fixes
`getDefaultLibLocation()` for mock filesystems to not assume `node_modules`
is in the current directory, but to resolve it similarly to how Node does
by progressively looking higher in the directory tree.
PR Close#33828
TNode.inputs are initialised during directives resolution now so we know early
if a node has directives with inputs or no. We don't need to use undefined value
as an indicator that inputs were not resolved yet.
PR Close#33798
Before this change a public name of a directive's input
was stored in 2 places:
- as a key of an object on TNode.index;
- as a value of PropertyAliasValue at the index 1
This PR changes the data structure so the public name is stored
only once as a key on TNode.index. This saves one array entry
for each and every directive input.
PR Close#33798
Adds support for chaining of `styleProp`, `classProp` and `stylePropInterpolateX` instructions whenever possible which should help generate less code. Note that one complication here is for `stylePropInterpolateX` instructions where we have to break into multiple chains if there are other styling instructions inbetween the interpolations which helps maintain the execution order.
PR Close#33837
This refactorings clearly separates the first and subsequent creation execution
of the `template` instruction. This approach has the following benefits:
- it is clear what happens during the first vs. subsequent executions;
- we can avoid several memory reads and checks after the first creation pass
(there is measurable performance improvement on various benchmarks);
- the template instructions becomes smaller and should become a candidate
for optimisations / inlining faster;
PR Close#33856
The ReflectionHost supports enumeration of constructor parameters, and one
piece of information it returns describes the origin of the parameter's
type. Parameter types come in two flavors: local (the type is not imported
from anywhere) or non-local (the type comes via an import).
ngcc incorrectly classified all type parameters as 'local', because in the
source files that ngcc processes the type parameter is a real ts.Identifer.
However, that identifier may still have come from an import and thus might
be non-local.
This commit changes ngcc's ReflectionHost(s) to properly recognize and
report these non-local type references.
Fixes#33677
PR Close#33901
`ng_package` rule has an implicitly optional depedency on terser a48573efe8/packages/bazel/src/ng_package/ng_package.bzl (L36)
When using this rule without terser being available we get the below error;
```
ERROR: /home/circleci/ng/modules/express-engine/BUILD.bazel:22:1: every rule of type ng_package implicitly depends upon the target '@npm//terser/bin:terser', but this target could not be found because of: no such package '@npm//terser/bin': BUILD file not found in directory 'terser/bin' of external repository @npm. Add a BUILD file to a directory to mark it as a package.
ERROR: Analysis of target '//modules/express-engine:npm_package' failed; build aborted: no such package '@npm//terser/bin': BUILD file not found in directory 'terser/bin' of external repository @npm. Add a BUILD file to a directory to mark it as a package.
```
PR Close#33891
Since i18n messages are mapped to `$localize` tagged template strings,
the "raw" version must be properly escaped. Otherwise TS will throw an
error such as:
```
Error: Debug Failure. False expression: Expected argument 'text' to be the normalized (i.e. 'cooked') version of argument 'rawText'.
```
This commit ensures that we properly escape these raw strings before creating
TS AST nodes from them.
PR Close#33820
The `:` char is used as a metadata marker in `$localize` messages.
If this char appears in the metadata it must be escaped, as `\:`.
Previously, although the `:` char was being escaped, the TS AST
being generated was not correct and so it was being output double
escaped, which meant that it appeared in the rendered message.
As of TS 3.6.2 the "raw" string can be specified when creating tagged
template AST nodes, so it is possible to correct this.
PR Close#33820
When asking for a ViewContainerRef on <ng-container> we do reuse <ng-container> comment
node as a LContainer's anachor. Before this fix the act of re-using a <ng-container>'s
comment node would result in this comment node being re-appended to the DOM in the wrong
place. With the fix in this PR we make sure that re-using <ng-container>'s comment node
doesn't result in unwanted DOM manipulation (ng-gontainer's comment node is already part
of the DOM and doesn't have to be re-created / re-appended).
PR Close#33816
In View Engine, providers which neither used `useValue`, `useClass`,
`useFactory` or `useExisting`, were interpreted differently.
e.g.
```
{provide: X} -> {provide: X, useValue: undefined}, // this is how it works in View Engine
{provide: X} -> {provide: X, useClass: X}, // this is how it works in Ivy
```
The missing-injectable migration should migrate such providers to the
explicit `useValue` provider. This ensures that there is no unexpected
behavioral change when updating to v9.
PR Close#33709
In #32902 a bug was supposedly fixed where internal classes as used
within `ModuleWithProviders` are publicly exported, even when the
typings file already contained the generic type on the
`ModuleWithProviders`. This fix turns out to have been incomplete, as
the `ModuleWithProviders` analysis is not done when not processing the
typings files.
The effect of this bug is that formats that are processed after the
initial format had been processed would not have exports for internal
symbols, resulting in "export '...' was not found in '...'" errors.
This commit fixes the bug by always running the `ModuleWithProviders`
analyzer. An integration test has been added that would fail prior to
this change.
Fixes#33701
PR Close#33875
ngcc has a basic integration test infrastructure that downlevels
TypeScript code into bundle formats that need to be processed by ngcc.
Until now, only ES5 bundles were created with a flat structure, however
more complex scenarios require an APF-like layout containing multiple
bundle formats.
PR Close#33875
Some declaration files may not be referenced from an entry-point's
main typings file, as it may declare types that are only used internally.
ngcc has logic to include declaration files based on all source files,
to ensure internal declaration files are available.
For packages following APF layout, however, this logic was insufficient.
Consider an entry-point with base path of `/esm2015/testing` and typings
residing in `/testing`, the file
`/esm2015/testing/src/nested/internal.js` has its typings file at
`/testing/src/nested/internal.d.ts`. Previously, the declaration was
assumed to be located at `/esm2015/testing/testing/internal.d.ts` (by
means of `/esm2015/testing/src/nested/../../testing/internal.d.ts`)
which is not where the declaration file can be found. This commit
resolves the issue by looking in the correct directory.
PR Close#33875
In flat bundle formats, multiple classes that have the same name can be
suffixed to become unique. In ES5-like bundles this results in the outer
declaration from having a different name from the "implementation"
declaration within the class' IIFE, as the implementation declaration
may not have been suffixed.
As an example, the following code would fail to have a `Directive`
decorator as ngcc would search for `__decorate` calls that refer to
`AliasedDirective$1` by name, whereas the `__decorate` call actually
uses the `AliasedDirective` name.
```javascript
var AliasedDirective$1 = /** @class */ (function () {
function AliasedDirective() {}
AliasedDirective = tslib_1.__decorate([
Directive({ selector: '[someDirective]' }),
], AliasedDirective);
return AliasedDirective;
}());
```
This commit fixes the problem by not relying on comparing names, but
instead finding the declaration and matching it with both the outer
and inner declaration.
PR Close#33878
Previously, indexing a container type would not return completions for
the indexed type because for every TypeScript type, the recorded index
type was always marked as `undefined`, regardless of the index
signature.
This PR now returns the index type of TypeScript containers with numeric
or string index signatures. This allows use to generate completions for
arrays and defined index types:
```typescript
interface Container<T> {
[key: string]: T;
}
const ctr: Container<T>;
ctr['stringKey']. // gives `T.` completions
const arr: T[];
arr[0]. // gives `T.` completions
```
Note that this does _not_ provide completions for properties indexed by
string literals, e.g.
```typescript
interface Container<T> {
foo: T;
}
const ctr: Container<T>;
ctr['foo']. // does not give `T.` completions
```
Closes angular/vscode-ng-language-service#110
Closes angular/vscode-ng-language-service#277
PR Close#33775
In ccc76f749, `@angular/platform-webworker` and
`@angular/platform-webworker-dynamic` were deprecated (i.e. by
deprecating all their public APIs). However, some public
`@angular/platform-webworker` APIs were accidentally missed,
additionally resulting in the package itself not showing up as
deprecated on angular.io.
This commit fixes it by marking those remaining public APIs as
deprecated.
PR Close#33824
This commit fixes a bug whereby completions for attribute values are only
provided for directives that support the micro-syntax format, all other
bindings are ignored.
I'm not sure if this is a regresssion or a bug, because there were no
tests prior to this.
PR Close#33839
The earlier update to nodejs rules 0.40.0 fixes the cross-platform RBE issues with nodejs_binary. This commit adds a work-around for rules_webtesting cross-platform RBE issues.
PR Close#33708