Exported functions or static method that return a `ModuleWithProviders`
compatible structure need to provide information about the referenced
`NgModule` type in their return type.
This allows ngtsc to be able to understand the type of `NgModule` that is
being returned from calls to the function, without having to dig into the
internals of the compiled library.
There are two ways to provide this information:
* Add a type parameter to the `ModuleWithProviders` return type. E.g.
```
static forRoot(): ModuleWithProviders<SomeNgModule>;
```
* Convert the return type to a union that includes a literal type. E.g.
```
static forRoot(): (SomeOtherType)&{ngModule:SomeNgModule};
```
This commit updates the rendering of typings files to include this type
information on all matching functions/methods.
PR Close#27326
To support updating `ModuleWithProviders` calls,
we need to be able to map exported functions between
source and typings files, as well as classes.
PR Close#27326
A surprising interaction with the MagicString library caused inserted
Ivy definitions to be dropped during the removal of decorators, iff all
decorators on the class could be removed. In that case, the removal
location corresponds with the exact location where Ivy definitions were
inserted into.
This commit moves the removal of decorators to occur before Ivy
definitions are inserted. This effectively avoids the problem, as later
inserted text fragments will be retained by MagicString.
PR Close#27159
If a template contains specific TypeScript syntax, such as a non-null
assertion, the code that is emitted from ngcc into a JavaScript bundle
should not retain such syntax as it is invalid in JS.
A full-blown TypeScript emit of a complete ts.SourceFile would be
required to be able to emit JS and possibly downlevel into a lower
language target, which is not an option for ngcc as it currently
operates on partial ASTs, not full source files.
Instead, ngtsc no longer produces TypeScript specific syntax in the first
place, such that TypeScript print logic will only generate JS code.
PR Close#27051
Ngcc will now render additional exports for classes that are referenced in
`NgModule` decorated classes, but which were not publicly exported
from an entry-point of the package.
This is important because when ngtsc compiles libraries processed by ngcc
it needs to be able to publcly access decorated classes that are referenced
by `NgModule` decorated classes in order to build templates that use these
classes.
Doing this re-exporting is not without its risks. There are chances that
the class is not exported correctly: there may already be similarly named
exports from the entry-point or the class may be being aliased. But there
is not much more we can do from the point of view of ngcc to workaround
such scenarios. Generally, packages should have been built so that this
approach works.
PR Close#26906
There are a number of variables that need to be passed around
the program, in particular to the renderers, which benefit from being
stored in well defined objects.
The new `EntryPointBundle` structure is a specific format of an entry-point
and contains the compiled `BundleProgram` objects for the source and typings,
if appropriate.
This change helps with future refactoring, where we may need to add new
properties to this object. It allows us to maintain more stable APIs between
the constituent parts of ngcc, rather than passing lots of primitive values
around throughout the program.
PR Close#26906
The `NgModuleDecoratorHandler` can now register all the references that
it finds in the `NgModule` metadata, such as `declarations`, `imports`,
`exports` etc.
This information can then be used by ngcc to work out if any of these
references are internal only and need to be manually exported from a
library's entry-point.
PR Close#26906
If a decorated class is not publicly exported via an entry-point then the
previous approach to finding the associated typings file failed.
Now we ensure that we extract all the class declarations from the
dtsTypings program, even if they are not exported from the entry-point.
This is achieved by also parsing statements of each source file, rather
than just parsing classes that are exported from the entry-point.
Because we now look at all the files, it is possible for there to be multiple
class declarations with the same local name. In this case, only the first
declaration with a given name is added to the map; subsequent classes are
ignored.
We are most interested in classes that are publicly exported from the
entry-point, so these are added to the map first, to ensure that they are
not ignored.
PR Close#26906
When ngtsc compiles @angular/core, it rewrites core imports to the
r3_symbols.ts file that exposes all internal symbols under their
external name. When creating the FESM bundle, the r3_symbols.ts file
causes the external symbol names to be rewritten to their internal name.
Under ngcc compilations of FESM bundles, the indirection of
r3_symbols.ts is no longer in place such that the external names are
retained in the bundle. Previously, the external name `ɵdefineNgModule`
was explicitly declared internally to resolve this issue, but the
recently added `setClassMetadata` was not declared as such, causing
runtime errors.
Instead of relying on the r3_symbols.ts file to perform the rewrite of
the external modules to their internal variants, the translation is
moved into the `ImportManager` during the compilation itself. This
avoids the need for providing the external name manually.
PR Close#27055
This fixes an issue where packages would be skipped if they contained
e.g. RxJS 5 style imports such as
```
import { observeOn } from 'rxjs/operators/observeOn';
```
Given that no package.json file can be found at the imported path, the
dependency would be reported missing, causing the package to be skipped.
PR Close#27031
Previously the ivy definition calls we going directly after the
class constructor function But this meant that the lifecycle
hooks attached to the prototype were ignored by the ngtsc
compiler.
Now the definitions are written to the end of the IIFE block,
just before the return statement.
Closes#26849
PR Close#26856
For each package entry-point there is only one format that
is used to compile the typings files (.d.ts). This will be
either esm2015 or fesm2015 (preferred). So we would not run
any dts processing in the renderer if we are not compiling
the appropriate format.
PR Close#26403
1) The `DecorationAnalyzer now analyzes all source files, rather than just
the entry-point files, which fixes#26183.
2) The `DecoratorAnalyzer` now runs all the `handler.analyze()` calls
across the whole entry-point *before* running `handler.compile()`. This
ensures that dependencies between the decorated classes *within* an
entry-point are known to the handlers when running the compile process.
3) The `Renderer` now does the transformation of the typings (.d.ts) files
which allows us to support packages that only have flat format
entry-points better, and is faster, since we won't parse `.d.ts` files twice.
PR Close#26403
The rendering of typings is not specific to the package
format, so it doesn't make sense to put it in a specific
renderer.
As a result there is no real difference between esm5 and esm2015
renderers, so there is no point in having separate classes.
PR Close#26403
Previously we always used the non-flat format because we thought
that this was the one that would always be available.
It turns out that this is not the case and that only one of the flat and
non-flat formats may be available.
Therefore we should use whichever is available, defaulting to the flat
format if that exists, since that will be faster to parse.
PR Close#26403
Going forward we need to be able to do the same work on both
flat and non-flat module formats (such as computing arity and
transforming .d.ts files)
PR Close#26403
The Material project uses slightly different properties to the
core Angular project for specifying the different format entry-point.
This commit ensures that we map these properties correctly for both
types of project.
PR Close#26403
This commit causes a call to setClassMetadata() to be emitted for every
type being compiled by ngtsc (every Angular type). With this metadata,
the TestBed should be able to recompile these classes when overriding
decorator information.
Testing strategy: Tests in the previous commit for
generateSetClassMetadataCall() verify that the metadata as generated is
correct. This commit enables the generation for each DecoratorHandler,
and a test is added to ngtsc_spec to verify all decorated types have
metadata generated for them.
PR Close#26860
We are close enough to blacklist a few test targets, rather than whitelist targets to run...
Because bazel rules can be composed of other rules that don't inherit tags automatically,
I had to explicitly mark all of our ts_library and ng_module targes with "ivy-local" and
"ivy-jit" tags so that we can create a query that excludes all fixme- tagged targets even
if those targets are composed of other targets that don't inherit this tag.
This is the updated overview of ivy related bazel tags:
- ivy-only: target that builds or runs only under ivy
- fixme-ivy-jit: target that doesn't yet build or run under ivy with --compile=jit
- fixme-ivy-local: target that doesn't yet build or run under ivy with --compile=local
- no-ivy-jit: target that is not intended to build or run under ivy with --compile=jit
- no-ivy-local: target that is not intended to build or run under ivy with --compile=local
PR Close#26471
Originally, the ivy_switch mechanism used Bazel genrules to conditionally
compile one TS file or another depending on whether ngc or ngtsc was the
selected compiler. This was done because we wanted to avoid importing
certain modules (and thus pulling them into the build) if Ivy was on or
off. This mechanism had a major drawback: ivy_switch became a bottleneck
in the import graph, as it both imports from many places in the codebase
and is imported by many modules in the codebase. This frequently resulted
in cyclic imports which caused issues both with TS and Closure compilation.
It turns out ngcc needs both code paths in the bundle to perform the switch
during its operation anyway, so import switching was later abandoned. This
means that there's no real reason why the ivy_switch mechanism needed to
operate at the Bazel level, and for the ivy_switch file to be a bottleneck.
This commit removes the Bazel-level ivy_switch mechanism, and introduces
an additional TypeScript transform in ngtsc (and the pass-through tsc
compiler used for testing JIT) to perform the same operation that ngcc
does, and flip the switch during ngtsc compilation. This allows the
ivy_switch file to be removed, and the individual switches to be located
directly next to their consumers in the codebase, greatly mitigating the
circular import issues and making the mechanism much easier to use.
As part of this commit, the tag for marking switched variables was changed
from __PRE_NGCC__ to __PRE_R3__, since it's no longer just ngcc which
flips these tags. Most variables were renamed from R3_* to SWITCH_* as well,
since they're referenced mostly in render2 code.
Test strategy: existing test coverage is more than sufficient - if this
didn't work correctly it would break the hello world and todo apps.
PR Close#26550
Previously we only removed assignments to `Class.decorators = [];`
if the array was not empty.
Now we also remove calls to `__decorate([])`, similarly.
PR Close#26236
Previously, classes that were declared via variable declarations,
rather than class declarations, were being excluded from the
parsed classes.
PR Close#26236
The most recent Angular distributions have begun to use __decorate instead of Class.decorators.
This prevents `ngcc` from recognizing the classes and then fails to perform the transform to
ivy format.
Example:
```
var ApplicationModule = /** @class */ (function () {
// Inject ApplicationRef to make it eager...
function ApplicationModule(appRef) {
}
ApplicationModule = __decorate([
NgModule({ providers: APPLICATION_MODULE_PROVIDERS }),
__metadata("design:paramtypes", [ApplicationRef])
], ApplicationModule);
return ApplicationModule;
}());
```
Now `ngcc` recognizes `__decorate([...])` declarations and performs its transform.
See FW-379
PR Close#26236
In some formats variables are declared as `var` or `let` and only
assigned a value later in the code.
The ngtsc resolver still needs to be able to resolve this value,
so the host now provides a `host.getVariableValue(declaration)`
method that can do this resolution based on the format.
The hosts make some assumptions about the layout of the
code, so they may only work in the constrained scenarios that
ngcc expects.
PR Close#26236
`ngcc` adds marker files to each folder that has been
compiled, containing the version of the ngcc used.
When compiling, it will ignore folders that contain these
marker files, as long as the version matches.
PR Close#25557
Closure compiler requires that the i18n message constants of the form
const MSG_XYZ = goog.getMessage('...');
have names that are unique across an entire compilation, even if the
variables themselves are local to a given module. This means that in
practice these names must be unique in a codebase.
The best way to guarantee this requirement is met is to encode the
relative file name of the file into which the constant is being written
into the constant name itself. This commit implements that solution.
PR Close#25689