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
By clearing `sessionStorage` and unsubscribing from `Location` events,
after each test, we reduce the possibility of potential
[spooky action at a distance][1]-type of failures in the future.
This does not have an impact on the actual app, since `ScrollService` is
currently expected to live throughout the lifetime of the app. Still,
unsubscribing from `Location` events keeps the code consistent with how
other `ScrollService` listeners are handled (e.g. for `window` events).
[1]: https://en.wikipedia.org/wiki/Action_at_a_distance_(computer_programming)
PR Close#33937
`ScrollService` subscribes to global `window` events and mutates global
state in the listener (e.g. read/write values from/to `sessionStorage`).
Therefore, we need to always call its `ngOnDestroy()` method to
unsubscribe from these events after each test.
In f69c6e204, a new testcase was introduced that was not destroyed. As a
result, random failures started to randomly happen in other, unrelated
tests ([example CI failure][1]).
This commit fixes this by ensuring all `ScrollService` instances are
destroyed after each tests (provided that they are created with the
`createScrollService()` helper).
[1]: https://circleci.com/gh/angular/angular/533298
PR Close#33937
This adds a `tools/ng_rollup_bundle/terser_config.json` file to override the default terser_minified config provided by the rule. After this change, the layer violation in rules_nodejs can be fixed by removing `"global_defs": {"ngDevMode": false, "ngI18nClosureMode": false},` from `terser_config.default.json` in rules_nodejs.
Change requested by Alex Rickabaugh in https://github.com/bazelbuild/rules_nodejs/pull/1338.
PR Close#33865
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
Whenever cookies are disabled in the browser, `window.sessionStorage` is not avaialable to the app (i.e. even trying to access `window.sessionStorage` throws an error).
To avoid breaking the app, we use a no-op `Storage` implementation if `window.sessionStorage` is not available.
Fixes#33795
PR Close#33829
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
Since `scripts/package-builder.js` gets run from the
`aio` folder sometimes, it is important to set the cwd
for the command that finds the bazel bin directory.
PR Close#33904
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
Fixes issue introduced in https://github.com/angular/angular/pull/33808 for ng_rollup_bundle with `-spawn_strategy=standalone`. Without the sandbox (if --spawn_strategy=standalone is set) rollup can resolve to the non-esm .js file generated by ts_library instead of the desired .mjs. This fixes the problem by prioritizing .mjs.
Issue observed is of the flavor:
```
ERROR: modules/benchmarks/src/views/BUILD.bazel:20:1: Bundling JavaScript modules/benchmarks/src/views/bundle.es2015.js
[rollup] failed (Exit 1)
[!] Error: 'enableProdMode' is not exported by bazel-out/darwin-fastbuild/bin/packages/core/index.js
https://rollupjs.org/guide/en/#error-name-is-not-exported-by-module
bazel-out/darwin-fastbuild/bin/modules/benchmarks/src/views/index.mjs (12:9)
10: * found in the LICENSE file at https://angular.io/license
11: */
12: import { enableProdMode } from '@angular/core';
^
13: import { platformBrowser } from '@angular/platform-browser';
14: import { ViewsBenchmarkModuleNgFactory } from './views-benchmark.ngfactory';
Error: 'enableProdMode' is not exported by bazel-out/darwin-fastbuild/bin/packages/core/index.js
```
PR Close#33867
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
By adding the `bash` language to the code snippet it will no
longer be auto-linked, which was causing a false positive link
to be rendered.
Fixes#33859
PR Close#33877
Previously any code block, which was not marked with
`no-auto-link` css class would have its contents auto-linked to
API pages. Sometimes this results in false positive links being
generated.
This is problematic for triple backticked blocks, which cannot provide
the `no-auto-link` CSS class to prevent the linking.
This commit fixes the problem by allowing the auto-linker to be
configured not to auto-link code blocks that have been marked with an
"ignored" language. By default these are `bash` and `json`.
Triple backticked blocks are able to specify the language directly after
the first set of triple backticks.
Fixes#33859
PR Close#33877
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