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
This commit adds generation of .ngsummary.js shims alongside .ngfactory.js
shims when generated files are enabled.
Generated .ngsummary shims contain a single, null export for every exported
class with decorators that exists in the original source files. Ivy code
does not depend on summaries, so these exist only as a placeholder to allow
them to be imported and their values passed to old APIs. This preserves
backwards compatibility.
Testing strategy: this commit adds a compiler test to verify the correct
shape and contents of the generated .ngsummary.js files.
PR Close#26495
This commit refactors the shim host to be agnostic to the shims being
generated, and provides an API for generating additional shims besides
the .ngfactory.js. This will be used in a following commit to generate
.ngsummary.js shims.
Testing strategy: this refactor introduces no new behavior, so it's
sufficient that the existing tests for factory shim generation continue
to pass.
PR Close#26495
This simple refactor of the build rules renames the .ngfactory.js shim
generator to 'shims' instead of 'factories', in preparation for adding
.ngsummary.js shim generation.
Testing strategy: this commit does not introduce any new behavior and
merely moves files and symbols around. It's sufficient that the existing
ngtsc tests pass.
PR Close#26495
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
The 'animations' field of @Component metadata should be copied directly
into the ngComponentDef for that component and should not pass through
static resolution.
Previously the animations array was statically resolved and then the
values were translated back when generating ngComponentDef.
PR Close#26322
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
This commit gets ready for the introduction of ngtsc template
type-checking tests by refactoring test environment setup into a
custom helper. This helper will simplify the authoring of future
ngtsc tests.
Ngtsc tests previously returned a numeric error code (a la ngtsc's CLI
interface) if any TypeScript errors occurred. The helper has the
ability to run ngtsc and return the actual array of ts.Diagnostics, which
greatly increases the ability to write clean tests.
PR Close#26203
This commit enables generation and checking of a type checking ts.Program
whenever the fullTemplateTypeCheck flag is enabled in tsconfig.json. It
puts together all the pieces built previously and causes diagnostics to be
emitted whenever type errors are discovered in a template.
Todos:
* map errors back to template HTML
* expand set of type errors covered in generated type-check blocks
PR Close#26203
Before type checking can be turned on in ngtsc, appropriate metadata for
each component and directive must be determined. This commit adds tracking
of the extra metadata in *DefWithMeta types to the selector scope handling,
allowing for later extraction for type-checking purposes.
PR Close#26203
This commit introduces the template type-checking context API, which manages
inlining of type constructors and type-check blocks into ts.SourceFiles.
This API will be used by ngtsc to generate a type-checking ts.Program.
An TypeCheckProgramHost is provided which can wrap a normal ts.CompilerHost
and intercept getSourceFile() calls. This can be used to provide source
files with type check blocks to a ts.Program for type-checking.
PR Close#26203
This commit introduces the main functionality of the type-check compiler:
generation of type check blocks. Type check blocks are blocks of TypeScript
code which can be inlined into source files, and when processed by the
TypeChecker will give information about any typing errors in template
expressions.
PR Close#26203
Template type-checking will make use of expression and statement
translation as well as the ImportManager, so this code needs to
live in a separate build target which can be depended on by both
the main ngtsc transform as well as the template type-checking
mechanism. This refactor introduces a separate build target
for that code.
PR Close#26203
Previously in Ivy, metadata for directives/components/modules/etc was
carried in .d.ts files inside type information encoded on the
DirectiveDef, ComponentDef, NgModuleDef, etc types of Ivy definition
fields. This works well, but has the side effect of complicating Ivy's
runtime code as these extra generic type parameters had to be specified
as <any> throughout the codebase. *DefInternal types were introduced
previously to mitigate this issue, but that's the wrong way to solve
the problem.
This commit returns *Def types to their original form, with no metadata
attached. Instead, new *DefWithMeta types are introduced that alias the
plain definition types and add extra generic parameters. This way the
only code that needs to deal with the extra metadata parameters is the
compiler code that reads and writes them - the existence of this metadata
is transparent to the runtime, as it should be.
PR Close#26203
This commit introduces //packages/compiler-cli/src/ngtsc/typecheck as a
container for template type-checking code, and implements an initial API:
type constructor generation.
Type constructors are static methods on component/directive types with
no runtime implementation. The methods are used during compilation to
enable inference of a component or directive's generic type parameters
from the types of expressions bound to any of their @Inputs. A type
constructor looks like:
class Directive<T> {
someInput: T;
static ngTypeCtor<T>(init: Partial<Pick<Directive<T>, 'someInput'>>): Directive<T>;
}
It can be used to infer a type for T based on the input:
const _dir = Directive.ngTypeCtor({someInput: 'string'}); // Directive<T>
PR Close#26203
`TypeScript` only supports merging and extending of `compilerOptions`. This is an implementation to support extending and inheriting of `angularCompilerOptions` from multiple files.
Closes: #22684
PR Close#22717
Previously, if ngtsc encountered a VariableDeclaration without an
initializer, it would assume that the variable was undefined, and
return that result.
However, for symbols exported from external modules that resolve to
.d.ts files, variable declarations are of the form:
export declare let varName: Type;
This form also lacks an initializer, but indicates the presence of an
importable symbol which can be referenced. This commit changes the
static resolver to understand variable declarations with the 'declare'
keyword and to generate references when it encounters them.
PR Close#25775
The bootstrap property of @NgModule was not previously compiled by
the compiler in AOT or JIT modes (in Ivy). This commit adds support
for bootstrap.
PR Close#25775
Closure requires @nocollapse on Ivy definition static fields in order
to not convert them to standalone constants. However tsickle, the tool
which would ordinarily be responsible for adding @nocollapse, doesn't
properly annotate fields which are added synthetically via transforms.
So this commit adds @nocollapse by applying regular expressions against
code during the final write to disk.
PR Close#25775
`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
TypeScript has a more modern diagnostic emit function which produces
contextually annotated error information, using colors in the console
to indicate where in the code the error occurs.
This commit swiches ngtsc to use this format for diagnostics when
emitting them after a failed compilation.
PR Close#25647
This commit takes the first steps towards ngtsc producing real
TypeScript diagnostics instead of simply throwing errors when
encountering incorrect code.
A new class is introduced, FatalDiagnosticError, which can be thrown by
handlers whenever a condition in the code is encountered which by
necessity prevents the class from being compiled. This error type is
convertable to a ts.Diagnostic which represents the type and source of
the error.
Error codes are introduced for Angular errors, and are prefixed with -99
(so error code 1001 becomes -991001) to distinguish them from other TS
errors.
A function is provided which will read TS diagnostic output and convert
the TS errors to NG errors if they match this negative error code
format.
PR Close#25647
In tsc 3.0 the check that enables program structure reuse in tryReuseStructureFromOldProgram has changed
and now uses identity comparison on arrays within CompilerOptions. Since we recreate the options
on each incremental compilation, we now fail this check.
After this change the default set of options is reused in between incremental compilations, but we still
allow options to be overriden if needed.
PR Close#25275
This fixes a bug in ngtsc where each @Directive was compiled using a
separate ConstantPool. This resulted in two issues:
* Directive constants were not shared across the file
* Extra statements from directive compilation were dropped instead of
added to the file
This commit fixes both issues and adds a test to verify @Directive is
working properly.
PR Close#25620
This commit adds support for enumeration values. An enumeration value
is now a first-class return value of the resolver, which provides both
a Reference to the enum type itself and the name of the value from that
enum. Resolving an enum itself returns a Map<string, EnumValue>.
PR Close#25619
Ivy definitions in .d.ts files often reference the type of a class.
Sometimes, those classes have generic type parameters. When this is
the case, ngtsc needs to emit generic type parameters in the .d.ts
files (usually by passing 'any').
PR Close#25406
Since non-flat module formats (esm2015, esm5) have different structure
than their flat counterparts (and since we are operating on JS files
inside `node_modules/`, we need to configure TS to include deeply nested
JS files (by specifying a sufficiently high `maxNodeModuleJsDepth`).
Remains to be determined if this has any (noticeable) performance
implications.
PR Close#25406
In some code formats (e.g. ES5) methods can actually be function
expressions. For example:
```js
function MyClass() {}
// this static method is declared as a function expression
MyClass.staticMethod = function() { ... };
```
PR Close#25406
ngtsc's static resolver can evaluate function calls where parameters
have default values. In TypeScript code these default values live on the
function definition, but in ES5 code the default values are represented
by statements in the function body.
A new ReflectionHost method getDefinitionOfFunction() abstracts over
this difference, and allows the static reflector to more accurately
evaluate ES5 code.
PR Close#25406
A small bug caused base factory variable statements for @Component to
not be emitted properly. At the same time as this is fixed, those
statements are now emitted as const.
PR Close#25425
When @angular/core is compiled by ngtsc, a factory file is generated
for ApplicationModule, that is currently invalid because r3_symbols
does not export NgModuleFactory. This change fixes that issue and
ensures the generated ngfactory file for @angular/core is valid.
PR Close#25392
When generating the 'directives:' property of ngComponentDef, ngtsc
needs to be conscious of declaration order. If a directive being
written into the array is declarated after the component currently
being compiled, then the entire directives array needs to be wrapped
in a closure.
This commit fixes ngtsc to pay attention to such ordering issues
within directives arrays.
PR Close#25392
This commit creates an API for factory functions which allows them
to be inherited from one another. To do so, it differentiates between
the factory function as a wrapper for a constructor and the factory
function in ngInjectableDefs which is determined by a default
provider.
The new form is:
factory: (t?) => new (t || SomeType)(inject(Dep1), inject(Dep2))
The 't' parameter allows for constructor inheritance. A subclass with
no declared constructor inherits its constructor from the superclass.
With the 't' parameter, a subclass can call the superclass' factory
function and use it to create an instance of the subclass.
For @Injectables with configured providers, the factory function is
of the form:
factory: (t?) => t ? constructorInject(t) : provider();
where constructorInject(t) creates an instance of 't' using the
naturally declared constructor of the type, and where provider()
creates an instance of the base type using the special declared
provider on @Injectable.
PR Close#25392
Previously, ngtsc used a new ConstantPool for each decorator
compilation. This could result in collisions between constants in the
top-level scope.
Now, ngtsc uses a single ConstantPool for each source file being
compiled, and merges the constant statements into the file after the
import section.
PR Close#25392
The performCompilation() is always called with an undefined oldProgram option (even in watch mode).
This was regression introduced in: 957be960d2
Partial fix, discovered in: #21361
PR Close#21364
To match the View Engine behavior.
We should make this configurable so that the node injector is tree shaken when
directives do not need to be published.
PR Close#25291
Existing bootstrap code in the wild depends on the existence of
.ngfactory files, which Ivy does not need. This commit adds the
capability in ngtsc to generate .ngfactory files which bridge
existing bootstrap code with Ivy.
This is an initial step. Remaining work includes complying with
the compiler option to specify a generated file directory, as well
as presumably testing in g3.
PR Close#25176
The optional property on `ts.CompilerHost` is called `realpath` (lower
case), not `realPath` (lower camel case).
It is not clear to me what the impact of this is, but the author's
intent was clearly to override `realpath`.
PR Close#25023
In some code formats (e.g. ES5) methods can actually be function
expressions. For example:
```js
function MyClass() {}
// this static method is declared as a function expression
MyClass.staticMethod = function() { ... };
```
PR Close#24897
The `ReflectionHost` interface that is being implemented only expects a
return value of `boolean`.
Moreover, if you want to extend this class to support non-TS code formats,
e.g. ES5, the result of this call returning true does not mean that the `node`
is a `ClassDeclaration`. It could be a `VariableDeclaration`.
PR Close#24897
This commit replaces the "not implemented" error when calling
listLazyRoutes() with an empty result, which will allow testing
in the CLI before listLazyRoutes() is implemented.
PR Close#25080
loadNgStructureAsync() for ngtsc has a bug where it returns a
Promise<Promise[]> instead of awaiting the entire array of Promises.
This commit uses Promise.all() to await the whole set.
PR Close#25080
ngtsc used to have a custom ts.CompilerHost which delegated to the plain
ts.CompilerHost. There's no need for this wrapper class and it causes
issues with CLI integration, so delete it.
PR Close#25080
ngtsc used to assume that all .d.ts dependencies (that is, third party
packages) were imported via an absolute module path. It turns out this
assumption isn't valid; some build tools allow relative imports of
other compilation units.
In the absolute case, ngtsc assumes (and still does) that all referenced
types are available through the entrypoint from which an @NgModule was
imported. This commit adds support for relative imports, in which case
ngtsc will use relative path resolution to determine the imports.
PR Close#25080
There is a bug in the existing handling for cross-file references.
Suppose there are two files, module.ts and component.ts.
component.ts declares two components, one of which uses the other.
In the Ivy model, this means the component will get a directives:
reference to the other in its defineComponent call.
That reference is generated by looking at the declared components
of the module (in module.ts). However, the way ngtsc tracks this
reference, it ends up comparing the identifier of the component
in module.ts with the component.ts file, detecting they're not in
the same file, and generating a relative import.
This commit changes ngtsc to track all identifiers of a reference,
including the one by which it is declared. This allows toExpression()
to correctly decide that a local reference is okay in component.ts.
PR Close#25080
When ngtsc encounters a reference to a type (for example, a Component
type listed in an NgModule declarations array), it traces the import
of that type and attempts to determine the best way to refer to it.
In the event the type is defined in the same file where a reference
is being generated, the identifier of the type is used. If the type
was imported, ngtsc has a choice. It can use the identifier from the
original import, or it can write a new import to the module where the
type came from.
ngtsc has a bug currently when it elects to rely on the user's import.
When writing a .d.ts file, the user's import may have been elided as
the type was not referred to from the type side of the program. Thus,
in .d.ts files ngtsc must always assume the import may not exist, and
generate a new one.
In .js output the import is guaranteed to still exist, so it's
preferable for ngtsc to continue using the existing import if one is
available.
This commit changes how @angular/compiler writes type definitions, and
allows it to use a different expression to write a type definition than
is used to write the value. This allows ngtsc to specify that types in
type definitions should always be imported. A corresponding change to
the staticallyResolve() Reference system allows the choice of which
type of import to use when generating an Expression from a Reference.
PR Close#25080
@ContentChild[ren] and @ViewChild[ren] can contain a forwardRef() to a
type. This commit allows ngtsc to unwrap the forward reference and
deal with the node inside.
It includes two modes of support for forward reference resolution -
a foreign function resolver which understands deeply nested forward
references in expressions that are being statically evaluated, and
an unwrapForwardRef() function which deals only with top-level nodes.
Both will be useful in the future, but for now only unwrapForwardRef()
is used.
PR Close#25080
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
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
@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
It's possible to declare an argument-less NgModule:
@NgModule() export class Foo {}
Update the @NgModule compiler to support this usage.
PR Close#24738
On accident a few of the definition types were emitted as public API
symbols. Much of the Ivy API surface is still prefixed with ɵ,
indicating it's a private API. The definition types should be private
for now.
PR Close#24738
This commit changes the @NgModule provider to understand that sometimes
an import will resolve to an object instead of a type, and that object
could be of the ModuleWithProviders type. In that case, the 'ngModule'
property is read, and its value used instead.
This still will not handle ModuleWithProviders references across
compilation units; that work is coming in a future PR.
PR Close#24738
The current module resolution simply attaches .ts to the import/export path, which does
not work if the path is using Node / CommonJS behavior to resolve to an index.ts file.
This patch uses typescript's module resolution logic, and will attempt to load the original
typescript file if this resolution returns a .js or .d.ts file
PR Close#22856
With these changes, the types are a little stricter now and also not
compatible with Protractor's jasmine-like syntax. So, we have to also
use `@types/jasminewd2` for e2e tests (but not for non-e2e tests).
I also had to "augment" `@types/jasminewd2`, because the latest
typings from [DefinitelyTyped][1] do not reflect the fact that the
`jasminewd2` version (v2.1.0) currently used by Protractor supports
passing a `done` callback to a spec.
[1]: 566e039485/types/jasminewd2/index.d.ts (L9-L15)Fixes#23952Closes#24733
PR Close#19904
This commit adds support for templateUrl in component templates within
ngtsc. The compilation pipeline is split into sync and async versions,
where asynchronous compilation invokes a special preanalyze() phase of
analysis. The preanalyze() phase can optionally return a Promise which
will delay compilation until it resolves.
A ResourceLoader interface is used to resolve templateUrls to template
strings and can return results either synchronously or asynchronously.
During sync compilation it is an error if the ResourceLoader returns a
Promise.
Two ResourceLoader implementations are provided. One uses 'fs' to read
resources directly from disk and is chosen if the CompilerHost doesn't
provide a readResource method. The other wraps the readResource method
from CompilerHost if it's provided.
PR Close#24704
- Adds InheritanceDefinitionFeature to ivy
- Ensures that lifecycle hooks are inherited from super classes whether they are defined as directives or not
- Directives cannot inherit from Components
- Components can inherit from Directives or Components
- Ensures that Inputs, Outputs, and Host Bindings are inherited
- Ensures that super class Features are run
PR Close#24570
Currently ngtsc does not compile @Pipe. This has a side effect
of not removing the @Pipe decorator.
This adds a dummy DecoratorHandler that compiles @Pipe into an
empty ngPipeDef. Eventually this will be replaced with a full
implementation, but for now this solution allows compield code
to be tree-shaken properly.
PR Close#24677
Previously ngtsc removed the class-level decorators (@Component,
etc) but left all the ancillary decorators (@Input, @Optional,
etc).
This changes the transform to descend into the members of decorated
classes and remove any Angular decorators, not just the class-level
ones.
PR Close#24677
@angular/core is unique in that it defines the Angular decorators
(@Component, @Directive, etc). Ordinarily ngtsc looks for imports
from @angular/core in order to identify these decorators. Clearly
within core itself, this strategy doesn't work.
Instead, a special constant ITS_JUST_ANGULAR is declared within a
known file in @angular/core. If ngtsc sees this constant it knows
core is being compiled and can ignore the imports when evaluating
decorators.
Additionally, when compiling decorators ngtsc will often write an
import to @angular/core for needed symbols. However @angular/core
cannot import itself. This change creates a module within core to
export all the symbols needed to compile it and adds intelligence
within ngtsc to write relative imports to that module, instead of
absolute imports to @angular/core.
PR Close#24677
This change generates ngInjectorDef as well as ngModuleDef for @NgModule
annotated types, reflecting the dual nature of @NgModules as both compilation
scopes and as DI configuration containers.
This required implementing ngInjectorDef compilation in @angular/compiler as
well as allowing for multiple generated definitions for a single decorator in
the core of ngtsc.
PR Close#24632
All errors for existing fields have been detected and suppressed with a
`!` assertion.
Issue/24571 is tracking proper clean up of those instances.
One-line change required in ivy/compilation.ts, because it appears that
the new syntax causes tsickle emitted node to no longer track their
original sourceFiles.
PR Close#24572
ngtsc needs to reflect over code to property compile it. It performs operations
such as enumerating decorators on a type, reading metadata from constructor
parameters, etc.
Depending on the format (ES5, ES6, etc) of the underlying code, the AST
structures over which this reflection takes place can be very different. For
example, in TS/ES6 code `class` declarations are `ts.ClassDeclaration` nodes,
but in ES5 code they've been downleveled to `ts.VariableDeclaration` nodes that
are initialized to IIFEs that build up the classes being defined.
The ReflectionHost abstraction allows ngtsc to perform these operations without
directly querying the AST. Different implementations of ReflectionHost allow
support for different code formats.
PR Close#24541
This change supports compilation of components, directives, and modules
within ngtsc. Support is not complete, but is enough to compile and test
//packages/core/test/bundling/todo in full AOT mode. Code size benefits
are not yet achieved as //packages/core itself does not get compiled, and
some decorators (e.g. @Input) are not stripped, leading to unwanted code
being retained by the tree-shaker. This will be improved in future commits.
PR Close#24427
This adds ngtsc/util/src/visitor, a utility for visiting TS ASTs that
can add synthetic nodes immediately prior to certain types of nodes (e.g.
class declarations). It's useful to lift definitions that need to be
referenced repeatedly in generated code outside of the class that defines
them.
PR Close#24230
Bazel has a restriction that a single output (eg. a compiled version of
//packages/common) can only be produced by a single rule. This precludes
the Angular repo from having multiple rules that build the same code. And
the complexity of having a single rule produce multiple outputs (eg. an
ngc-compiled version of //packages/common and an Ivy-enabled version) is
too high.
Additionally, the Angular repo has lots of existing tests which could be
executed as-is under Ivy. Such testing is very valuable, and it would be
nice to share not only the code, but the dependency graph / build config
as well.
Thus, this change introduces a --define flag 'compile' with three potential
values. When --define=compile=X is set, the entire build system runs in a
particular mode - the behavior of all existing targets is controlled by
the flag. This allows us to reuse our entire build structure for testing
in a variety of different manners. The flag has three possible settings:
* legacy (the default): the traditional View Engine (ngc) build
* local: runs the prototype ngtsc compiler, which does not rely on global
analysis
* jit: runs ngtsc in a mode which executes tsickle, but excludes the
Angular related transforms, which approximates the behavior of plain
tsc. This allows the main packages such as common to be tested with
the JIT compiler.
Additionally, the ivy_ng_module() rule still exists and runs ngc in a mode
where Ivy-compiled output is produced from global analysis information, as
a stopgap while ngtsc is being developed.
PR Close#24056
This commit adds a mechanism by which the @angular/core annotations
for @Component, @Injectable, and @NgModule become decorators which,
when executed at runtime, trigger just-in-time compilation of their
associated types. The activation of these decorators is configured
by the ivy_switch mechanism, ensuring that the Ivy JIT engine does
not get included in Angular bundles unless specifically requested.
PR Close#23833
Previously, the compileComponent() and compileDirective() APIs still required
the output of global analysis, even though they only read local information
from that output.
With this refactor, compileComponent() and compileDirective() now define
their inputs explicitly, with the new interfaces R3ComponentMetadata and
R3DirectiveMetadata. compileComponentGlobal() and compileDirectiveGlobal()
are introduced and convert from global analysis output into the new metadata
format.
This refactor also splits out the view compiler into separate files as
r3_view_compiler_local.ts was getting unwieldy.
Finally, this refactor also splits out generation of DI factory functions
into a separate r3_factory utility as the logic is utilized between different
compilers.
PR Close#23545
g3 and the Angular repo have different versions of TypeScript, and
ts.updateIdentifier() has a different signature in the different versions.
There is no way to write a call to the function that will compile in both
versions simultaneously.
Instead, use ts.getMutableClone() as that has the same effect of cloning
the identifier.
PR Close#23550
This commit adds a new compiler pipeline that isn't dependent on global
analysis, referred to as 'ngtsc'. This new compiler is accessed by
running ngc with "enableIvy" set to "ngtsc". It reuses the same initialization
logic but creates a new implementation of Program which does not perform the
global-level analysis that AngularCompilerProgram does. It will be the
foundation for the production Ivy compiler.
PR Close#23455
rxjs 6.0.0 breaks strictMetadataEmit as they now publish a .d.ts file with a
structure like:
declare export class Subscription {
static EMPTY: Subscription;
}
This generates metadata which contains an error, and fails the strictMetadataEmit
validation. There is nothing a library author can do in this situation except to
set strictMetadataEmit to false.
The spirit of strictMetadataEmit is to validate that the author's library doesn't
do anything that will break downstream users. This failure is a corner case which
causes more harm than good, so this commit disables validation for metadata
collected from .d.ts files.
Fixes#22210
PR Close#23275
Lowering expressions in flat module metadata is desirable, but it won't
work without some rearchitecting. Currently the flat module index source
is added to the Program and therefore must be determined before the rest
of the transforms run. Since the lowering transform changes the set of
exports needed in the index, this creates a catch-22 in the index
generation.
This commit causes the flat module index metadata to be generated using
only those transforms which are "safe" (don't modify the index).
PR Close#23226
Currently, the flat module index metadata is produced directly from
the source metadata. The compiler, however, applies transformations
on the Typescript sources during transpilation, and also equivalent
transformations on the metadata itself. This transformed metadata
doesn't end up in the flat module index.
This changes the compiler to generate the flat module index metadata
from its transformed version instead of directly from source.
PR Close#23129
Computing the value of loadChildren does not work externally, as the CLI
needs to be able to detect the paths referenced to properly set up
codesplitting. However, internally, different approaches to codesplitting
require hashed module IDs, and the computation of those hashes involves
something like:
{path: '...', loadChildren: hashFn('module')}
ngc should lower loadChildren into an exported constant in that case.
This will never break externally, because loadChildren is always a
string externally, and a string won't get lowered.
PR Close#23088
This allows a bundle index to be re-exported by a higher-level module without fear of collisions.
Under bazel, we always set the prefix to be underscore-joined workspace, package, label
PR Close#23007
ngc knows to filter out d.ts inputs, but the logic accidentally
depended on whether it had a previous Program lying around.
Fixing that logic puts ngc on the fast code path, but in that code
path it must be able to merge tsickle EmitResults, so we need to
plumb the tsickle.mergeEmitResults function through all the intervening
APIs. The bulk of this change is that plumbing.
PR Close#22899
This adds compilation of @NgModule providers and imports into
ngInjectorDef statements in generated code. All @NgModule annotations
will be compiled and the @NgModule decorators removed from the
resultant js output.
All @Injectables will also be compiled in Ivy mode, and the decorator
removed.
PR Close#22458
BREAKING CHANGE:
The `<template>` tag was deprecated in Angular v4 to avoid collisions (i.e. when
using Web Components).
This commit removes support for `<template>`. `<ng-template>` should be used
instead.
BEFORE:
<!-- html template -->
<template>some template content</template>
# tsconfig.json
{
# ...
"angularCompilerOptions": {
# ...
# This option is no more supported and will have no effect
"enableLegacyTemplate": [true|false]
}
}
AFTER:
<!-- html template -->
<ng-template>some template content</ng-template>
PR Close#22783
Works around an issue with TypeScript 2.6 and 2.7 that causes
the tranformer emit to emit incorrect escapes for css string
literals.
Fixes: #22774
PR Close#22776
Closure has a transformation which turns:
Service.ngInjectableDef = ...;
into:
Service$ngInjectableDef = ...;
This transformation obviously breaks Ivy in a major way. The solution is
to annotate the fields as @nocollapse. However, Typescript appears to ignore
synthetic comments added to a node during a transformation, so the "right"
way to add these comments doesn't work.
As an interim measure, a post-processing step just before the compiled JS is
written to disk appends the correct comments with a regular expression.
PR Close#22691
Previously the flag would only disable the check in the case we tried to use newer tsc version.
In g3 we sometimes take a while to update tsc, but as a prerequisite of that Angular needs to be
updated first. This change enables us to update Angular and use it in g3 while g3 is being update
to the required tsc. Of course extra care is required when this check is disabled, but since we
control everything in g3, it's on us to get this right.
I don't see any preexisting tests for this, and I'm not sure how to write them right now.
I filed https://github.com/angular/angular/issues/22699
PR Close#22669
When the compiler generates a reference to an exported variable in the
same file, it inserts a synthetic ts.Identifier node. In CommonJS
output, this synthetic node would not be properly rewritten with an
`exports.` prefix.
This change sets the TS original node property on the synthetic node
we generate, which ensures TS knows to rewrite it in CommonJS output.
PR Close#22564
When angularCompilerOptions { enableResourceInlining: true }, we replace all templateUrl and styleUrls properties in @Component with template/styles
PR Close#22615
InjectionToken can be created with an ngInjectableDef, and previously
this allowed the full expressiveness of @Injectable. However, this
requires a runtime reflection system in order to generate factories
from expressed provider declarations.
Instead, this change requires scoped InjectionTokens to provide the
factory directly (likely using inject() for the arguments), bypassing
the need for a reflection system.
Fixes#22205
PR Close#22207
This commit bundles 3 important changes, with the goal of enabling tree-shaking
of services which are never injected. Ordinarily, this tree-shaking is prevented
by the existence of a hard dependency on the service by the module in which it
is declared.
Firstly, @Injectable() is modified to accept a 'scope' parameter, which points
to an @NgModule(). This reverses the dependency edge, permitting the module to
not depend on the service which it "provides".
Secondly, the runtime is modified to understand the new relationship created
above. When a module receives a request to inject a token, and cannot find that
token in its list of providers, it will then look at the token for a special
ngInjectableDef field which indicates which module the token is scoped to. If
that module happens to be in the injector, it will behave as if the token
itself was in the injector to begin with.
Thirdly, the compiler is modified to read the @Injectable() metadata and to
generate the special ngInjectableDef field as part of TS compilation, using the
PartialModules system.
Additionally, this commit adds several unit and integration tests of various
flavors to test this change.
PR Close#22005
Folding errors passed calls prevented the static reflector from
begin able to ignore errors in annotations it doesn't know as
the call to the unknown annotation was elided from the metadata.
Fixes: #21273
PR Close#21708
The "enableIvy" compiler option is the initial implementation
of the Render3 (or Ivy) code generation. This commit enables
generation generating "Hello, World" (example in the test)
but not much else. It is currenly only useful for internal Ivy
testing as Ivy is in development.
PR Close#21427
The compiler host would force any file that is in node_modules
into the list of files that needed to be type checked which
captures .js files if `allowJs` is set to `true`. This should
have only forced .d.ts files into the project to enable
generation of factories.
Fixes: #19757
Previously, this code would unconditionally add a @fileoverview
comment to generated files, and only if the contained any code at all.
However often existing fileoverview comments should be copied from the
file the generated file was originally based off of. This allows users
to e.g. include Closure Compiler directives in their original
`component.ts` file, which will then automaticallly also apply to code
generated from it.
This special cases `@license` comments, as Closure disregards directives
in comments containing `@license`.
PR Close#20870
Closure Compiler by default will report diagnostics from type checks in
any JavaScript code, including code emitted by the Angular compiler.
Disabling `checkTypes` substantially reduces warning spam for users, and
allows them to run with stricter compiler flags (e.g. treating actual
diagnostics from user code as errors).
Closure Compiler will still type check the code and use types (where
found and correct) for optimizations.
PR Close#20828
Saving `oldProgram` in `AngularCompilerProgram` instances is causing a memory leak for unemitted programs.
It's not actually used so simply not saving it fixes the memory leak.
Fix#20691
PR Close#20692
The errors produced when error were encountered while interpreting the
content of a directive was often incomprehencible. With this change
these kind of error messages should be easier to understand and diagnose.
PR Close#20459
- update to TypeScript 2.5
- point the 2.4 typings test at the previous typescript version, so we
don't break it accidentally
- widen the peerDeps from Angular packages that depend on TypeScript
- update to latest TypeScript 2.5 compatible Bazel rules
- move .bazelrc to tools/bazel.rc per https://docs.bazel.build/versions/master/best-practices.html#bazelrc
PR Close#20175
Condition: static analysis error, given:
- noResolve:true
- generateCodeForLibraries: false
- CompilerHost.getSourceFile throws on non existent files
All of these are true in G3.
PR Close#20041
* don't reexport symbols that the user already reexported
* never reexport symbols that are part of arguments of non simple function calls
Fixes#19883
PR Close#19884
This also changes the compiler so that we throw less often
on structural changes and produce a meaningful state
in the `ng.Program` in case of errors.
Related to #19951
PR Close#19953
The path mapping was broken for Windows by fc0b1d5b61.
Fixed the path mapping and put code in place to make such a problem
to sneek by again.
PR Close#19915
The error collector changes behavior of the metadata resolver
in ways that haven't been fully hardened. This changes limits
its use to the lazy route detection and the language service.
Issue: #19906
PR Close#19912
This change is needed to prevent users’ builds from breaking.
If a user sets `fullTemlateTypeCheck` to true, we will
continue to check the templates even when `skipTemplateCodegen` is true
as well.
Related to #19906
PR Close#19909
This fixes a problem introduced in 8d45fefc31
which modified how diagnostic error messages are reported for structural
metadata errors causing some of the diagnostics to be lost.
PR Close#19886
Usages of `NgTools_InternalApi_NG_2` from `@angular/compiler-cli` will now
throw an error.
Adds `listLazyRoutes` to `@angular/compiler-cli/ngtools2.ts` for getting
the lazy routes of a `ng.Program`.
PR Close#19836
References to resources (such as .css files) that are generated into
the `outDir` directory outside of `rootDir` would cause a spurious
compiler error about not being able to find a files that ends in
'.ngstyle.ts'.
Also fixed a minor issue in compiler error reporting
Fixes: #19765, #19767
PR Close#19770
If no user files changed:
- only type check the changed generated files
Never emit non changed generated files
- we still calculate them, but don’t send them through
TypeScript to emit them but cache the written files instead.
PR Close#19646
Assocating each template node with a the generated TypeScript
generated overly verbose source maps. Changed to creating a
source map entry per unique source span instead of each
unique template ast node.
Fixes: #19537
PR Close#19578
This helps hazel as it does not check libraries (e.g. the default lib) which are
not input files, but still checks `.d.ts` files that are inputs.
PR Close#19581
This is important to not confuse users nor downstream tools that
consume our source maps. For generated content for which we don’t
have an original source file, we use the generated file now.
Fixes#19538
For now, we always create all generated files, but diff them
before we pass them to TypeScript.
For the user files, we compare the programs and only emit changed
TypeScript files.
This also adds more diagnostic messages if the `—diagnostics` flag
is passed to the command line.
Closure no longer needs to have the imports rewritten avoid rewriting
as this can cause issues when the source directory structure differs
from what is deployed.
Fixes: #19026
Added the compiler options `strictInjectionParameters` that defaults
to `false`. If enabled the compiler will report errors for parameters
of an `@Injectable` that cannot be determined instead of generating a
warning.
This is planned to be switched to default to `true` for Angular 6.0.
Also adds auto upgrade from lower version based
on the .d.ts file (e.g. from version 3 to 4).
This is needed as we are now also capturing type aliases
in metadata files (and we rely on this),
see 6e3498ca8e.
introduce the option `allowEmptyCodegenFiles` to generate all generated files,
even if they are empty.
- also provides the original source files from which the file was generated
in the write file callback
- needed e.g. for G3 when copying over pinto mod names from the original component
to all generated files
use `importAs` from flat modules when writing summaries
- i.e. prevents incorrect entries like @angular/common/common in the .ngsummary.json files.
change interaction between ng and ts to prevent race conditions
- before Angular would rely on TS to first read the file for which we generate files,
and then the generated files. However, this can break easily when we reuse an old program.
don’t generate files for sources that are outside of `rootDir`
(see #19337)
With this commit `ngc` is used instead of `tsc-wrapped` for
collecting metadata and tsickle rewriting and `tsc-wrapped`
is removed from the repository.
`@angular/tsc-wrapped@5` is now deprecated and is no longer
used, updated, or maintained as part as of Angular 5.x.x.
`@angular/tsc-wrapped@4` is still maintained and required by
Angular 4.x.x and will be maintained as long as 4.x.x is in
LTS.
PR Close#19298
- don’t regenerate code for .d.ts files when
an oldProgram is passed to `createProgram`
- cache `fileExists` / `getSourceFile` / `readFile` in watch mode
- refactor tests to share common code in `test_support`
- support `—diagnostic` command line to print total time
used per watch mode compilation.
PR Close#19275
This flag controls whether the compiler emits generated files.
It is initially calculated via `skipTemplateCodegen` from the
compiler options.
Also:
- adds a small performance improvement to not generate the files
at all if we don’t emit generated code.
- removes `EmitFlags.Summaries` as we never used it.
PR Close#19275
We now create 2 programs with exactly the same fileNames and
exactly the same `import` / `export` declarations,
allowing TS to reuse the structure of first program
completely. When passing in an oldProgram and the files didn’t change,
TS can also reuse the old program completely.
This is possible buy adding generated files to TS
in `host.geSourceFile` via `ts.SourceFile.referencedFiles`.
This commit also:
- has a minor side effect on how we generate shared stylesheets:
- previously every import in a stylesheet would generate a new
`.ngstyles.ts` file.
- now, we only generate 1 `.ngstyles.ts` file per entry in `@Component.styleUrls`.
This was required as we need to be able to determine the program files
without loading the resources (which can be async).
- makes all angular related methods in `CompilerHost`
optional, allowing to just use a regular `ts.CompilerHost` as `CompilerHost`.
- simplifies the logic around `Compiler.analyzeNgModules` by introducing `NgAnalyzedFile`.
Perf impact: 1.5s improvement in compiling angular io
PR Close#19275
This speeds up the compilation process significantly.
Also introduces a new option `fullTemplateTypeCheck` to do more checks in templates:
- check expressions inside of templatized content (e.g. inside of `<div *ngIf>`).
- check the arguments of calls to the `transform` function of pipes
- check references to directives that were exposed as variables via `exportAs`
PR Close#19152
- temporarily keeps the old sources under packages/tsc-wrapped
until the build scripts are changed to use compiler-cli everywhere.
- removes the compiler options `disableTransformerPipeline` that was introduced
in a previous beta of Angular 5, i.e. the transformer based compiler
is now always enabled.
PR Close#18966
BREAKING CHANGE: the compiler option `enableLegacyTemplate` is now disabled by default as the `<template>` element has been deprecated since v4. Use `<ng-template>` instead. The option `enableLegacyTemplate` and the `<template>` element will both be removed in Angular v6.
PR Close#18756
This is a corner case, and converting them is what
was expected in G3. This also fits the fact that
we already convert package paths into relative paths.
PR Close#18912
With this change ngc now accepts a `-w` or a `--watch`
command-line option that will automatically perform a
recompile whenever any source files change on disk.
PR Close#18818
With this commit the compiler will "lower" expressions into exported
variables for values the compiler does not need to know statically
in order to be able to generate a factory. For example:
```
providers: [{provider: 'token', useValue: calculated()}]
```
produced an error as the expression `calculated()` is not supported
by the compiler because `calculated` is not a
[known function](https://angular.io/guide/metadata#annotationsdecorators)
With this commit this is rewritten, during emit of the .js file, into
something like:
```
export var ɵ0 = calculated();
...
provdiers: [{provider: 'token', useValue: ɵ0}]
```
The compiler then will now generate a reference to the exported `ɵ0`
instead of failing to evaluate `calculated()`.
PR Close#18905