When the template type checker try to get a symbol of a template node, it will
not return the directives intended for an element on a microsyntax template,
for example, `<div *ngFor="let user of users;" dir>`, the `dir` will be skipped,
but it's needed in language service.
Fixes https://github.com/angular/vscode-ng-language-service/issues/1420
PR Close#42640
As of ES2021, JavaScript allows using underscores as separators inside numbers, in order to make them more readable (e.g. `1_000_000` vs `1000000`). TypeScript has had support for separators for a while so these changes expand the template parser to handle them as well.
PR Close#42672
The previous default algorithm was `md5`, which is not compliant with FIPS.
The default is now set to `sha256`, which is compliant.
Fixes#42577
PR Close#42582
The hash algorithm for the entry-point manifest was hardcoded to `md5`.
This can now be configured by the `hashAlgorithm` property on the
ngcc.config.js project configuration.
PR Close#42582
The ngcc configuration gets hashed to be used when caching
but it was hardcoded to use the `md5` algorithm, which is
not FIPS compliant.
Now the hash algorithm can be configured in the ngcc.config.js
file at the project level.
PR Close#42582
Adds support for shorthand property declarations inside Angular templates. E.g. doing `{foo, bar}` instead of `{foo: foo, bar: bar}`.
Fixes#10277.
PR Close#42421
Previously, the template type checker would only opt-in to inline type
constructors if it could import all type references from absolute module
specifiers. This limitation was put into place in an abundance of
caution as there was a safe, but less performant, fallback available.
The language service is not capable of using this fallback, which now
means that the limitation of absolute module specifiers limits the
language service's ability to use accurate types for component/directive
classes that have generic type parameters.
This commit loosens the restriction such that type references are now
eligible for emit as long as they are exported.
PR Close#42492
When a component/directive has a generic type parameter, the template
type checker attempts to translate the type parameter such that the
type parameters can be replicated in the type constructor that is
emitted into the typecheck file.
Type parameters with a default clause would incorrectly be emitted into
the typecheck file using the original `ts.TypeNode` for the default
clause, such that `ts.TypeReferenceNode`s within the default clause
would likely be invalid (i.e. referencing a type for which no import is
present in the typecheck file). This did not result in user-facing
type-check errors as errors reported in type constructors are not
translated into template positions Regardless, this commit ensures that
`ts.TypeReferenceNode`s within defaults are properly translated into the
typecheck file.
PR Close#42492
The template type checker is capable of recreating generic type bounds
in a different context, rewriting type references along the way (if
possible). This was previously done using a visitor that only supported
a limited set of types, resulting in the inability to emit all sorts of
types (even if they don't contain type references at all).
The inability to emit generic type bounds was not critical when the type
parameter emitting logic was introduced, as the compiler also has a
fallback strategy of creating inline type constructors. However, this
fallback is not available to the language service, resulting in
inaccurate types when components/directives use a complex generic type.
To mitigate this problem, the specialized visitor has been replaced with
a generalized TypeScript transform, where only type references get
special treatment. This allows for more complex types to be emitted,
such as union and intersection types, object literal types and tuple
types.
PR Close#42492
If an implcit receiver is accessed in a listener inside of an `ng-template`, we generate some extra code in order to ensure that we're assigning to the correct object. The problem is that the logic wasn't covering keyed writes which caused it to write to the wrong object and throw an assertion error at runtime.
These changes expand the logic to cover keyed writes.
Fixes#41267.
PR Close#42603
xi18n is the operation of extracting i18n messages from templates in the
compilation. Previously, only View Engine was able to perform xi18n. This
commit implements xi18n in the Ivy compiler, and a copy of the View Engine
test for Ivy verifies that the results are identical.
PR Close#42485
This commit moves some xi18n-related functions in the View Engine
ng.Program into a new file. This is necessary in order to depend on them
from the Ivy ng.Program while avoiding a cycle.
PR Close#42485
In watch builds, the compiler attempts to reuse as much information from
a prior compilation as possible. To accomplish this, it keeps a
reference to the most recently succeeded `TraitCompiler`, which contains
all analysis data for the program. However, `TraitCompiler` has an
internal reference to an `IncrementalBuild`, which is itself built on
top of its prior state. Consequently, all prior compilations continued
to be referenced, preventing garbage collection from cleaning up these
instances.
This commit changes the `AnalyzedIncrementalState` to no longer retain
a `TraitCompiler` instance, but only the analysis data it contains. This
breaks the retainer path to the prior incremental state, allowing it to
be garbage collected.
PR Close#42537
This is based on a discussion we had a few weeks ago. Currently if a component uses `ViewEncapsulation.ShadowDom` and its selector doesn't meet the requirements for a custom element tag name, a vague error will be thrown at runtime saying something like "Element does not support attachShadowRoot".
These changes add a new diagnostic to the compiler that validates the component selector and gives a better error message during compilation.
PR Close#42245
For quite a while it is an unspoken convention to add a trailing
new-line files within the Angular repository. This was never enforced
automatically, but has been frequently raised in pull requests through
manual review. This commit sets up a lint rule so that this is
"officially" enforced and doesn't require manual review.
PR Close#42478
Updates the compiler-cli compliance goldens. The golden updates are
required due to a regression in TypeScript 4.3 that causes the emitter
to not incorrectly preserve lines when emitting a node list.
This can be reverted once https://github.com/microsoft/TypeScript/pull/44070
is available.
PR Close#42022
Switches the repository to TypeScript 4.3 and the latest
version of tslib. This involves updating the peer dependency
ranges on `typescript` for the compiler CLI and for the Bazel
package. Tests for new TypeScript features have been added to
ensure compatibility with Angular's ngtsc compiler.
PR Close#42022
Currently we support safe property (`a?.b`) and method (`a?.b()`) accesses, but we don't handle safe keyed reads (`a?.[0]`) which is inconsistent. These changes expand the compiler in order to support safe key read expressions as well.
PR Close#41911
With the removal of the `ModuleWithProviders` transform in the parent commit,
the underlying dts transform can also be removed as it is not used elsewhere.
PR Close#41996
The `ModuleWithProviders` type has required a generic type since Angular 10,
so it is no longer necessary for the compiler to transform usages of the
`ModuleWithProviders` type without the generic type, as that should have
been reported as a compile error. This commit removes the detection logic
from ngtsc.
PR Close#41996
When a `trackBy` function is used that accepts a supertype of the iterated
array's type, the loop variable would undesirably be inferred as the supertype
instead of the array's item type. This commit adds an inferred type parameter
to `TrackByFunction` to allow an extra degree of freedom, enabling the
loop value to be inferred as the most narrow type.
Fixes#40125
PR Close#41995
The ngtsc test targets have fake declarations files for `@angular/core`
and `@angular/common` and the template type checking tests can leverage
the fake common declarations instead of declaring its own types.
PR Close#41995
Type-only imports are known to be elided by TypeScript, so the compiler
can be certain that such imports do not contribute to potential import
cycles. As such, type-only imports are no longer considered during cycle
analysis.
Regular import statements that would eventually be fully elided by
TypeScript during emit if none of the imported symbols are used in a
value position continue to be included in the cycle analysis, as the
cycle analyzer is unaware of these elision opportunities. Only explicit
`import type` statements are excluded.
PR Close#42453
The compiler flag `compileNonExportedClasses` allows the Angular compiler to
process classes which are not exported at the top level of a source file.
This is often used to allow for AOT compilation of test classes inside
`it()` test blocks, for example.
Previously, the compiler would identify exported classes by looking for an
`export` modifier on the class declaration itself. This works for the
trivial case, but fails for indirectly exported classes:
```typescript
// Component is declared unexported.
@Component({...})
class FooCmp {...}
// Indirect export of FooCmp
export {FooCmp};
```
This is not an immediate problem for most application builds, since the
default value for `compileNonExportedClasses` is `true` and therefore such
classes get compiled regardless.
However, in the Angular Language Service now, `compileNonExportedClasses` is
forcibly overridden to `false`. That's because the tsconfig used by the IDE
and Language Service is often far broader than the application build's
configuration, and pulls in test files that can contain unexported classes
not designed with AOT compilation in mind.
Therefore, the Language Service has trouble working with such structures.
In this commit, the `ReflectionHost` gains a new API for detecting whether a
class is exported. The implementation of this method now not only considers
the `export` modifier, but also scans the `ts.SourceFile` for indirect
exports like the example above. This ensures the above case will be
processed directly in the Language Service.
This new operation is cached using an expando symbol on the `ts.SourceFile`,
ensuring good performance even when scanning large source files with lots of
exports (e.g. a FESM file under `ngcc`).
Fixes#42184.
PR Close#42207
Update the supported range of node versions for to be less restrictive, no longer causing
yarn or npm to fail engine's checks for future versions of node.
While this change will no longer cause yarn or npm to fail these engine's check, this does
not reflect a change in the officially supported versions of node for Angular. Angular
continues to maintain support for Active LTS and Maintenance LTS versions of node.
PR Close#42205
Remove publishConfig property from the package.json entry for each of the entries in
the publish configuration. Using the wombat proxy is now ensured/managed by the
ng-dev release tooling.
PR Close#42104
Now that there is no need to work around the source-map bug in TypeScript
(https://github.com/Microsoft/TypeScript/issues/29300) we can just use
`resolvedTemplateUrl` for the source-map URL, rather than having a separate
property.
PR Close#42000
Indirect templates are templates produced by a non-literal expression value
of the `template` field in `@Component`. The compiler can statically
determine the template string, but there is not guaranteed to be a physical
file which contains the bytes of the template string. For example, the
template string may be computed by a concatenation expression: 'a' + 'b'.
Previously, the compiler would use the TS file path as the source map path
for indirect templates. This is incorrect, however, and breaks source
mapping for such templates, since the offsets within the template string do
not correspond to bytes of the TS file.
This commit returns the compiler to its old behavior for indirect templates,
which is to use `''` as the source map URL for such templates.
Fixes#40854
PR Close#41973
When `checkTypeOfPipes` is set to `false`, our TCB currently generates
the a statement like the following when pipes appear in the template:
`(_pipe1 as any).transform(args)`
This did enable us to get _some_ information from the Language Service
about pipes in this case because we still had access to the pipe
instance. However, because it is immediately cast to `any`, we cannot
get type information about the transform access. That means actions like "go to
definition", "find references", "quick info", etc. will return
incomplete information or fail altogether.
Instead, this commit changes the TCB to generate `(_pipe1.transform as any)(args)`.
This gives us the ability to get complete information for the LS
operations listed above.
PR Close#40523
This commit updates the logic in the LS renaming to handle renaming of
pipes, both from the name expression in the pipe metadata as well as
from the template.
The approach here is to introduce a new concept for renaming: an
"indirect" rename. In this type of rename, we find rename locations
in with the native TS Language Service using a different node than the
one we are renaming. Using pipes as an example, if we want to rename the
pipe name from the string literal expression, we use the transform
method to find rename locations rather than the string literal itself
(which will not return any results because it's just a string).
So the general approach is:
* Determine the details about the requested rename location, i.e. the
targeted template node and symbol for a template rename, or the TS
node for a rename outside a template.
* Using the details of the location, determine if the node is attempting
to rename something that is an indirect rename (pipes, selectors,
bindings). Other renames are considered "direct" and we use whatever
results the native TSLS returns for the rename locations.
* In the case of indirect renames, we throw out results that do not
appear in the templates (in this case, the shim files). These results will be
for the "indirect" rename that we don't want to touch, but are only
using to find template results.
* Create an additional rename result for the string literal expression
that is used for the input/output alias, the pipe name, or the
selector.
Note that renaming is moving towards being much more accurate in its
results than "find references". When the approach for renaming
stabilizes, we may want to then port the changes back to being shared
with the approach for retrieving references.
PR Close#40523
This allows the linker to be used as a true Babel plugin. In a Babel
configuration file, include the linker as follows:
```js
{
plugins: [
'@angular/compiler-cli/linker/babel',
]
}
```
or, if you need to specify configuration options:
```js
{
plugins: [
['@angular/compiler-cli/linker/babel', {linkerJitMode: true}],
]
}
```
PR Close#41918
This commit changes the reference emitters in the Ivy compiler to prefer
non-aliased exports if they exist. This avoids selecting "private
exports" that may not be stable, e.g. the reexports that have been added
by the View Engine compiler. Such reexports are not stable and are
therefore not suitable to be emitted into partial compilations, as the
output of partial compilations should only reference stable symbols
from upstream libraries.
An alternative solution has been considered where ViewEngine-generated
exports would gain a certain prefix, such that the Ivy compiler could
just exclude those exports (see #41443). However, that solution would
be insufficient in case a library is built using partial compilation and
while depending itself on a VE-compiled library from earlier versions of
Angular, where the magic prefix would be missing. For such libraries,
ngcc would have generated reexports using the declared name if not already
present so this change does result in choosing the correct export.
Because ngcc always generates reexports using the declared name even if
an aliased export is present, this change causes those ngcc-generated
exports to be chosen in downstream libraries using partial compilation.
This is unfortunate as it means that the declared names become
effectively public even if the library author was intentionally
exporting it using an alias. This commit does not address this problem;
it is expected that this should not result in widespread issues across
the library ecosystem.
Fixes#41277
PR Close#41866
Some partial libraries have been minified, which results in the declaration
calls being being converted from property accesses to indexed accesses.
This commit ensures that the linker can process these calls.
Fixes#41655
PR Close#41747
Some partial libraries have been minified, which results in boolean literals
being converted to `!0` and `!1`. This commit ensures that the linker can
process these values.
Fixes#41655
PR Close#41747
We have a check that determines whether to generate property binding instructions for an `ng-template`. The check looks at whether the tag name is exactly `ng-template`, but the problem is that if the tag is placed in a non-HTML namespace (e.g. `svg`), the tag name will actually be `:namespace:ng-template` and the check will fail.
These changes resolve the issue by looking at the tag name without the namespace.
Fixes#41308.
PR Close#41669
Currently if a component defines a template inline, but not through a
string literal, the partial compilation references the template expression
as is. This is problematic because the component declaration can no longer
be processed by the linker later as there is no static interpretation. e.g.
```js
const myTemplate = `...`;
TestCmp.ɵcmp = i0.ɵɵngDeclareComponent({
version: "0.0.0-PLACEHOLDER",
type: TestCmp,
selector: "test-cmp",
ngImport: i0,
template: myTemplate,
isInline: true
});
```
To fix this, we use the the resolved template in such cases so that
the linker can process the template/component declaration as expected.
PR Close#41583
With the introduction of the partial compilation, the Angular compiler's
existing `parseTemplate` method has been extended to pass through multiple
properties purely in favor of the partial compilation.
e.g. the `parseTemplate` function now accepts an "option" called `isInline`.
This option is just passed through and returned as part of the `ParsedTemplate`.
This is not ideal because the `parseTemplate` function doesn't care
whether the specified template was inline or not. This commit cleans
up the `parseTemplate` compiler function so that nothing needed only
for the partial compilation is added to it.
We introduce a new struct for additional template information that
is specific to the generation of the `declareComponent` function. With
that change, we can simplify the component decorator handler and keep
logic more local.
PR Close#41583