Fixes#25018.
Instantiating a NgModuleRef from NgModuleFactory reuses the NgModuleDefinition if it is already present. However the NgModuleDefinition has a providers array which modified when tree shakable providers are instantiated. This corrupts the provider definitions the next time the same factory is used to create a new NgModuleRef - Two provider definitions can end up with the same index anf the injector could potentially return a completely wrong object for a provider token.
This scenario is more likely on the server where the same NgModuleFactory is reused across requests.
The fix clones the cached NgModuleDefinition so that any tree shakable providers added later do not affect the cached copy.
PR Close#25022
Ivy definition types have a generic type which specifies the return
type of the factory function. For example:
static ngDirectiveDef<NgForOf, '[ngFor][ngForOf]'>
However, in this case NgForOf itself has a type parameter <T>. Thus,
writing the above is incorrect.
This commit modifies ngtsc to understand the genericness of NgForOf and
to write the following:
static ngDirectiveDef<NgForOf<any>, '[ngFor][ngForOf]'>
PR Close#24862
Previously ngtsc would use a tuple of class types for listing metadata
in .d.ts files. For example, an @NgModule's declarations might be
represented with the type:
[NgIf, NgForOf, NgClass]
If the module had no declarations, an empty tuple [] would be produced.
This has two problems.
1. If the class type has generic type parameters, TypeScript will
complain that they're not provided.
2. The empty tuple type is not actually legal.
This commit addresses both problems.
1. Class types are now represented using the `typeof` operator, so the
above declarations would be represented as:
[typeof NgIf, typeof NgForOf, typeof NgClass].
Since typeof operates on a value, it doesn't require generic type
arguments.
2. Instead of an empty tuple, `never` is used to indicate no metadata.
PR Close#24862
Previously, some of the *Def symbols were not exported or were exported
as public API. This commit ensures every definition type is in the
private export namespace.
PR Close#24862
This commit moves the compiler compliance tests into compiler-cli,
and uses ngtsc to run them instead of the custom compilation
pipeline used before. Testing against ngtsc allows for validation
of the real compiler output.
This commit also fixes a few small issues that prevented the tests
from passing.
PR Close#24862
Previously, when translating an assignment expression (e.g. x = 3), the
translator would always print the statement as X = Y. However, if the
expression is included in a larger expression (X = (Y = Z)), the
translator would print "X = Y = Z" without regard for the outer
expression context.
Now, the translator understands when it's printing an expression
statement (X = Y;) vs an expression in a larger context (X = (Y = Z);)
and encapsulates the latter in parentheses.
PR Close#24862
Previously, references had the concept of an identifier, but would not
properly detect whether the identifier should be used or not when
generating an expression. This change fixes that logic.
Additionally, now whenever an identifier resolves to a reference (even
one imported from another module) as part of resolving an expression,
the reference is updated to use that identifier. This ensures that for
a class Foo declared in foo.ts, but referenced in an expression in
bar.ts, the Reference returned includes the identifier from bar.ts,
meaning that writing an expression in bar.ts for the Reference will not
generate an import.
PR Close#24862
Previously ngtsc had a bug where it would only detect the presence of
ngOnChanges as a static method. This commit flips the condition and only
recognizes ngOnChanges as a non-static method.
PR Close#24862
Previously, the static resolver did its own interpretation of statements
in the TypeScript AST, which only functioned on TypeScript code. ES5
code in particular would not work with the resolver as it had hard-coded
assumptions about AST structure.
This commit changes the resolver to use a ReflectionHost instead, which
abstracts away understanding of the structural side of the AST. It adds 3
new methods to the ReflectionHost in support of this functionality:
* getDeclarationOfIdentifier
* getExportsOfModule
* isClass
PR Close#24862
This change adds support for host bindings to ngtsc, and parses them
both from decorators and from the metadata in the top-level annotation.
PR Close#24862
ngInjectorDef.imports is generated from @NgModule.imports plus
@NgModule.exports. A problem arises as a result, because @NgModule
exports contain not only other modules (which will have ngInjectorDef
fields), but components, directives, and pipes as well. Because of
locality, it's difficult for the compiler to filter these out at
build time.
It's not impossible, but for now filtering them out at runtime will
allow testing of the compiler against complex applications.
PR Close#24862
@NgModule()s get compiled to two fields: ngModuleDef and ngInjectorDef.
Both fields contain imports, as both selector scopes and injectors have
the concept of composed units of configuration. Previously these fields
were generated by static resolution of imports and exports in metadata.
Support for ModuleWithProviders requires they be generated differently.
ngModuleDef's imports/exports are generated as resolved lists of types,
whereas ngInjectorDef's imports should reflect the raw expressions that
the developer wrote in the metadata.
This change modifies the NgModule handler and properly copies raw nodes
for the imports and exports into the ngInjectorDef.
PR Close#24862
Previously ngtsc had a few bugs handling special token types:
* Injector was not properly translated to INJECTOR
* ChangeDetectorRef was not injected via injectChangeDetectorRef()
This commit fixes these two bugs, and also adds a test to ensure
they continue to work correctly.
PR Close#24862
Within an @NgModule it's common to include in the imports a call to
a ModuleWithProviders function, for example RouterModule.forRoot().
The old ngc compiler was able to handle this pattern because it had
global knowledge of metadata of not only the input compilation unit
but also all dependencies.
The ngtsc compiler for Ivy doesn't have this knowledge, so the
pattern of ModuleWithProviders functions is more difficult. ngtsc
must be able to determine which module is imported via the function
in order to expand the selector scope and properly tree-shake
directives and pipes.
This commit implements a solution to this problem, by adding a type
parameter to ModuleWithProviders through which the actual module
type can be passed between compilation units.
The provider side isn't a problem because the imports are always
copied directly to the ngInjectorDef.
PR Close#24862
Metadata in Ivy must be literal. For example,
@NgModule({...})
is legal, whereas
const meta = {...};
@NgModule(meta)
is not.
However, some code contains additional superfluous parentheses:
@NgModule(({...}))
It is desirable that ngtsc accept this form of literal object.
PR Close#24862
This commit adds the ivy-local tag to //packages/router. Since the
router depends on //packages/upgrade, it makes that package
compatible with ngtsc as well.
PR Close#24862
This change turns on preserve-symlinks in nodejs to verify hermeticity of the Angular build.
BREAKING CHANGE: Use of @angular/bazel rules now requires calling ng_setup_workspace() in your WORKSPACE file.
For example:
local_repository(
name = "angular",
path = "node_modules/@angular/bazel",
)
load("@angular//:index.bzl", "ng_setup_workspace")
ng_setup_workspace()
PR Close#24881
Examples using `@angular/elements` need to transpile to es2015 for
Custom Elements to work (on browsers that natively support them).
Alternatively, a polyfill would need to be loaded. For now, changing the
transpilation target to es2015 is the simplest solution.
PR Close#24840
Adds an example of using the `currency` pipe with a currency that has no cents like CLP,
which will format the amount with no digits if `digitsInfo` is not provided:
<!-- outputs CA$14.00 -->
{{ 14 | currency:'CAD' }}
<!-- outputs CLP14 -->
{{ 14 | currency:'CLP' }}
Amends the docs, adds an example and fix an error with a current example.
PR Close#24661
This change fixes up several comments that accidentally used the JSDoc
tag @internal in regular block comments (`/*` instead of `/**`).
This prevents a problem with Closure Compiler that balks at `@` tags
occuring in regular block comments, because it assumes they were
intended to be tags for the compiler.
When occuring in `/**` JSDoc, tsickle escapes the tags, so they do not
cause problems.
PR Close#24928