The `ngInjectableDef` property was renamed to `ɵprov`, but core must
still support both because there are published libraries that use the
older term.
We are only interested in such properties that are defined directly on
the type being injected, not on base classes. So there is a check that
the defintion is specifically for the given type.
Previously if you tried to inject a class that had `ngInjectableDef` but
also inherited `ɵprov` then the check would fail on the `ɵprov` property
and never even try the `ngInjectableDef` property resulting in a failed
injection.
This commit fixes this by attempting to find each of the properties
independently.
Fixes https://github.com/angular/ngcc-validation/pull/526
PR Close#33732
Chains multiple listener instructions on a particular element into a single call which results in less generated code. Also handles listeners on templates, host listeners and synthetic host listeners.
PR Close#33720
Previously the renderers were fixed so that they inserted extra
"adjacent" statements after the last static property of classes.
In order to help the build-optimizer (in Angular CLI) to be able to
tree-shake classes effectively, these statements should also appear
after any helper calls, such as `__decorate()`.
This commit moves the computation of this positioning into the
`NgccReflectionHost` via the `getEndOfClass()` method, which
returns the last statement that is related to the class.
FW-1668
PR Close#33689
Similar to https://github.com/angular/angular/pull/33633, this commit is
needed to fix an outage with the Angular Kythe indexer.
Crash logs:
```
TypeError: Cannot read property 'text' of undefined
at NodeObject.getFullText (typescript/stable/lib/typescript.js:121443:57)
at FactoryGenerator.generate (angular2/rc/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts:67:34)
at GeneratedShimsHostWrapper.getSourceFile (angular2/rc/packages/compiler-cli/src/ngtsc/shims/src/host.ts:88:26)
at findSourceFile (typescript/stable/lib/typescript.js:90654:29)
at typescript/stable/lib/typescript.js:90553:85
at getSourceFileFromReferenceWorker (typescript/stable/lib/typescript.js:90520:34)
at processSourceFile (typescript/stable/lib/typescript.js:90553:13)
at processRootFile (typescript/stable/lib/typescript.js:90383:13)
at typescript/stable/lib/typescript.js:89399:60
at Object.forEach (typescript/stable/lib/typescript.js:280:30)
```
PR Close#33660
When ngcc is configured to generate reexports for a package using the
`generateDeepReexports` configuration option, it could incorrectly
render the reexports as often as the number of compiled classes in the
declaration file. This would cause compilation errors due to duplicated
declarations.
PR Close#33658
When the Angular compiler is operated through the ngc binary in watch
mode, changing a template in an external file would not cause the
component to be recompiled if Ivy is enabled.
There was a problem with how a cached compiler host was present that was
unaware of the changed resources, therefore failing to trigger a
recompilation of a component whenever its template changes. This commit
fixes the issue by ensuring that information about modified resources is
correctly available to the cached compiler host.
Fixes#32869
PR Close#33551
When template type checking is configured with `strictDomEventTypes` or
`strictOutputEventTypes` disabled, in compilation units that have
`noImplicitAny` enabled but `strictNullChecks` disabled, a template type
checking error could be produced for certain event handlers.
The error is avoided by letting an event handler in the generated TCB
always have an explicit `any` return type.
Fixes#33528
PR Close#33550
We already have special cases for the `__spread` helper function and with this change we handle the new tslib helper introduced in version 1.10 `__spreadArrays`.
For more context see: https://github.com/microsoft/tslib/releases/tag/1.10.0Fixes: #33614
PR Close#33617
This commit fixes a crash in the Angular Kythe indexer caused by failure
to retrieve `SourceFile` in a `Statement`.
Crash logs:
TypeError: Cannot read property 'text' of undefined
at Object.getTokenPosOfNode (typescript/stable/lib/typescript.js:8957:72)
at NodeObject.getStart (typescript/stable/lib/typescript.js:121419:23)
at NodeObject.getLeadingTriviaWidth (typescript/stable/lib/typescript.js:121439:25)
at FactoryGenerator.generate (angular2/rc/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts:64:49)
at GeneratedShimsHostWrapper.getSourceFile (angular2/rc/packages/compiler-cli/src/ngtsc/shims/src/host.ts:88:26)
at findSourceFile (typescript/stable/lib/typescript.js:90654:29)
at typescript/stable/lib/typescript.js:90553:85
at getSourceFileFromReferenceWorker (typescript/stable/lib/typescript.js:90520:34)
at processSourceFile (typescript/stable/lib/typescript.js:90553:13)
at processRootFile (typescript/stable/lib/typescript.js:90383:13)
PR Close#33588
When decorating classes with ivy definitions (e.g. `ɵfac` or `ɵdir`)
the inner name of the class declaration must be used.
This is because in ES5 the definitions are inside the class's IIFE
where the outer declaration has not yet been initialized.
PR Close#33533
In ES5 the class consists of an outer variable declaration that is
initialised by an IIFE. Inside the IIFE the class is implemented by
an inner function declaration that is returned from the IIFE.
This inner declaration may have a different name to the outer
declaration.
This commit overrides `getInternalNameOfClass()` and
`getAdjacentNameOfClass()` in `Esm5ReflectionHost` with methods that
can find the correct inner declaration name identifier.
PR Close#33533
When compiling an Angular decorator (e.g. Directive), @angular/compiler
generates an 'expression' to be added as a static definition field
on the class, a 'type' which will be added for that field to the .d.ts
file, and a statement adjacent to the class that calls `setClassMetadata()`.
Previously, the same WrappedNodeExpr of the class' ts.Identifier was used
within each of this situations.
In the ngtsc case, this is proper. In the ngcc case, if the class being
compiled is within an ES5 IIFE, the outer name of the class may have
changed. Thus, the class has both an inner and outer name. The outer name
should continue to be used elsewhere in the compiler and in 'type'.
The 'expression' will live within the IIFE, the `internalType` should be used.
The adjacent statement will also live within the IIFE, the `adjacentType` should be used.
This commit introduces `ReflectionHost.getInternalNameOfClass()` and
`ReflectionHost.getAdjacentNameOfClass()`, which the compiler can use to
query for the correct name to use.
PR Close#33533
This commit moves nested i18n section detection to an earlier stage where we convert HTML AST to Ivy AST. This also gives a chance to produce better diagnistic message for nested i18n sections, that also includes a file name and location.
PR Close#33583
These exports are no longer used by the CLI since 7.1.0. Since major versions of the CLI are now locked to major versions of the framework, a CLI user will not be able to use FW 9.0+ on an outdated version (<7.1.0) of the CLI that uses these old APIs.
PR Close#33242
During static evaluation of expressions within ngtsc, it may occur that
certain expressions or just parts thereof cannot be statically
interpreted for some reason. The static interpreter keeps track of the
failure reason and the code path that was evaluated by means of
`DynamicValue`, which will allow descriptive errors. In some situations
however, the static interpreter would throw an exception instead,
resulting in a crash of the compilation. Not only does this cause
non-descriptive errors, more importantly does it prevent the evaluated
result from being partial, i.e. parts of the result can be dynamic if
their value does not have to be statically available to the compiler.
This commit refactors the static interpreter to never throw errors for
certain expressions that it cannot evaluate.
Resolves FW-1582
PR Close#33453
Previously the compiler would crash if a pipe was encountered which did not
match any pipe in the scope of a template.
This commit introduces a new diagnostic error for unknown pipes instead.
PR Close#33454
Previously the template binder would crash when encountering an unknown
localref (# reference) such as `<div #ref="foo">` when no directive has
`exportAs: "foo"`.
With this commit, the compiler instead generates a template diagnostic error
informing the user about the invalid reference.
PR Close#33454
Previously declarations that were imported via a namespace import
were given the same `bestGuessOwningModule` as the context
where they were imported to. This causes problems with resolving
`ModuleWithProviders` that have a type that has been imported in
this way, causing errors like:
```
ERROR in Symbol UIRouterModule declared in
.../@uirouter/angular/uiRouterNgModule.d.ts
is not exported from
.../@uirouter/angular/uirouter-angular.d.ts
(import into .../src/app/child.module.ts)
```
This commit modifies the `TypescriptReflectionHost.getDirectImportOfIdentifier()`
method so that it also understands how to attach the correct `viaModule` to
the identifier of the namespace import.
Resolves#32166
PR Close#33495
Now that we've replaced `ngBaseDef` with an abstract directive definition, there are a lot more cases where we generate a directive definition without a selector. These changes make it so that we don't generate the `selectors` array if it's going to be empty.
PR Close#33431
Removes `ngBaseDef` from the compiler and any runtime code that was still referring to it. In the cases where we'd previously generate a base def we now generate a definition for an abstract directive.
PR Close#33264
For abstract directives, i.e. directives without a selector, it may
happen that their constructor is called explicitly from a subclass,
hence its parameters are not required to be valid for Angular's DI
purposes. Prior to this commit however, having an abstract directive
with a constructor that has parameters that are not eligible for
Angular's DI would produce a compilation error.
A similar scenario may occur for `@Injectable`s, where an explicit
`use*` definition allows for the constructor to be irrelevant. For
example, the situation where `useFactory` is specified allows for the
constructor to be called explicitly with any value, so its constructor
parameters are not required to be valid. For `@Injectable`s this is
handled by generating a DI factory function that throws.
This commit implements the same solution for abstract directives, such
that a compilation error is avoided while still producing an error at
runtime if the type is instantiated implicitly by Angular's DI
mechanism.
Fixes#32981
PR Close#32987
In Angular View Engine, there are two kinds of decorator inheritance:
1) both the parent and child classes have decorators
This case is supported by InheritDefinitionFeature, which merges some fields
of the definitions (such as the inputs or queries).
2) only the parent class has a decorator
If the child class is missing a decorator, the compiler effectively behaves
as if the parent class' decorator is applied to the child class as well.
This is the "undecorated child" scenario, and this commit adds a migration
to ngcc to support this pattern in Ivy.
This migration has 2 phases. First, the NgModules of the application are
scanned for classes in 'declarations' which are missing decorators, but
whose base classes do have decorators. These classes are the undecorated
children. This scan is performed recursively, so even if a declared class
has a base class that itself inherits a decorator, this case is handled.
Next, a synthetic decorator (either @Component or @Directive) is created
on the child class. This decorator copies some critical information such
as 'selector' and 'exportAs', as well as supports any decorated fields
(@Input, etc). A flag is passed to the decorator compiler which causes a
special feature `CopyDefinitionFeature` to be included on the compiled
definition. This feature copies at runtime the remaining aspects of the
parent definition which `InheritDefinitionFeature` does not handle,
completing the "full" inheritance of the child class' decorator from its
parent class.
PR Close#33362
When upgrading an Angular application to a new version using the Angular
CLI, built-in schematics are being run to update user code from
deprecated patterns to the new way of working. For libraries that have
been built for older versions of Angular however, such schematics have
not been executed which means that deprecated code patterns may still be
present, potentially resulting in incorrect behavior.
Some of the logic of schematics has been ported over to ngcc migrations,
which are automatically run on libraries. These migrations achieve the
same goal of the regular schematics, but operating on published library
sources instead of used code.
PR Close#33362
Previously, the (currently disabled) undecorated parent migration in
ngcc would produce errors when a base class could not be determined
statically or when a class extends from a class in another package. This
is not ideal, as it would cause the library to fail compilation without
a workaround, whereas those problems are not guaranteed to cause issues.
Additionally, inheritance chains were not handled. This commit reworks
the migration to address these limitations.
PR Close#33362
In ngcc's migration system, synthetic decorators can be injected into a
compilation to ensure that certain classes are compiled with Angular
logic, where the original library code did not include the necessary
decorators. Prior to this change, synthesized decorators would have a
fake AST structure as associated node and a made-up identifier. In
theory, this may introduce issues downstream:
1) a decorator's node is used for diagnostics, so it must have position
information. Having fake AST nodes without a position is therefore a
problem. Note that this is currently not a problem in practice, as
injected synthesized decorators would not produce any diagnostics.
2) the decorator's identifier should refer to an imported symbol.
Therefore, it is required that the symbol is actually imported.
Moreover, bundle formats such as UMD and CommonJS use namespaces for
imports, so a bare `ts.Identifier` would not be suitable to use as
identifier. This was also not a problem in practice, as the identifier
is only used in the `setClassMetadata` generated code, which is omitted
for synthetically injected decorators.
To remedy these potential issues, this commit makes a decorator's
identifier optional and switches its node over from a fake AST structure
to the class' name.
PR Close#33362
A class that is provided as Angular service is required to have an
`@Injectable()` decorator so that the compiler generates its injectable
definition for the runtime. Applications are automatically migrated
using the "missing-injectable" schematic, however libraries built for
older version of Angular may not yet satisfy this requirement.
This commit ports the "missing-injectable" schematic to a migration that
is ran when ngcc is processing a library. This ensures that any service
that is provided from an NgModule or Directive/Component will have an
`@Injectable()` decorator.
PR Close#33362
ngcc has an internal cache of computed decorator information for
reflected classes, which could previously be mutated by consumers of the
reflection host. With the ability to inject synthesized decorators, such
decorators would inadvertently be added into the array of decorators
that was owned by the internal cache of the reflection host, incorrectly
resulting in synthesized decorators to be considered real decorators on
a class. This commit fixes the issue by cloning the cached array before
returning it.
PR Close#33362
This patch ensures that the `[style]` and `[class]` based bindings
are directly applied to an element's style and className attributes.
This patch optimizes the algorithm so that it...
- Doesn't construct an update an instance of `StylingMapArray` for
`[style]` and `[class]` bindings
- Doesn't apply `[style]` and `[class]` based entries using
`classList` and `style` (direct attributes are used instead)
- Doesn't split or iterate over all string-based tokens in a
string value obtained from a `[class]` binding.
This patch speeds up the following cases:
- `<div [class]>` and `<div class="..." [class]>`
- `<div [style]>` and `<div style="..." [style]>`
The overall speec increase is by over 5x.
PR Close#33336
The template type checking abilities of the Ivy compiler are far more
advanced than the level of template type checking that was previously
done for Angular templates. Up until now, a single compiler option
called "fullTemplateTypeCheck" was available to configure the level
of template type checking. However, now that more advanced type checking
is being done, new errors may surface that were previously not reported,
in which case it may not be feasible to fix all new errors at once.
Having only a single option to disable a large number of template type
checking capabilities does not allow for incrementally addressing newly
reported types of errors. As a solution, this commit introduces some new
compiler options to be able to enable/disable certain kinds of template
type checks on a fine-grained basis.
PR Close#33365
View Engine correctly infers the type of local refs to directives or to
<ng-template>s, just not to DOM nodes. This commit splits the
checkTypeOfReferences flag into two separate halves, allowing the compiler
to align with this behavior.
PR Close#33365
For elements that have a text attribute, it may happen that the element
is matched by a directive that consumes the attribute as an input. In
that case, the template type checker will validate the correctness of
the attribute with respect to the directive's declared type of the
input, which would typically be `boolean` for the `disabled` input.
Since empty attributes are assigned the empty string at runtime, the
template type checker would report an error for this template.
This commit introduces a strictness flag to help alleviate this
particular situation, effectively ignoring text attributes that happen
to be consumed by a directive.
PR Close#33365
During the creation of an Angular program in the compiler, a check is
done to verify whether the version of TypeScript is considered
supported, producing an error if it is not. This check was missing in
the Ivy compiler, so users may have ended up running an unsupported
TypeScript version inadvertently.
Resolves FW-1643
PR Close#33377
Recently it was made possible to have a directive without selector,
which are referred to as abstract directives. Such directives should not
be registered in an NgModule, but can still contain decorators for
inputs, outputs, queries, etc. The information from these decorators and
the `@Directive()` decorator itself needs to be registered with the
central `MetadataRegistry` so that other areas of the compiler can
request information about a given directive, an example of which is the
template type checker that needs to know about the inputs and outputs of
directives.
Prior to this change, however, abstract directives would only register
themselves with the `MetadataRegistry` as being an abstract directive,
without all of its other metadata like inputs and outputs. This meant
that the template type checker was unable to resolve the inputs and
outputs of these abstract directives, therefore failing to check them
correctly. The typical error would be that some property does not exist
on a DOM element, whereas said property should have been bound to the
abstract directive's input.
This commit fixes the problem by always registering the metadata of a
directive or component with the `MetadataRegistry`. Tests have been
added to ensure abstract directives are handled correctly in the
template type checker, together with tests to verify the form of
abstract directives in declaration files.
Fixes#30080
PR Close#33131
Often the types of an `@Input`'s field don't fully reflect the types of
assignable values. This can happen when an input has a getter/setter pair
where the getter always returns a narrow type, and the setter coerces a
wider value down to the narrow type.
For example, you could imagine an input of the form:
```typescript
@Input() get value(): string {
return this._value;
}
set value(v: {toString(): string}) {
this._value = v.toString();
}
```
Here, the getter always returns a `string`, but the setter accepts any value
that can be `toString()`'d, and coerces it to a string.
Unfortunately TypeScript does not actually support this syntax, and so
Angular users are forced to type their setters as narrowly as the getters,
even though at runtime the coercion works just fine.
To support these kinds of patterns (e.g. as used by Material), this commit
adds a compiler feature called "input coercion". When a binding is made to
the 'value' input of a directive like MatInput, the compiler will look for a
static field with the name ngAcceptInputType_value. If such a field is found
the type-checking expression for the input will use the static field's type
instead of the type for the @Input field,allowing for the expression of a
type conversion between the binding expression and the value being written
to the input's field.
To solve the case above, for example, MatInput might write:
```typescript
class MatInput {
// rest of the directive...
static ngAcceptInputType_value: {toString(): string};
}
```
FW-1475 #resolve
PR Close#33243
Prior to this change, a method call of a local template variable would
incorrectly be considered a call to a method on the component class.
For example, this pattern would produce an error:
```
<ng-template let-method>{{ method(1) }}</ng-template>
```
Here, the method call should be targeting the `$implicit` variable on
the template context, not the component class. This commit corrects the
behavior by first resolving methods in the template before falling back
on the component class.
Fixes#32900
PR Close#33132
In View Engine, with fullTemplateTypeCheck mode disabled, the type of any
inferred based on the entity being referenced. This is a bug, since the
goal with fullTemplateTypeCheck: false is for Ivy and VE to be aligned in
terms of type inference.
This commit adds a 'checkTypeOfReference' flag in the TypeCheckingConfig
to control this inference, and sets it to false when fullTemplateTypeCheck
is disabled.
PR Close#33261
Libraries can expose directive/component base classes that will be
used by consumer applications. Using such a base class from another
compilation unit works fine with "ngtsc", but when using "ngc", the
compiler will thrown an error saying that the base class is not
part of a NgModule. e.g.
```
Cannot determine the module for class X in Y! Add X to the NgModule to fix it.
```
This seems to be because the logic for distinguishing directives from
abstract directives is scoped to the current compilation unit within
ngc. This causes abstract directives from other compilation units to
be considered as actual directives (causing the exception).
PR Close#33347
When computing i18n messages for templates there are two passes.
This is because messages must be computed before any whitespace
is removed. Then on a second pass, the messages must be recreated
but reusing the message ids from the first pass.
Previously ICUs were losing their legacy ids that had been computed
via the first pass. This commit fixes that by keeping track of the
message from the first pass (`previousMessage`) for ICU placeholder
nodes.
// FW-1637
PR Close#33318
This commit adapts the private NgModule re-export system (using aliasing) to
ngcc. Not all ngcc compilations are compatible with these re-exports, as
they assume a 1:1 correspondence between .js and .d.ts files. The primary
concern here is supporting them for commonjs-only packages.
PR Close#33177