The Angular CLI will continue to call ngcc on all possible packages, even if they
have already been processed by ngcc in a postinstall script.
In a parallel build environment, this was causing ngcc to complain that it was
being run in more than one process at the same time.
This commit moves the check for whether the targeted package has been
processed outside the locked code section, since there is no issue with
multiple ngcc processes from doing this check.
PR Close#34722
Previously, it was possible for multiple instance of ngcc to be running
at the same time, but this is not supported and can cause confusing and
flakey errors at build time.
Now, only one instance of ngcc can run at a time. If a second instance
tries to execute it fails with an appropriate error message.
See https://github.com/angular/angular/issues/32431#issuecomment-571825781
PR Close#34722
This commit adds an `exclusive` parameter to the
`FileSystem.writeFile()` method. When this parameter is
true, the method will fail with an `EEXIST` error if the
file already exists on disk.
PR Close#34722
Fixes Ivy throwing an error when trying to access the `DebugNode.classes` of an SVG element. The problem is that the `className` of an SVG element is an `SVGAnimatedString`, rather than a plain string.
Fixes#34868.
PR Close#34872
This commit makes the Angular Language Service interface a strict subset
of TypeScript's Language Service by renaming all methods to be
consistent with TypeScript's.
The custom Angular `LanguageService` interface was needed before the
inception of TypeScript tsserver plugin, but is now obsolete since
Angular LS is a proper tsserver plugin.
This allows us to easily adapt to upstream TS changes in the future, and
also allows us to reuse all data types defined in TypeScript.
PR Close#34888
This patch removes the need for the styleSanitizer() instruction in
favor of passing the sanitizer into directly into the styleProp
instruction.
This patch also increases the binding index size for all style/class bindings in preparation for #34418
PR Close#34480
Pipes in host binding expressions are not supported in View Engine and Ivy, but in some more complex cases (like `(value | pipe) === true`) compiler was not reporting errors. This commit extends Ivy logic to detect pipes in host binding expressions and throw in cases bindings are present. View Engine behavior remains the same.
PR Close#34655
In #28162 we introduced an extra `removeNode` call for host elements which can cause the parent element to be removed before all child animations have finished. The issue is only in Ivy, because that the only place where we pass in the `isHostElement` flag. These changes fix the issue by not re-triggering the removal logic if the element has in-progress animations.
Fixes#33597.
PR Close#34702
Before ivy it was possible to configure a mutable service value
in an application initializer (by providing an `APP_INITIALIZER`)
that could be read in the provider of `LOCALE_ID`. This is a common
scenario if you wanted to load the locale id asynchronously from
an HTTP request for instance.
When using the ivy, the runtime needs to be told what the current
locale is, which is done by calling the `setLocaleId()` function with
the value injected by the `LOCALE_ID` token. Previously this was
being done before the application initializers were run, which meant
that the `LOCALE_ID` provider was being executed before the
app initializers had a chance to get a new value for it.
Now this initalization of the locale for the ivy runtime is done after the
application initializers have been run.
Closes#34701
PR Close#34830
Since I was learning the codebase and had a hard time understanding what was going on I've done a
bunch of changes in one commit that under normal circumstances should have been split into several
commits. Because this code is likely going to be overwritten with Misko's changes I'm not going to
spend the time with trying to split this up.
Overall I've done the following:
- I processed review feedback from #34307
- I did a bunch of renaming to make the code easier to understand
- I refactored some internal functions that were either inefficient or hard to read
- I also updated lots of type signatures to correct them and to remove many casts in the code
PR Close#34307
Prior to this change, in Ivy mode ngStyle/ngClass would accidentally emit value changes for static
(string-based) values even if the value itself had not changed. This patch ensures that
the style/class diffing code is more strict and when it signals ngClass/ngStyle that there has been
a value change.
Fixes#34336, #34444
PR Close#34307
remove unnecessary underscore suffix and the corresponding TODO comments,
because the rollup bug was fixed: github.com/rollup/rollup/issues/2047
PR Close#34757
Typescript 3.7 now emits d.ts files for getters differently than prior versions,
and there seems to be a bug in how it strips private types without replacing them
with explicit 'any' type. This then leads to compilation failures in projects compiled
against our packages that don't have skipLibCheck turned on but do have strict or
noImplicitAny check on.
I'm working around this by marking the affected getters as @internal and
adding a test to prevent future regressions.
I believe this is a TypeScript bug, and I filed a bug report:
https://github.com/microsoft/TypeScript/issues/36216
PR Close#34798
This release resolves the bootstrap require patching issue with jasmine_node_test. Require patches are now included before any bootstrap scripts.
PR Close#34736
This is recommended in the Bazel docs as $(location) is ambiguous and can mean either $(execpath) or $(rootpath) depending on the context.
PR Close#34736
This brings in a few minor fixes including a better way to patch require for bootstrap scripts
Also remove install_source_map_support attribute from nodejs_binary targets This attribute will be removed from nodejs_binary in the future
PR Close#34736
For the purposes of the integration test the zone.js script & bundle script tags can just go into the source index.html itself. The purpose of the integration test is is to test @angular/bazel & ng_module & ng_package so there is no need to exercise html_insert_assets in integration/bazel.
PR Close#34736
The major one that affects the angular repo is the removal of the bootstrap attribute in nodejs_binary, nodejs_test and jasmine_node_test in favor of using templated_args --node_options=--require=/path/to/script. The side-effect of this is that the bootstrap script does not get the require.resolve patches with explicitly loading the targets _loader.js file.
PR Close#34736
When searching the typings program for a package for imports a
distinction is drawn between missing entry-points and deep imports.
Previously in the `DtsDependencyHost` these deep imports may be
marked as missing if there was no typings file at the deep import path.
Instead there may be a javascript file instead. In practice this means
the import is "deep" and not "missing".
Now the `DtsDependencyHost` will also consider `.js` files when checking
for deep-imports, and it will also look inside `@types/...` for a suitable
deep-imported typings file.
Fixes#34720
PR Close#34695
Refactored Bazel host creation to export some of the relevant utility functions. google3 needs to make some modifications to the Bazel host to enable the Ivy migration. The functionality exported here is still needed in g3, but it allows g3 code to create the Bazel host, make necessary modifications, and then provide it to the external codebase here while everything is still compatible. For external users, this is a no-op.
PR Close#34686
Currently ngtsc looks for the first `ConstructorDeclaration` when figuring out what the parameters are so that it can generate the DI instructions. The problem is that if a constructor has overloads, it'll have several `ConstructorDeclaration` members with a different number of parameters. These changes tweak the logic so it looks for the constructor implementation.
PR Close#34590
Both `MinLengthValidator` and `MaxLengthValidator` accepted only string inputs for the length required, which throws with Ivy and `fullTemplateTypeCheck` enabled:
<!-- min = 2 in the component -->
<input [minlength]="min">
with:
Type 'number' is not assignable to type 'string | undefined'
This relaxes the accepted type to `string | number` to avoid breakage when developers switch to Ivy and fTTC.
PR Close#32057
The Template AST that corresponds to a given HTML AST is not always
complete, and often has to be reconstructed. This commit refactors the
code to make it easier to adapt to multiple cases.
PR Close#34764
Adds a `typeArguments` method to the `Symbol` interface, cleaning up how
type parameters of a TypeScript type are currently found. This will be
necessary for providing completions for `$event` variables' properties
(#34570).
This commit also performs some fly-by cleanups seen while implementing
the `typeArguments` methods. There is more clean up to do in the
`typescript_symbols` file, but the scope of this commit didn't need to
get larger.
PR Close#34571
Currently the language service constructs an `AttrAst` anytime it is
missing from a `TemplateAst` path. However, this should only be done
when the path does not contain an "attribute-like" AST, which can
includes bound properties or bound events.
This commit also refactors `visitAttr` to parse bindings only for
microsyntax expressions and does some other minor cleanup to make
linters happy.
This is some cleanup to help the language service eventually use
`BoundDirectivePropertyAst`s for providing completions for template
bindings rather than performing the manual parsing currently done.
PR Close#34743
DebugElement.query also matches elements that may have been created
outside of Angular (ex: with `document.appendChild`). If those matched
DebugElements are in turn used to query for more elements, an error
occurs because the first step in queryAll is to load the LContext.
PR Close#34687
The locale data extraction has been modified to include the default
currency code in the generated locale data. This commit updates these
generated files accordingly.
PR Close#32584
Default currency code in CurrencyPipe is currently hardcoded to USD
and is not configurable. This commit allows the default currency code
to be configurable by adding a DEFAULT_CURRENCY_CODE injection token.
Example:
```
providers: [{ provide: DEFAULT_CURRENCY_CODE, useValue: "GBP" }]
...
{{ 123.45 | currency }} // outputs £123.45 as opposed to always $123.45 before
```
Closes: #25461
PR Close#32584
Previously, `CommonJsDependencyHost.collectDependencies()` would only
find dependencies via imports of the form `var foo = require('...');` or
`var foo = require('...'), bar = require('...');` However, CommonJS
files can have imports in many different forms. By failing to recognize
other forms of imports, the associated dependencies were missed, which
in turn resulted in entry-points being compiled out-of-order and failing
due to that.
While we cannot easily capture all different types of imports, this
commit enhances `CommonJsDependencyHost` to recognize the following
common forms of imports:
- Imports in property assignments. E.g.:
`exports.foo = require('...');` or
`module.exports = {foo: require('...')};`
- Imports for side-effects only. E.g.:
`require('...');`
- Star re-exports (with both emitted and imported heleprs). E.g.:
`__export(require('...'));` or
`tslib_1.__exportStar(require('...'), exports);`
PR Close#34528
Unlike in View Engine, we currently reset the dirty state of
components in the check no changes change detection cycle.
This means that components cannot be marked as dirty from
view lifecycle hooks because the dirty state is reset and
the lifecycle hooks do not run in the check no changes CD cycle.
PR Close#34495
Currently the decorator handlers are run against all `SourceFile`s in the compilation, but we shouldn't be doing it against declaration files. This initially came up as a CI issue in #33264 where it was worked around only for the `DirectiveDecoratorHandler`. These changes move the logic into the `TraitCompiler` and `DecorationAnalyzer` so that it applies to all of the handlers.
PR Close#34557
This commit removes some test scenarios from `parsing-cases.ts` and
colocate them with the test code instead. This makes the tests easier to
read and understand.
PR Close#34716
This is recommended in the Bazel docs as $(location) is ambiguous and can mean either $(execpath) or $(rootpath) depending on the context.
PR Close#34589
For the purposes of the integration test the zone.js script & bundle script tags can just go into the source index.html itself. The purpose of the integration test is is to test @angular/bazel & ng_module & ng_package so there is no need to exercise html_insert_assets in integration/bazel.
PR Close#34589
The major one that affects the angular repo is the removal of the bootstrap attribute in nodejs_binary, nodejs_test and jasmine_node_test in favor of using templated_args --node_options=--require=/path/to/script. The side-effect of this is that the bootstrap script does not get the require.resolve patches with explicitly loading the targets _loader.js file.
PR Close#34589
This commit renames `addAttributeValuesToCompletions`, which generates
expression completions and is not exclusive to processing attributes, to
`processExpressionCompletions`. Also removes the expression completion
logic in `visitBoundText` for a call to `processExpressionCompletions`.
The conditional branch in `visitBoundText` is also removed. This branch
was added in one of the first commits to the language service
(519a324454) and appears to be
unnecessary, as the expression AST is constructed from the template
position anyway.
PR Close#34518
Previously, the `CommonJsReflectionHost` and `UmdReflectionHost` would
only recognize re-exports of the form `__export(...)`. This is what
re-exports look like, when the TypeScript helpers are emitted inline
(i.e. when compiling with the default [TypeScript compiler options][1]
that include `noEmitHelpers: false` and `importHelpers: false`).
However, when compiling with `importHelpers: true` and [tslib][2] (which
is the recommended way for optimized bundles), the re-exports will look
like: `tslib_1.__exportStar(..., exports)`
These types of re-exports were previously not recognized by the
CommonJS/UMD `ReflectionHost`s and thus ignored.
This commit fixes this by ensuring both re-export formats are
recognized.
[1]: https://www.typescriptlang.org/docs/handbook/compiler-options.html
[2]: https://www.npmjs.com/package/tslib
PR Close#34527
A while ago we made a pass through all instructions to make sure that none of them call directly into other instructions, however it seems like missed the `pipeBind*` since they still call into the pure functions. The result is that we have some unnecessary duplicated accesses of global state like `getLView` which are called twice in a row with nothing changing.
These changes move the common functionality into a shared file and make the pipe instructions call into them with the global state instead.
PR Close#33714
The compiler's `I18NHtmlParser` may expand template nodes that have
internationalization metadata attached to them; for instance,
```html
<div i18n="@@i18n-el">{{}}</div>
```
gets expanded to an AST with the i18n metadata extracted and text filled
in as necessary; to the language service, the template above, as read in
the AST, now looks something like
```html
<div>{{$implicit}}</div>
```
This is undesirable for the language service because we want to preserve
the original form of the source template source code, and have
information about the original values of the template. The language
service also does not need to use an i18n parser -- we don't generate
any template output.
To fix this turns out to be as easy as moving to using a raw
`HtmlParser`.
---
A note on the testing strategy: as mentioned above, we don't need to use
an i18n parser, but we don't **not** need to use one if the parser
does not heavily modify the template AST. For this reason, the tests
target the functionality of not modifying a template with i18n metadata
rather than testing that the language service does not use an i18n parser.
---
Closes https://github.com/angular/vscode-ng-language-service/issues/272
PR Close#34531
With 5cecd97493 we intended to expand
the input type of the `disabled` input of the `NgModel` directive.
Read more about the reason for this in the actual commit message.
Currently though, the acceptance coercion member does not have any
effect. This is because the acceptance member needs to refer to the
actual input property name, and not to the public input name.
`disabled` corresponds to the `isDisabled` property.
PR Close#34502
This commit improves `ExpressionChangedAfterChecked` error message for attributes by including attribute name and the content of the entire expression that contains interpolation(s). In order to achieve that, metadata is now stored in `TData` array when `attribute` and `attributeInterpolate` instructions are being called (similar to `property` and `propertyInterpolate` instructions).
PR Close#34505
If a class was defined as a class expression
in a variable declaration, the definitions
were being inserted before the statment's
final semi-colon.
Now the insertion point will be after the
full statement.
Fixes#34648
PR Close#34677
This was already the default. I'm working on a change in the underlying TS rules where this parameter will be replaced, so ng_module needs to change first
PR Close#34665
In some cases, where a module imports a dependency
but does not actually use it, UMD bundlers may remove
the dependency parameter from the UMD factory function
definition.
For example:
```
import * as x from 'x';
import * as z from 'z';
export const y = x;
```
may result in a UMD bundle including:
```
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ?
factory(exports, require('x'), require('z')) :
typeof define === 'function' && define.amd ?
define(['exports', 'x', 'z'], factory) :
(global = global || self, factory(global.myBundle = {}, global.x));
}(this, (function (exports, x) { 'use strict';
...
})));
```
Note that while the `z` dependency is provide in the call,
the factory itself only accepts `exports` and `x` as parameters.
Previously ngcc appended new dependencies to the end of the factory
function, but this breaks in the above scenario. Now the new
dependencies are prefixed at the front of parameters/arguments
already in place.
Fixes#34653
PR Close#34660
In some cases TypeScript is unable to identify a valid
symbol for an export. In this case it returns an "unknown"
symbol, which does not reference any declarations.
This fix ensures that ngcc does not crash if such a symbol
is encountered by checking whether `symbol.declarations`
exists before accessing it.
The commit does not contain a unit test as it was not possible
to recreate a scenario that had such an "unknown" symbol in
the unit test environment. The fix has been manually checked
against that original issue; and also this check is equivalent to
similar checks elsewhere in the code, e.g.
https://github.com/angular/angular/blob/8d0de89e/packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts#L309Fixes#34560
PR Close#34658
Fixes classes with trailing or leading space that are passed to `ngClass` (e.g. `{'foo ': bar}`) not being applied in Ivy. The issue comes from the fact that when the styling differ builds up the style map it uses the trimmed key to look up the value in the map that uses non-trimmed keys.
Fixes#34476.
PR Close#34539
Follow-up from [this discussion](https://github.com/angular/angular/pull/33419#discussion_r339296216). In Ivy we don't use the schema to validate tag names, but instead we use feature detection to figure out whether an element is supported. While this should generally be more accurate, it'll also end up throwing for some more innocent cases. E.g. now Ivy throws an error for `main` elements in IE which is accurate since IE doesn't support the element, but is annoying since there is no functionality attached.
These changes switch to logging a warning instead, similarly to what we're doing for unknown properties.
PR Close#34524
Previously, in cases were values were expensive to compute and would be
used multiple times, a combination of a regular `Map` and a helper
function (`getOrDefault()`) was used to ensure values were only computed
once.
This commit uses a special `Map`-like structure to compute and memoize
such expensive values without the need to a helper function.
PR Close#34512
This change should not have any impact on the code's behavior (based on
how the function is currently used), but it will avoid unnecessary work.
PR Close#34512
While different, CommonJS and UMD have a lot in common regarding the
their exports are constructed. Therefore, there was some code
duplication between `CommonJsReflectionHost` and `UmdReflectionHost`.
This commit extracts some of the common bits into a separate file as
helpers to allow reusing the code in both `ReflectionHost`s.
PR Close#34512
Previously, `UmdReflectionHost` would only recognize re-exports of the
form `__export(someIdentifier)` and not `__export(require('...'))`.
However, it is possible in some UMD variations to have the latter format
as well. See discussion in https://github.com/angular/angular/pull/34254/files#r359515373
This commit adds support for re-export of the form
`__export(require('...'))` in UMD.
PR Close#34512
This fix was part of a broader `ngtsc`/`ngcc` fix in 02bab8cf9 (see
there for details). In 02bab8cf9, the fix was only applied to
`CommonJsReflectionHost`, but it is equally applicable to
`UmdReflectionHost`. Later in #34254, the fix was partially ported to
`UmdReflectionHost` by fixing the `extractUmdReexports()` method.
This commit fully fixes `ngcc`'s handling of inline exports for code in
UMD format.
PR Close#34512
The `getProjectAsAttrValue` in `node_selector_matcher` finds the
ProjectAs marker and then additionally checks that the marker appears in
an even index of the node attributes because "attribute names are stored
at even indexes". This is true for "regular" attribute bindings but
classes, styles, bindings, templates, and i18n do not necessarily follow
this rule because there can be an uneven number of them, causing the
next "special" attribute "name" to appear at an odd index. To address
this issue, ensure ngProjectAs is placed right after "regular"
attributes.
PR Close#34617
Previously, if `UmdRenderingFormatter#addImports()` was called with an
empty list of imports to add (i.e. no new imports were needed), it would
add trailing commas in several locations (arrays, function arguments,
function parameters), thus making the code imcompatible with legacy
browsers such as IE11.
This commit fixes it by ensuring that no trailing commas are added if
`addImports()` is called with an empty list of imports.
This is a follow-up to #34353.
Fixes#34525
PR Close#34545
ngcc computes a dependency graph of entry-points to ensure that
entry-points are processed in the correct order. Previously only the imports
in source files were analysed to determine the dependencies for each
entry-point.
This is not sufficient when an entry-point has a "type-only" dependency
- for example only importing an interface from another entry-point.
In this case the "type-only" import does not appear in the
source code. It only appears in the typings files. This can cause a
dependency to be missed on the entry-point.
This commit fixes this by additionally processing the imports in the
typings program, as well as the source program.
Note that these missing dependencies could cause unexpected flakes when
running ngcc in async mode on multiple processes due to the way that
ngcc caches files when they are first read from disk.
Fixes#34411
// FW-1781
PR Close#34494
The `DependencyHost` implementations were duplicating the "postfix" strings
which are used to find matching paths when resolving module specifiers.
Now the hosts reuse the postfixes given to the `ModuleResolver` that is
passed to the host.
PR Close#34494
Rather than return a new object of dependency info from calls to
`collectDependencies()` we now pass in an object that will be updated
with the dependency info. This is in preparation of a change where
we will collect dependency information from more than one
`DependencyHost`.
Also to better fit with this approach the name is changed from
`findDependencies()` to `collectDependencies()`.
PR Close#34494
Prior to this commit, there were no `advance` instructions generated before `i18nExp` instructions and as a result, lifecycle hooks for components used inside i18n blocks were flushed too late. This commit adds the logic to generate `advance` instructions in front of `i18nExp` ones (similar to what we have in other places like interpolations, property bindings, etc), so that the necessary lifecycle hooks are flushed before expression value is captured.
PR Close#34436
The main logic of the `InheritDefinitionFeature` is to go through the prototype chain of a given Component and merge all Angular-specific information onto that Component def. The problem happens in case there is a Component in a hierarchy that also contains the `InheritDefinitionFeature` (i.e. it extends some other Component), so it inherits all Angular-specific information from its super class. As a result, the root Component may end up having duplicate information inherited from different Components in hierarchy.
Let's consider the following structure: `GrandChild` extends `Child` that extends `Base` and the `Base` class has a `HostListener`. In this scenario `GrandChild` and `Child` will have `InheritDefinitionFeature` included into the `features` list. The processing will happend in the following order:
- `Child` inherits `HostListener` from the `Base` class
- `GrandChild` inherits `HostListener` from the `Child` class
- since `Child` has a parent, `GrandChild` also inherits from the `Base` class
The result is that the `GrandChild` def has duplicated host listener, which is not correct.
This commit introduces additional logic that checks whether we came across a def that has `InheritDefinitionFeature` feature (which means that this def already inherited information from its super classes). If that's the case, we skip further fields-related inheritance logic, but keep going though the prototype chain to look for super classes that contain other features (like NgOnChanges), that we need to invoke for a given Component def.
PR Close#34244
Fixes an error that is thrown when a provider is overridden in `TestBed`, if the module definition of one of the imported modules uses a function for the `imports` that is set via `setNgModuleScope`. The problem was that we have a `for...of` loop that assumes that the imports are an array, but they can also be a function. This was handled correctly in other places, but this one was missed.
Note that the above-mentioned error is only thrown at runtime when the code is transpiled to es6. In es5 TS generates a call to a helper that handles the error silently so the attached unit test only fails in es6.
Fixes#34623.
PR Close#34629
Currently, the language service provides completions in a template node
attribute by first checking if the attribute contains template bindings
to provide completions for, and then providing completions for the
expression in the attribute.
In the latter case, the expression AST was being constructed
"synthetically" inside the language service, in particular declaring the
expression to be a `PropertyRead` with an implicit receiver.
Unfortunately, this AST can be incorrect if the expression is actually a
property read on a component property receiver (e.g. when reading
`key` in the expression `obj.key`, `obj` is the receiver).
The fix is pretty simple - rather than a synthetic construction of the
AST, ask the expression parser to parse the expression in the attribute.
Fixes https://github.com/angular/vscode-ng-language-service/issues/523
PR Close#34517
Previously, it was required that both `fullTemplateTypeCheck` and
`strictTemplates` had to be enabled for strict mode to be enabled. This
is strange, as `strictTemplates` implies `fullTemplateTypeCheck`. This
commit makes setting the `fullTemplateTypeCheck` flag optional so that
strict mode can be enabled by just setting `strictTemplates`.
PR Close#34195
It is now an error if '"fullTemplateTypeCheck"' is disabled while
`"strictTemplates"` is enabled, as enabling the latter implies that the
former is also enabled.
PR Close#34195
The compiler has a translation mechanism to convert from an Angular
`Type` to a `ts.TypeNode`, as appropriate. Prior to this change, it
would translate certain Angular expressions into their value equivalent
in TypeScript, instead of the correct type equivalent. This was possible
as the `ExpressionVisitor` interface is not strictly typed, with `any`s
being used for return values.
For example, a literal object was translated into a
`ts.ObjectLiteralExpression`, containing `ts.PropertyAssignment` nodes
as its entries. This has worked without issues as their printed
representation is identical, however it was incorrect from a semantic
point of view. Instead, a `ts.TypeLiteralNode` is created with
`ts.PropertySignature` as its members, which corresponds with the type
declaration of an object literal.
PR Close#34021
In Ivy's template type checker, type constructors are created for all
directive types to allow for accurate type inference to work. The type
checker has two strategies for dealing with such type constructors:
1. They can be emitted local to the type check block/type check file.
2. They can be emitted as static `ngTypeCtor` field into the directive
itself.
The first strategy is preferred, as it avoids having to update the
directive type which would cause a more expensive rebuild. However, this
strategy is not suitable for directives that have constrained generic
types, as those constraints would need to be present on the local type
constructor declaration. This is not trivial, as it requires that any
type references within a type parameter's constraint are imported into
the local context of the type check block.
For example, lets consider the `NgForOf` directive from '@angular/core'
looks as follows:
```typescript
import {NgIterable} from '@angular/core';
export class NgForOf<T, U extends NgIterable<T>> {}
```
The type constructor will then have the signature:
`(o: Pick<i1.NgForOf<T, U>, 'ngForOf'>) => i1.NgForOf<T, U>`
Notice how this refers to the type parameters `T` and `U`, so the type
constructor needs to be emitted into a scope where those types are
available, _and_ have the correct constraints.
Previously, the template type checker would detect the situation where a
type parameter is constrained, and would emit the type constructor
using strategy 2; within the directive type itself. This approach makes
any type references within the generic type constraints lexically
available:
```typescript
export class NgForOf<T, U extends NgIterable<T>> {
static ngTypeCtor<T = any, U extends NgIterable<T> = any>
(o: Pick<NgForOf<T, U>, 'ngForOf'>): NgForOf<T, U> { return null!; }
}
```
This commit introduces the ability to emit a type parameter with
constraints into a different context, under the condition that it can
be imported from an absolute module. This allows a generic type
constructor to be emitted into a type check block or type check file
according to strategy 1, as imports have been generated for all type
references within generic type constraints. For example:
```typescript
import * as i0 from '@angular/core';
import * as i1 from '@angular/common';
const _ctor1: <T = any, U extends i0.NgIterable<T> = any>
(o: Pick<i1.NgForOf<T, U>, 'ngForOf'>) => i1.NgForOf<T, U> = null!;
```
Notice how the generic type constraint of `U` has resulted in an import
of `@angular/core`, and the `NgIterable` is transformed into a qualified
name during the emitting process.
Resolves FW-1739
PR Close#34021
In the past, only the starting index of an expression Token has been
recorded, so a parser could demarkate the span of a token only by the
start locations of two tokens. This may lead to trailing whitespace
being included in the token span:
```html
{{ token1 + token2 }}
^^^^^^^^^ recorded span of `token1`
```
It's also not enough for a parser to determine the end of a token by
adding the length of the token value to the token's start location,
because lexed expression values may not exactly reflect the source code.
For example, `"d\\"e"` is lexed as a string token whose value is `d"e`.
Instead, this commit adds a `end` field to expression tokens. `end`
is one past the last index of the token source code. This will enable a
parser to determine the span of a token just by looking at that token.
This is a breaking change because the contructor interface of `Token`
has changed.
Part of #33477.
PR Close#33549
This commit fixes a bug in which we do testing for completions.
Subsequently, this exposes another bug in our implementation whereby
suggestions are not provided in "ngFor" where there should have been.
Currently, multiple test cases are grouped together in a single
template. This requires the template to be somewhat complete so that
test cases that depend on variables declared earlier would pass.
Consider the following example:
```
template: `
<div *ngFor="let ~{for-person}person of ~{for-people}people">
<span>Name: {{~{for-interp-person}person.~{for-interp-name}name}}</span>
<span>Age: {{person.~{for-interp-age}age}}</span>
</div>`,
```
In order to test `~{for-interp-person}`, `people` has to be included after
`~{for-people}`. This means the test case for `~{for-people}` is not
reflective of the actual use case because the variable is already there!
In real case, the expression would be incomplete, and our implementation
failed to take that into account.
This commit breaks such test into individual tests, and fix the bugs in
the underlying implementation.
PR Close#34473
Angular View Engine uses global knowledge to compile the following code:
```typescript
export class Base {
constructor(private vcr: ViewContainerRef) {}
}
@Directive({...})
export class Dir extends Base {
// constructor inherited from base
}
```
Here, `Dir` extends `Base` and inherits its constructor. To create a `Dir`
the arguments to this inherited constructor must be obtained via dependency
injection. View Engine is able to generate a correct factory for `Dir` to do
this because via metadata it knows the arguments of `Base`'s constructor,
even if `Base` is declared in a different library.
In Ivy, DI is entirely a runtime concept. Currently `Dir` is compiled with
an ngDirectiveDef field that delegates its factory to `getInheritedFactory`.
This looks for some kind of factory function on `Base`, which comes up
empty. This case looks identical to an inheritance chain with no
constructors, which works today in Ivy.
Both of these cases will now become an error in this commit. If a decorated
class inherits from an undecorated base class, a diagnostic is produced
informing the user of the need to either explicitly declare a constructor or
to decorate the base class.
PR Close#34460
Adds a compilation error if the consumer tries to pass in an undecorated class into the `providers` of an `NgModule`, or the `providers`/`viewProviders` arrays of a `Directive`/`Component`.
PR Close#34460
The function `makeTemplateDiagnostic` was accepting an error code of type
`number`, making it easy to accidentally pass an `ErrorCode` directly and
not convert it to an Angular diagnostic code first.
This commit refactors `makeTemplateDiagnostic` to accept `ErrorCode` up
front, and convert it internally. This is less error-prone.
PR Close#34460
Previously, ngtsc would perform scope analysis (which directives/pipes are
available inside a component's template) and template type-checking of that
template as separate steps. If a component's scope was somehow invalid (e.g.
its NgModule imported something which wasn't another NgModule), the
component was treated as not having a scope. This meant that during template
type-checking, errors would be produced for any invalid expressions/usage of
other components that should have been in the scope.
This commit changes ngtsc to skip template type-checking of a component if
its scope is erroneous (as opposed to not present in the first place). Thus,
users aren't overwhelmed with diagnostic errors for the template and are
only informed of the root cause of the problem: an invalid NgModule scope.
Fixes#33849
PR Close#34460
Previously each NgModule trait checked its own scope for valid declarations
during 'resolve'. This worked, but caused the LocalModuleScopeRegistry to
declare that NgModule scopes were valid even if they contained invalid
declarations.
This commit moves the generation of diagnostic errors to the
LocalModuleScopeRegistry where it belongs. Now the registry can consider an
NgModule's scope to be invalid if it contains invalid declarations.
PR Close#34460
The template type checker generates TypeScript expressions for any
expression that occurs in a template, so that TypeScript can check it
and produce errors. Some expressions as they occur in a template may be
translated into TypeScript code multiple times, for instance a binding
to a directive input that has a template guard.
One example would be the `NgIf` directive, which has a template guard to
narrow the type in the template as appropriate. Given the following
template:
```typescript
@Component({
template: '<div *ngIf="person">{{ person.name }}</div>'
})
class AppComponent {
person?: { name: string };
}
```
A type check block (TCB) with roughly the following structure is
created:
```typescript
function tcb(ctx: AppComponent) {
const t1 = NgIf.ngTypeCtor({ ngIf: ctx.person });
if (ctx.person) {
"" + ctx.person.name;
}
}
```
Notice how the `*ngIf="person"` binding is present twice: once in the
type constructor call and once in the `if` guard. As such, TypeScript
will check both instances and would produce duplicate errors, if any
were found.
Another instance is when the safe navigation operator is used, where an
expression such as `person?.name` is emitted into the TCB as
`person != null ? person!.name : undefined`. As can be seen, the
left-hand side expression `person` occurs twice in the TCB.
This commit adds the ability to insert markers into the TCB that
indicate that any errors within the expression should be ignored. This
is similar to `@ts-ignore`, however it can be applied more granularly.
PR Close#34417
Previously, the type checker would compute an absolute source span by
combining an expression AST node's `ParseSpan` (relative to the start of
the expression) together with the absolute offset of the expression as
represented in a `ParseSourceSpan`, to arrive at a span relative to the
start of the file. This information is now directly available on an
expression AST node in the `AST.sourceSpan` property, which can be used
instead.
PR Close#34417
Now that the source to typings matching is able to handle
aliasing of exports, there is no need to handle aliases in private
declarations analysis.
These were originally added to cope when the typings files had
to use the name that the original source files used when exporting.
PR Close#34254
Previously the identifiers used in the typings files were the same as
those used in the source files.
When the typings files and the source files do not match exactly, e.g.
when one of them is flattened, while the other is a deep tree, it is
possible for identifiers to be renamed.
This commit ensures that the correct identifier is used in typings files
when the typings file does not export the same name as the source file.
Fixes https://github.com/angular/ngcc-validation/pull/608
PR Close#34254
The naïve matching algorithm we previously used to match declarations in
source files to declarations in typings files was based only on the name
of the thing being declared. This did not handle cases where the declared
item had been exported via an alias - a common scenario when one of the two
file sets (source or typings) has been flattened, while the other has not.
The new algorithm tries to overcome this by creating two maps of export
name to declaration (i.e. `Map<string, ts.Declaration>`).
One for the source files and one for the typings files.
It then joins these two together by matching export names, resulting in a
new map that maps source declarations to typings declarations directly
(i.e. `Map<ts.Declaration, ts.Declaration>`).
This new map can handle the declaration names being different between the
source and typings as long as they are ultimately both exported with the
same alias name.
Further more, there is one map for "public exports", i.e. exported via the
root of the source tree (the entry-point), and another map for "private
exports", which are exported from individual files in the source tree but
not necessarily from the root. This second map can be used to "guess"
the mapping between exports in a deep (non-flat) file tree, which can be
used by ngcc to add required private exports to the entry-point.
Fixes#33593
PR Close#34254
In TS we can re-export imports using statements of the form:
```
export * from 'some-import';
```
This is downleveled in UMD to:
```
function factory(exports, someImport) {
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
__export(someImport);
}
```
This commit adds support for this.
PR Close#34254
In TS we can re-export imports using statements of the form:
```
export * from 'some-import';
```
This can be downleveled in CommonJS to either:
```
__export(require('some-import'));
```
or
```
var someImport = require('some-import');
__export(someImport);
```
Previously we only supported the first downleveled version.
This commit adds support for the second version.
PR Close#34254
Previously individual properties of the src bundle program were
passed to the reflection host constructors. But going forward,
more properties will be required. To prevent the signature getting
continually larger and more unwieldy, this change just passes the
whole src bundle to the constructor, allowing it to extract what it
needs.
PR Close#34254
When a HTML Ast containing an Attribute node is converted to a Template Ast,
the attribute node might get dropped from the Template Ast path.
This is because the AttrNode is not even in the Template Ast to begin with.
In this case, we manually fix the path by converting the Attribute node
to a AttrAst node and appending it to the path.
This allows the `ExpressionVisitor` to properly visit the leaf node in the
TemplateAst path. We no longer need to visit the `Element` and look for
attributes.
PR Close#34459
Prior to this change, the ExpressionChangedAfterChecked error thrown in Ivy was missing useful information that was available in View Engine, specifically: missing property name for proprty bindings and also the content of the entire property interpolation (only a changed value was displayed) if one of expressions was changed unexpectedly. This commit improves the error message by including the mentioned information into the error text.
PR Close#34381
Previously, bound events were incorrectly bound to directives with
inputs matching the bound event attribute. This fixes that so bound
events can only be bound to directives with matching outputs.
Adds tests for all kinds of directive matching on bound attributes.
PR Close#31938
This is not expected to have any noticeable perf impact, but it wasteful
nonetheless (and annoying when stepping through the code while debugging
`ngtsc`/`ngcc`).
PR Close#34441
This commit adds three previously missing validations to
NgModule.declarations:
1. It checks that declared classes are actually within the current
compilation.
2. It checks that declared classes are directives, components, or pipes.
3. It checks that classes are declared in at most one NgModule.
PR Close#34404