Injector defs are not considered public API, so the property
that contains them should be prefixed with Angular's marker
for "private" ('ɵ') to discourage apps from relying on def
APIs directly.
This commit adds the prefix and shortens the name from
ngInjectorDef to inj. This is because property names
cannot be minified by Uglify without turning on property
mangling (which most apps have turned off) and are thus
size-sensitive.
PR Close#33151
Module defs are not considered public API, so the property
that contains them should be prefixed with Angular's marker
for "private" ('ɵ') to discourage apps from relying on def
APIs directly.
This commit adds the prefix and shortens the name from
ngModuleDef to mod. This is because property names
cannot be minified by Uglify without turning on property
mangling (which most apps have turned off) and are thus
size-sensitive.
PR Close#33142
Pipe defs are not considered public API, so the property
that contains them should be prefixed with Angular's marker
for "private" ('ɵ') to discourage apps from relying on def
APIs directly.
This commit adds the prefix and shortens the name from
ngPipeDef to pipe. This is because property names
cannot be minified by Uglify without turning on property
mangling (which most apps have turned off) and are thus
size-sensitive.
PR Close#33142
Factory defs are not considered public API, so the property
that contains them should be prefixed with Angular's marker
for "private" ('ɵ') to discourage apps from relying on def
APIs directly.
This commit adds the prefix and shortens the name from
ngFactoryDef to fac. This is because property names
cannot be minified by Uglify without turning on property
mangling (which most apps have turned off) and are thus
size-sensitive.
Note that the other "defs" (ngPipeDef, etc) will be
prefixed and shortened in follow-up PRs, in an attempt to
limit how large and conflict-y this change is.
PR Close#33116
Prior to this change, a static attribute that corresponds with a
directive's input would not be type-checked against the type of the
input. This is unfortunate, as a static value always has type `string`,
whereas the directive's input type might be something different. This
typically occurs when a developer forgets to enclose the attribute name
in brackets to make it a property binding.
This commit lets static attributes be considered as bindings with string
values, so that they will be properly type-checked.
PR Close#33066
This commit introduces an internal config option of the template type
checker that allows to disable strict null checks of input bindings to
directives. This may be particularly useful when a directive is from a
library that is not compiled with `strictNullChecks` enabled.
Right now, strict null checks are enabled when `fullTemplateTypeCheck`
is turned on, and disabled when it's off. In the near future, several of
the internal configuration options will be added as public Angular
compiler options so that users can have fine-grained control over which
areas of the template type checker to enable, allowing for a more
incremental migration strategy.
PR Close#33066
Prior to this change, the template type checker would always allow a
value of type `undefined` to be passed into a directive's inputs, even
if the input's type did not allow for it. This was due to how the type
constructor for a directive was generated, where a `Partial` mapped
type was used to allow for inputs to be unset. This essentially
introduces the `undefined` type as acceptable type for all inputs.
This commit removes the `Partial` type from the type constructor, which
means that we can no longer omit any properties that were unset.
Instead, any properties that are not set will still be included in the
type constructor call, having their value assigned to `any`.
Before:
```typescript
class NgForOf<T> {
static ngTypeCtor<T>(init: Partial<Pick<NgForOf<T>,
'ngForOf'|'ngForTrackBy'|'ngForTemplate'>>): NgForOf<T>;
}
NgForOf.ngTypeCtor(init: {ngForOf: ['foo', 'bar']});
```
After:
```typescript
class NgForOf<T> {
static ngTypeCtor<T>(init: Pick<NgForOf<T>,
'ngForOf'|'ngForTrackBy'|'ngForTemplate'>): NgForOf<T>;
}
NgForOf.ngTypeCtor(init: {
ngForOf: ['foo', 'bar'],
ngForTrackBy: null as any,
ngForTemplate: null as any,
});
```
This change only affects generated type check code, the generated
runtime code is not affected.
Fixes#32690
Resolves FW-1606
PR Close#33066
Currently, method `getVarDeclarations()` does not try to resolve the type of
exported variable from *ngIf directive. It always returns `any` type.
By resolving the real type of exported variable, it is now possible to use this
type information in language service and provide completions, go to definition
and quick info functionality in expressions that use exported variable.
Also language service will provide more accurate diagnostic errors during
development.
PR Close#33016
Currently, the spans of expressions are recorded only relative to the
template node that they reside in, not their source file.
Introduce a `sourceSpan` property on expression ASTs that records the
location of an expression relative to the entire source code file that
it is in. This may allow for reducing duplication of effort in
ngtsc/typecheck/src/diagnostics later on as well.
Child of #31898
PR Close#31897
Directive defs are not considered public API, so the property
that contains them should be prefixed with Angular's marker
for "private" ('ɵ') to discourage apps from relying on def
APIs directly.
This commit adds the prefix and shortens the name from
ngDirectiveDef to dir. This is because property names
cannot be minified by Uglify without turning on property
mangling (which most apps have turned off) and are thus
size-sensitive.
Note that the other "defs" (ngFactoryDef, etc) will be
prefixed and shortened in follow-up PRs, in an attempt to
limit how large and conflict-y this change is.
PR Close#33110
For elements in a template that look like custom elements, i.e.
containing a dash in their name, the template type checker will now
issue an error with instructions on how the resolve the issue.
Additionally, a property binding to a non-existent property will also
produce a more descriptive error message.
Resolves FW-1597
PR Close#33064
Component defs are not considered public API, so the property
that contains them should be prefixed with Angular's marker
for "private" ('ɵ') to discourage apps from relying on def
APIs directly.
This commit adds the prefix and shortens the name from
`ngComponentDef` to `cmp`. This is because property names
cannot be minified by Uglify without turning on property
mangling (which most apps have turned off) and are thus
size-sensitive.
Note that the other "defs" (ngDirectiveDef, etc) will be
prefixed and shortened in follow-up PRs, in an attempt to
limit how large and conflict-y this change is.
PR Close#33088
For v9 we want the migration to the new i18n to be as
simple as possible.
Previously the developer had to positively choose to use
legacy messsage id support in the case that their translation
files had not been migrated to the new format by setting the
`legacyMessageIdFormat` option in tsconfig.json to the format
of their translation files.
Now this setting has been changed to `enableI18nLegacyMessageFormat`
as is a boolean that defaults to `true`. The format is then read from
the `i18nInFormat` option, which was previously used to trigger translations
in the pre-ivy angular compiler.
PR Close#33053
The `$localize` library uses a new message digest function for
computing message ids. This means that translations in legacy
translation files will no longer match the message ids in the code
and so will not be translated.
This commit adds the ability to specify the format of your legacy
translation files, so that the appropriate message id can be rendered
in the `$localize` tagged strings. This results in larger code size
and requires that all translations are in the legacy format.
Going forward the developer should migrate their translation files
to use the new message id format.
PR Close#32937
This PR updates Angular to compile with TypeScript 3.6 while retaining
compatibility with TS3.5. We achieve this by inserting several `as any`
casts for compatiblity around `ts.CompilerHost` APIs.
PR Close#32908
Metadata blocks are delimited by colons. Previously the code naively just
looked for the next colon in the string as the end marker.
This commit supports escaping colons within the metadata content.
The Angular compiler has been updated to add escaping as required.
PR Close#32867
Previously the metadata and placeholder blocks were serialized in
a variety of places. Moreover the code for creating the `LocalizedString`
AST node was doing serialization, which break the separation of concerns.
Now this is all done by the code that renders the AST and is refactored into
helper functions to avoid repeating the behaviour.
PR Close#32867
With #31953 we moved the factories for components, directives and pipes into a new field called `ngFactoryDef`, however I decided not to do it for injectables, because they needed some extra logic. These changes set up the `ngFactoryDef` for injectables as well.
For reference, the extra logic mentioned above is that for injectables we have two code paths:
1. For injectables that don't configure how they should be instantiated, we create a `factory` that proxies to `ngFactoryDef`:
```
// Source
@Injectable()
class Service {}
// Output
class Service {
static ngInjectableDef = defineInjectable({
factory: () => Service.ngFactoryFn(),
});
static ngFactoryFn: (t) => new (t || Service)();
}
```
2. For injectables that do configure how they're created, we keep the `ngFactoryDef` and generate the factory based on the metadata:
```
// Source
@Injectable({
useValue: DEFAULT_IMPL,
})
class Service {}
// Output
export class Service {
static ngInjectableDef = defineInjectable({
factory: () => DEFAULT_IMPL,
});
static ngFactoryFn: (t) => new (t || Service)();
}
```
PR Close#32433
Prior to this change, the template source mapping details were always
built during the analysis phase, under the assumption that pre-analysed
templates would always correspond with external templates. This has
turned out to be a false assumption, as inline templates are also
pre-analyzed to be able to preload any stylesheets included in the
template.
This commit fixes the bug by capturing the template source mapping
details at the moment the template is parsed, which is either during the
preanalysis phase when preloading is available, or during the analysis
phase when preloading is not supported.
Tests have been added to exercise the template error mapping in
asynchronous compilations where preloading is enabled, similar to how
the CLI performs compilations.
Fixes#32538
PR Close#32544
This commit changes the Angular compiler (ivy-only) to generate `$localize`
tagged strings for component templates that use `i18n` attributes.
BREAKING CHANGE
Since `$localize` is a global function, it must be included in any applications
that use i18n. This is achieved by importing the `@angular/localize` package
into an appropriate bundle, where it will be executed before the renderer
needs to call `$localize`. For CLI based projects, this is best done in
the `polyfills.ts` file.
```ts
import '@angular/localize';
```
For non-CLI applications this could be added as a script to the index.html
file or another suitable script file.
PR Close#31609
The Angular compiler has an emulation system for various kinds of
filesystems and runs its testcases for all those filesystems. This
allows to verify that the compiler behaves correctly in all of the
supported platforms, without needing to run the tests on the actual
platforms.
Previously, the emulated Windows mode would normalize rooted paths to
always include a drive letter, whereas the native mode did not perform
this normalization. The consequence of this discrepancy was that running
the tests in native Windows was behaving differently compared to how
emulated Windows mode behaves, potentially resulting in test failures
in native Windows that would succeed for emulated Windows.
This commit adds logic to ensure that paths are normalized equally for
emulated Windows and native Windows mode, therefore resolving the
discrepancy.
PR Close#31996
Reworks the compiler to output the factories for directives, components and pipes under a new static field called `ngFactoryFn`, instead of the usual `factory` property in their respective defs. This should eventually allow us to inject any kind of decorated class (e.g. a pipe).
**Note:** these changes are the first part of the refactor and they don't include injectables. I decided to leave injectables for a follow-up PR, because there's some more cases we need to handle when it comes to their factories. Furthermore, directives, components and pipes make up most of the compiler output tests that need to be refactored and it'll make follow-up PRs easier to review if the tests are cleaned up now.
This is part of the larger refactor for FW-1468.
PR Close#31953
In ngc is was valid to set the "flatModuleOutFile" option to "null". This is sometimes
necessary if a tsconfig extends from another one but the "fatModuleOutFile" option
needs to be unset (note that "undefined" does not exist as value in JSON)
Now if ngtsc is used to compile the project, ngtsc will fail with an error because it
tries to do string manipulation on the "flatModuleOutFile". This happens because
ngtsc only skips flat module indices if the option is set to "undefined".
Since this is not compatible with what was supported in ngc and such exceptions
should be avoided, the flat module check is now aligned with ngc.
```
TypeError: Cannot read property 'replace' of null
at Object.normalizeSeparators (/home/circleci/project/node_modules/@angular/compiler-cli/src/ngtsc/util/src/path.js:35:21)
at new NgtscProgram (/home/circleci/project/node_modules/@angular/compiler-cli/src/ngtsc/program.js:126:52)
```
Additionally setting the `flatModuleOutFile` option to an empty string
currently results in unexpected behavior. No errors is thrown, but the
flat module index file will be `.ts` (no file name; just extension).
This is now also fixed by treating an empty string similarly to
`null`.
PR Close#32235
Previously, ngtsc attempted to use the .d.ts schema for HTML elements to
check bindings to DOM properties. However, the TypeScript lib.dom.d.ts
schema does not perfectly align with the Angular DomElementSchemaRegistry,
and these inconsistencies would cause issues in apps. There is also the
concern of supporting both CUSTOM_ELEMENTS_SCHEMA and NO_ERRORS_SCHEMA which
would have been very difficult to do in the existing system.
With this commit, the DomElementSchemaRegistry is employed in ngtsc to check
bindings to the DOM. Previous work on producing template diagnostics is used
to support generation of this different kind of error with the same high
quality of error message.
PR Close#32171
Historically, the Angular Compiler has produced both native TypeScript
diagnostics (called ts.Diagnostics) and its own internal Diagnostic format
(called an api.Diagnostic). This was done because TypeScript ts.Diagnostics
cannot be produced for files not in the ts.Program, and template type-
checking diagnostics are naturally produced for external .html template
files.
This design isn't optimal for several reasons:
1) Downstream tooling (such as the CLI) must support multiple formats of
diagnostics, adding to the maintenance burden.
2) ts.Diagnostics have gotten a lot better in recent releases, with support
for suggested changes, highlighting of the code in question, etc. None of
these changes have been of any benefit for api.Diagnostics, which have
continued to be reported in a very primitive fashion.
3) A future plugin model will not support anything but ts.Diagnostics, so
generating api.Diagnostics is a blocker for ngtsc-as-a-plugin.
4) The split complicates both the typings and the testing of ngtsc.
To fix this issue, this commit changes template type-checking to produce
ts.Diagnostics instead. Instead of reporting a special kind of diagnostic
for external template files, errors in a template are always reported in
a ts.Diagnostic that highlights the portion of the template which contains
the error. When this template text is distinct from the source .ts file
(for example, when the template is parsed from an external resource file),
additional contextual information links the error back to the originating
component.
A template error can thus be reported in 3 separate ways, depending on how
the template was configured:
1) For inline template strings which can be directly mapped to offsets in
the TS code, ts.Diagnostics point to real ranges in the source.
This is the case if an inline template is used with a string literal or a
"no-substitution" string. For example:
```typescript
@Component({..., template: `
<p>Bar: {{baz}}</p>
`})
export class TestCmp {
bar: string;
}
```
The above template contains an error (no 'baz' property of `TestCmp`). The
error produced by TS will look like:
```
<p>Bar: {{baz}}</p>
~~~
test.ts:2:11 - error TS2339: Property 'baz' does not exist on type 'TestCmp'. Did you mean 'bar'?
```
2) For template strings which cannot be directly mapped to offsets in the
TS code, a logical offset into the template string will be included in
the error message. For example:
```typescript
const SOME_TEMPLATE = '<p>Bar: {{baz}}</p>';
@Component({..., template: SOME_TEMPLATE})
export class TestCmp {
bar: string;
}
```
Because the template is a reference to another variable and is not an
inline string constant, the compiler will not be able to use "absolute"
positions when parsing the template. As a result, errors will report logical
offsets into the template string:
```
<p>Bar: {{baz}}</p>
~~~
test.ts (TestCmp template):2:15 - error TS2339: Property 'baz' does not exist on type 'TestCmp'.
test.ts:3:28
@Component({..., template: TEMPLATE})
~~~~~~~~
Error occurs in the template of component TestCmp.
```
This error message uses logical offsets into the template string, and also
gives a reference to the `TEMPLATE` expression from which the template was
parsed. This helps in locating the component which contains the error.
3) For external templates (templateUrl), the error message is delivered
within the HTML template file (testcmp.html) instead, and additional
information contextualizes the error on the templateUrl expression from
which the template file was determined:
```
<p>Bar: {{baz}}</p>
~~~
testcmp.html:2:15 - error TS2339: Property 'baz' does not exist on type 'TestCmp'.
test.ts:10:31
@Component({..., templateUrl: './testcmp.html'})
~~~~~~~~~~~~~~~~
Error occurs in the template of component TestCmp.
```
PR Close#31952
When a template contains a binding without a value, the template parser
creates an `EmptyExpr` node. This would previously be translated into
an `undefined` value, which would cause a crash downstream as `undefined`
is not included in the allowed type, so it was not handled properly.
This commit prevents the crash by returning an actual expression for empty
bindings.
Fixes#30076Fixes#30929
PR Close#31594
This commit switches the default value of the enableIvy flag to true.
Applications that run ngc will now by default receive an Ivy build!
This does not affect the way Bazel builds in the Angular repo work, since
those are still switched based on the value of the --define=compile flag.
Additionally, projects using @angular/bazel still use View Engine builds
by default.
Since most of the Angular repo tests are still written against View Engine
(particularly because we still publish VE packages to NPM), this switch
also requires lots of `enableIvy: false` flags in tsconfigs throughout the
repo.
Congrats to the team for reaching this milestone!
PR Close#32219
This option makes ngc behave as tsc, and was originally implemented before
ngtsc existed. It was designed so we could build JIT-only versions of
Angular packages to begin testing Ivy early, and is not used at all in our
current setup.
PR Close#32219
One of the compiler's tasks is to enumerate the exports of a given ES
module. This can happen for example to resolve `foo.bar` where `foo` is a
namespace import:
```typescript
import * as foo from './foo';
@NgModule({
directives: [foo.DIRECTIVES],
})
```
In this case, the compiler must enumerate the exports of `foo.ts` in order
to evaluate the expression `foo.DIRECTIVES`.
When this operation occurs under ngcc, it must deal with the different
module formats and types of exports that occur. In commonjs code, a problem
arises when certain exports are downleveled.
```typescript
export const DIRECTIVES = [
FooDir,
BarDir,
];
```
can be downleveled to:
```javascript
exports.DIRECTIVES = [
FooDir,
BarDir,
```
Previously, ngtsc and ngcc expected that any export would have an associated
`ts.Declaration` node. `export class`, `export function`, etc. all retain
`ts.Declaration`s even when downleveled. But the `export const` construct
above does not. Therefore, ngcc would not detect `DIRECTIVES` as an export
of `foo.ts`, and the evaluation of `foo.DIRECTIVES` would therefore fail.
To solve this problem, the core concept of an exported `Declaration`
according to the `ReflectionHost` API is split into a `ConcreteDeclaration`
which has a `ts.Declaration`, and an `InlineDeclaration` which instead has
a `ts.Expression`. Differentiating between these allows ngcc to return an
`InlineDeclaration` for `DIRECTIVES` and correctly keep track of this
export.
PR Close#32129
Previously if only a component template changed then we would know to
rebuild its component source file. But the compilation was incorrect if the
component was part of an NgModule, since we were not capturing the
compilation scope information that had a been acquired from the NgModule
and was not being regenerated since we were not needing to recompile
the NgModule.
Now we register compilation scope information for each component, via the
`ComponentScopeRegistry` interface, so that it is available for incremental
compilation.
The `ComponentDecoratorHandler` now reads the compilation scope from a
`ComponentScopeReader` interface which is implemented as a compound
reader composed of the original `LocalModuleScopeRegistry` and the
`IncrementalState`.
Fixes#31654
PR Close#31932
If a project being built with ngtsc has no templates to check, then ngtsc
previously generated an empty typecheck file. This seems to trigger some
pathological behavior in TS where the entire user program is re-checked,
which is extremely expensive. This likely has to do with the fact that the
empty file is not considered an ES module, meaning the module structure of
the program has changed.
This commit causes an export to be produced in the typecheck file regardless
of its other contents, which guarantees that it will be an ES module. The
pathological behavior is avoided and template type-checking is fast once
again.
PR Close#31922
Describe the indexer module for Angular compiler developers. Include
scope of analysis provided by the module and the indexers it targets as
first-party.
PR Close#31260
In #30181, several testcases were added that were failing in Windows.
The reason was that a recent rebase missed a required change to interact
with the compiler's virtualized filesystems. This commit introduces the
required usage of the VFS layer to fix the testcase.
PR Close#31860
`TemplateVisitor#visitBoundAttribute` currently has to invoke visiting
expressions manually (this is fixed in #31813). Previously, it did not
bind `targetToIdentifier` to the visitor before deferring to the
expression visitor, which breaks the `targetToIdentifier` code. This
fixes that and adds a test to ensure the closure processed correctly.
This change is urgent; without it, many indexing targets in g3 are
broken.
PR Close#31861
Template AST nodes for (bound) attributes, variables and references will
now retain a reference to the source span of their value, which allows
for more accurate type check diagnostics.
PR Close#30181
The type check blocks (TCB) that ngtsc generates for achieving type
checking of Angular templates needs to be annotated with positional
information in order to translate TypeScript's diagnostics for the TCB
code back to the location in the user's template. This commit augments
the TCB by attaching trailing comments with AST nodes, such that a node
can be traced back to its source location.
PR Close#30181
Adds support for indexing template referenecs, variables, and property
and method calls inside bound attributes and bound events. This is
mostly an extension of the existing indexing infrastructure.
PR Close#31535
Extend indexing API interface to provide information about used
directives' selectors on template elements. This enables an indexer to
xref element attributes to the directives that match them.
The current way this matching is done is by mapping selectors to indexed
directives. However, this fails in cases where the directive is not
indexed by the indexer API, like for transitive dependencies. This
solution is much more general.
PR Close#31782
When analyzing components, directives, etc we capture its base class.
Previously this assumed that the code is in TS format, which is not
always the case (e.g. ngcc).
Now this code is replaced with a call to
`ReflectionHost.getBaseClassExpression()`, which abstracts the work
of finding the base class.
PR Close#31544
Previously the last file-system being tested was left as the current
file-system. Now it is reset to an `InvalidFileSystem` to ensure future
tests are not affected.
PR Close#31544
When injecting a `ChangeDetectorRef` into a pipe, the expected result is that the ref will be tied to the component in which the pipe is being used. This works for most cases, however when a pipe is used inside a property binding of a component (see test case as an example), the current `TNode` is pointing to component's host so we end up injecting the inner component's view. These changes fix the issue by only looking up the component view of the `TNode` if the `TNode` is a parent.
This PR resolves FW-1419.
PR Close#31438
Currently, template expressions and statements have their location
recorded relative to the HTML element they are in, with no handle to
absolute location in a source file except for a line/column location.
However, the line/column location is also not entirely accurate, as it
points an entire semantic expression, and not necessarily the start of
an expression recorded by the expression parser.
To support record of the source code expressions originate from, add a
new `sourceSpan` field to `ASTWithSource` that records the absolute byte
offset of an expression within a source code.
Implement part 2 of [refactoring template parsing for
stability](https://hackmd.io/@X3ECPVy-RCuVfba-pnvIpw/BkDUxaW84/%2FMA1oxh6jRXqSmZBcLfYdyw?type=book).
PR Close#31391
Versions of CLI prior to angular/angular-cli@0e339ee did not expose the host.getModifiedResourceFiles() method.
This meant that null was being passed through to the IncrementalState.reconcile() method
to indicate that there were either no changes or the host didn't support that method.
This commit fixes a bug where we were checking for undefined rather than null when
deciding whether any resource files had changed, causing a null reference error to be thrown.
This bug was not caught by the unit testing because the tests set up the changed files
via a slightly different process, not having access to the CompilerHost, and these test
were making the erroneous assumption that undefined indicated that there were no
changed files.
PR Close#31322
Previously, the usage of `null` and `undefined` keywords in code that is
statically interpreted by ngtsc resulted in a `DynamicValue`, as they were
not recognized as special entities. This commit adds support to interpret
these keywords.
PR Close#31150
The support for decorators that were imported via a namespace,
e.g. `import * as core from `@angular/core` was implemented
piecemeal. This meant that it was easy to miss situations where
a decorator identifier needed to be handled as a namepsaced
import rather than a direct import.
One such issue was that UMD processing of decorators was not
correct: the namespace was being omitted from references to
decorators.
Now the types have been modified to make it clear that a
`Decorator.identifier` could hold a namespaced identifier,
and the corresponding code that uses these types has been
fixed.
Fixes#31394
PR Close#31426
Add support for indexing elements in the indexing module.
Opening and self-closing HTML tags have their selector indexed, as well
as the attributes on the element and the directives applied to an
element.
PR Close#31240
Previously, resource paths beginning with '/' (aka "rooted" paths, which
are not actually absolute filesystem paths, but are relative to the
TypeScript project root directory) were not handled correctly. The leading
'/' was stripped and the path was resolved as if it was relative, but with
no containing file for context. This led to resources in different rootDirs
not being found.
Instead, such rooted paths are now resolved without TypeScript's help, by
checking each root directory. A test is added to this effect.
PR Close#31511
When profiling ngcc it is notable that a large amount of time
is spent dealing with an exception that is thrown (and handled
internally by fs) when checking the existence of a file.
We check file existence a lot in both finding entry-points
and when TS is compiling code. This commit adds a simple
cached `FileSystem`, which wraps a real `FileSystem` delegate.
This will reduce the number of calls through to `fs.exists()` and
`fs.readFile()` on the delegate.
Initial benchmarks indicate that the cache is miss to hit ratio
for `exists()` is about 2:1, which means that we save about 1/3
of the calls to `fs.existsSync()`.
Note that this implements a "non-expiring" cache, so it is not suitable
for a long lived `FileSystem`, where files may be modified externally.
The cache will be updated if a file is changed or moved via
calls to `FileSystem` methods but it will not be aware of changes
to the files system from outside the `FileSystem` service.
For ngcc we must create a new `FileSystem` service
for each run of `mainNgcc` and ensure that all file operations
(including TS compilation) use the `FileSystem` service.
This ensures that it is very unlikely that a file will change
externally during `mainNgcc` processing.
PR Close#30525
The ngcc tool adds namespaced imports to files when compiling. The ngtsc
tooling was not processing types correctly when they were imported via
such namespaces. For example:
```
export declare class SomeModule {
static withOptions(...): ModuleWithProviders<ɵngcc1.BaseModule>;
```
In this case the `BaseModule` was being incorrectly attributed to coming
from the current module rather than the imported module, represented by
`ɵngcc1`.
Fixes#31342
PR Close#31367
When a class uses Angular decorators such as `@Input`, `@Output` and
friends without an Angular class decorator, they are compiled into a
static `ngBaseDef` field on the class, with the TypeScript declaration
of the class being altered to declare the `ngBaseDef` field to be of type
`ɵɵBaseDef`. This type however requires a generic type parameter that
corresponds with the type of the class, however the compiler did not
provide this type parameter. As a result, compiling a program where such
invalid `ngBaseDef` declarations are present will result in compilation
errors.
This commit fixes the problem by providing the generic type parameter.
Fixes#31160
PR Close#31210
The TS compiler is likely to test paths with extensions and try to
load them as files. Therefore `fileExists()` and methods that rely
on it need to be able to distinguish between real files and directories
that have paths that look like files.
This came up as a bug in ngcc when trying to process `ngx-virtual-scroller`,
which relies upon a library called `@tweenjs/tween.js`.
PR Close#31289
Previously we expected the constructor parameter `decorators`
property to be an array wrapped in a function. Now we also support
an array not wrapped in a function.
PR Close#30591
To improve cross platform support, all file access (and path manipulation)
is now done through a well known interface (`FileSystem`).
For testing a number of `MockFileSystem` implementations are provided.
These provide an in-memory file-system which emulates operating systems
like OS/X, Unix and Windows.
The current file system is always available via the static method,
`FileSystem.getFileSystem()`. This is also used by a number of static
methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass
`FileSystem` objects around all the time. The result of this is that one
must be careful to ensure that the file-system has been initialized before
using any of these static methods. To prevent this happening accidentally
the current file system always starts out as an instance of `InvalidFileSystem`,
which will throw an error if any of its methods are called.
You can set the current file-system by calling `FileSystem.setFileSystem()`.
During testing you can call the helper function `initMockFileSystem(os)`
which takes a string name of the OS to emulate, and will also monkey-patch
aspects of the TypeScript library to ensure that TS is also using the
current file-system.
Finally there is the `NgtscCompilerHost` to be used for any TypeScript
compilation, which uses a given file-system.
All tests that interact with the file-system should be tested against each
of the mock file-systems. A series of helpers have been provided to support
such tests:
* `runInEachFileSystem()` - wrap your tests in this helper to run all the
wrapped tests in each of the mock file-systems.
* `addTestFilesToFileSystem()` - use this to add files and their contents
to the mock file system for testing.
* `loadTestFilesFromDisk()` - use this to load a mirror image of files on
disk into the in-memory mock file-system.
* `loadFakeCore()` - use this to load a fake version of `@angular/core`
into the mock file-system.
All ngcc and ngtsc source and tests now use this virtual file-system setup.
PR Close#30921
Prior to this commit, the logic to extract query information from class fields used an instance of regular Error class to throw an error. As a result, some useful information (like reference to a specific field) was missing. Replacing Error class with FatalDiagnosticError one makes the error more verbose that should simplify debugging.
PR Close#31123
Add an IndexingContext class to store indexing information and a
transformer module to generate indexing analysis. Integrate the indexing
module with the rest of NgtscProgram and add integration tests.
Closes#30959
PR Close#31151
Previously, the usage of equality operators ==, ===, != and !== was not
supported in ngtsc's static interpreter. This commit adds support for
such operators and includes tests.
Fixes#31076
PR Close#31145
Optimizations to skip compiling source files that had not changed
did not account for the case where only a resource file changes,
such as an external template or style file.
Now we track such dependencies and trigger a recompilation
if any of the previously tracked resources have changed.
This will require a change on the CLI side to provide the list of
resource files that changed to trigger the current compilation by
implementing `CompilerHost.getModifiedResourceFiles()`.
Closes#30947
PR Close#30954
This commit fixes a couple of issues with TS 3.5 compatibility in order to
unblock migration of g3. Mostly 'any's are added, and there are no behavior
changes.
PR Close#31174
Add support for indexing of property reads, method calls in a template.
Visit AST of template syntax expressions to extract identifiers.
Child of #30959
PR Close#30963
The usage of array spread syntax in source code may be downleveled to a
call to TypeScript's `__spread` helper function from `tslib`, depending
on the options `downlevelIteration` and `emitHelpers`. This proves
problematic for ngcc when it is processing ES5 formats, as the static
evaluator won't be able to interpret those calls.
A custom foreign function resolver is not sufficient in this case, as
`tslib` may be emitted into the library code itself. In that case, a
helper function can be resolved to an actual function with body, such
that it won't be considered as foreign function. Instead, a reflection
host can now indicate that the definition of a function corresponds with
a certain TypeScript helper, such that it becomes statically evaluable
in ngtsc.
Resolves#30299
PR Close#30492
When an `ng-template` element has a variable declaration without a value,
it is assigned the value of the `$implicit` property in the embedded view's
context. The template compiler inserts a property access to `$implicit` for
template variables without a value, however the type-check code generation
logic did not. This resulted in incorrect type-checking code being generated.
Fixes FW-1326
PR Close#30675
Some HTML attributes don't correspond to their DOM property name, in which
case the runtime will apply the appropriate transformation when assigning
a property using its attribute name. One example of this is the `for`
attribute, for which the DOM property is named `htmlFor`.
The type-checking machinery in ngtsc must also take this mapping into
account, as it generates type-check code in which unclaimed property bindings
are assigned to properties of (subtypes of) `HTMLElement`.
Fixes#30607
Fixes FW-1327
PR Close#30675
Prior to this commit there were no explicit types setup for NgModuleFactory calls in ngfactories, so TypeScript inferred the type based on a given call. In some cases (when generic types were used for Components/Directives) that turned out to be problematic, so we add explicit typing for NgModuleFactory calls.
PR Close#30708
Plural ICU expressions depend on the locale (different languages have different plural forms). Until now the locale was hard coded as `en-US`.
For compatibility reasons, if you use ivy with AOT and bootstrap your app with `bootstrapModule` then the `LOCALE_ID` token will be set automatically for ivy, which is then used to get the correct plural form.
If you use JIT, you need to define the `LOCALE_ID` provider on the module that you bootstrap.
For `TestBed` you can use either `configureTestingModule` or `overrideProvider` to define that provider.
If you don't use the compat mode and start your app with `renderComponent` you need to call `ɵsetLocaleId` manually to define the `LOCALE_ID` before bootstrap. We expect this to change once we start adding the new i18n APIs, so don't rely on this function (there's a reason why it's a private export).
PR Close#29249
The AbsoluteModuleStrategy in ngtsc assumed that the source code is
formatted as TypeScript with regards to module exports.
In ngcc this is not always the case, so this commit changes
`AbsoluteModuleStrategy` so that it relies upon a `ReflectionHost` to
compute the exports of a module.
PR Close#30200
There is an encoding issue with using delta `Δ`, where the browser will attempt to detect the file encoding if the character set is not explicitly declared on a `<script/>` tag, and Chrome will find the `Δ` character and decide it is window-1252 encoding, which misinterprets the `Δ` character to be some other character that is not a valid JS identifier character
So back to the frog eyes we go.
```
__
/ɵɵ\
( -- ) - I am ineffable. I am forever.
_/ \_
/ \ / \
== == ==
```
PR Close#30546
Previously we defensively wrapped expressions in case they ran afoul of
precedence rules. For example, it would be easy to create the TS AST structure
Call(Ternary(a, b, c)), but might result in printed code of:
```
a ? b : c()
```
Whereas the actual structure we meant to generate is:
```
(a ? b : c)()
```
However the TypeScript renderer appears to be clever enough to provide
parenthesis as necessary.
This commit removes these defensive paraenthesis in the cases of binary
and ternary operations.
FW-1273
PR Close#30349
Previously, interpolations were generated into TCBs as a comma-separated
list of expressions, letting TypeScript infer the type of the expression
as the type of the last expression in the chain. This is undesirable, as
interpolations always result in a string type at runtime. Therefore,
type-checking of bindings such as `<img src="{{ link }}"/>` where `link`
is an object would incorrectly report a type-error.
This commit adjusts the emitted TCB code for interpolations, where a
chain of string concatenations is emitted, starting with the empty string.
This ensures that the inferred type of the interpolation is of type string.
PR Close#30177
In some cases the `forwardRef` helper has been imported via a namespace,
e.g. `core.forwardRef(...)`.
This commit adds support for unwrapping such namespaced imports when
ngtsc is statically evaluating code.
PR Close#25445
Previously we were using an anonymous type `{specifier: string; qualifier: string;}`
throughout the code base. This commit gives this type a name and ensures it
is only defined in one place.
PR Close#25445
Previously, ngtsc would fail to evaluate expressions that access properties
from e.g. the `window` object. This resulted in hard to debug error messages
as no indication on where the problem originated was present in the output.
This commit cleans up the handling of unknown property accesses, such that
evaluating such expressions no longer fail but instead result in a `DynamicValue`.
Fixes#30226
PR Close#30247
A structural directive can specify a template guard for an input, such that
the type of that input's binding can be narrowed based on the guard's return
type. Previously, such template guards could only be methods, of which an
invocation would be inserted into the type-check block (TCB). For `NgIf`,
the template guard narrowed the type of its expression to be `NonNullable`
using the following declaration:
```typescript
export declare class NgIf {
static ngTemplateGuard_ngIf<E>(dir: NgIf, expr: E): expr is NonNullable<E>
}
```
This works fine for usages such as `*ngIf="person"` but starts to introduce
false-positives when e.g. an explicit non-null check like
`*ngIf="person !== null"` is used, as the method invocation in the TCB
would not have the desired effect of narrowing `person` to become
non-nullable:
```typescript
if (NgIf.ngTemplateGuard_ngIf(directive, ctx.person !== null)) {
// Usages of `ctx.person` within this block would
// not have been narrowed to be non-nullable.
}
```
This commit introduces a new strategy for template guards to allow for the
binding expression itself to be used as template guard in the TCB. Now,
the TCB generated for `*ngIf="person !== null"` would look as follows:
```typescript
if (ctx.person !== null) {
// This time `ctx.person` will successfully have
// been narrowed to be non-nullable.
}
```
This strategy can be activated by declaring the template guard as a
property declaration with `'binding'` as literal return type.
See #30235 for an example where this led to a false positive.
PR Close#30248
Preserve compatibility with rollup_bundle rule.
Add missing npm dependencies, which are now enforced by the strict_deps plugin in tsc_wrapped
PR Close#30370
At the moment the module resolver will end up in an infinite loop in Windows because we are assuming that the root directory is always `/` however in windows this can be any drive letter example `c:/` or `d:/` etc...
With this change we also resolve the drive letter in windows, when using `AbsoluteFsPath.from` for consistence so under `/foo` will be converted to `c:/foo` this is also needed because of relative paths with different drive letters.
PR Close#30297
Currently in Ivy `NgModule` registration happens when the class is declared, however this is inconsistent with ViewEngine and requires extra generated code. These changes remove the generated code for `registerModuleFactory`, pass the id through to the `ngModuleDef` and do the module registration inside `NgModuleFactory.create`.
This PR resolves FW-1285.
PR Close#30244
```
//packages/compiler-cli/test:ngc
//packages/compiler/test:test
```
This also address `node_modules` to the ignored paths for ngc compiler as otherwise the `ready` is never fired
Partially addresses #29785
PR Close#30146
Now that the dependent files and compilation scopes are being tracked in
the incremental state, we can skip analysing and emitting source files if
none of their dependent files have changed since the last compile.
The computation of what files (and their dependencies) are unchanged is
computed during reconciliation.
This commit also removes the previous emission skipping logic, since this
approach covers those cases already.
PR Close#30238
To support skipping analysis of a file containing a component
we need to know that none of the declarations that might affect
its ngtsc compilation have not changed. The files that we need to
check are those that contain classes from the `CompilationScope`
of the component. These classes are already tracked in the
`LocalModuleScopeRegistry`.
This commit modifies the `IvyCompilation` class to record the
files that are in each declared class's `CompilationScope` via
a new method, `recordNgModuleScopeDependencies()`, that is called
after all the handlers have been "resolved".
Further, if analysis is skipped for a declared class, then we need
to recover the analysis from the previous compilation run. To
support this, the `IncrementalState` class has been updated to
expose the `MetadataReader` and `MetadataRegistry` interfaces.
This is included in the `metaRegistry` object to capture these analyses,
and also in the `localMetaReader` as a fallback to use if the
current compilation analysis was skipped.
PR Close#30238
As part of incremental compilation performance improvements, we need
to track the dependencies of files due to expressions being evaluated by
the `PartialEvaluator`.
The `PartialEvaluator` now accepts a `DependencyTracker` object, which is
used to track which files are visited when evaluating an expression.
The interpreter computes this `originatingFile` and stores it in the evaluation
`Context` so it can pass this to the `DependencyTracker.
The `IncrementalState` object implements this interface, which allows it to be
passed to the `PartialEvaluator` and so capture the file dependencies.
PR Close#30238
Sometimes we need to override module resolution behaviour.
We do this by implementing the optional method `resolveModuleNames()`
on `CompilerHost`.
This commit ensures that we always try this method first before falling
back to the standard `ts.resolveModuleName`
PR Close#30017
Fixes `HostBinding` and `HostListener` declarations not being inherited from base classes that don't have an Angular decorator.
This PR resolves FW-1275.
PR Close#30158
Previously, ngtsc included query fields in the list of fields which can
affect the type of a directive via its type constructor. This feature
however has yet to be built, and View Engine in default mode does not
do this inference.
This caused an unexpected bug where private query fields (which should be
an error but are allowed by View Engine) cause the type constructor
signature to be invalid. This commit fixes that issue by disabling the
logic to include query fields.
PR Close#30094
ngtsc generates type constructors which infer the type of a directive based
on its inputs. Previously, a bug existed where this inference would fail in
the case of 'any' input values. For example, the inference of NgForOf fails
when an 'any' is provided, as it causes TypeScript to attempt to solve:
T[] = any
In this case, T gets inferred as {}, the empty object type, which is not
desirable.
The fix is to assign generic types in type constructors a default type of
'any', which TypeScript uses instead of {} when inference fails.
PR Close#30094
ngtsc previously could attempt to reuse the main ts.Program twice. This
occurred when template type-checking was enabled and then an incremental
build was performed. This breaks a TypeScript invariant - ts.Programs can
only be reused once.
The creation of the template type-checking program reuses the main program,
rendering it moot. Then, on the next incremental build the main program
would be subject to reuse again, which would crash inside TypeScript.
This commit fixes the issue by reusing the template type-checking program
from the previous run on the next incremental build. Since under normal
circumstances the files in the type-checking program aren't changed, this
should be just as fast.
Testing strategy: a test is added in the incremental_spec which validates
that program reuse with type-checking turned on does not crash the compiler.
Fixes#30079
PR Close#30090
Fixes view and content queries not being inherited in Ivy, if the base class hasn't been annotated with an Angular decorator (e.g. `Component` or `Directive`).
Also reworks the way the `ngBaseDef` is created so that it is added at the same point as the queries, rather than inside of the `Input` and `Output` decorators.
This PR partially resolves FW-1275. Support for host bindings will be added in a follow-up, because this PR is somewhat large as it is.
PR Close#30015
Prior to this commit, the check that verifies correct "id" field type was too strict and didn't allow `module.id` as @NgModule's "id" field value. This change adds a special handling for `module.id` and uses it as id of @NgModule if specified.
PR Close#30040
Now that ngtsc performs type checking using a dedicated `__ng_typecheck__.ts`
file, `NgtscProgram` always wraps its `ts.CompilerHost` in a shim host. This
shim fails to delegate `resolveModuleNames` so no custom module resolution
logic is considered. This introduces a problem for the CLI, as the compiler
host it passes kicks of ngcc for any imported module such that Ivy's
compatibility compiler runs automatically behind the scenes.
This commit adds delegation of the `resolveModuleNames` to fix the issue.
Fixes#30064
PR Close#30068
The compiler uses metadata to represent what it statically knows about
various expressions in a program. Occasionally, expressions in the program
for which metadata is extracted may contain sub-expressions which are not
representable in metadata. One such construct is an arrow function.
The compiler does not always need to understand such expressions completely.
For example, for a provider defined with `useValue`, the compiler does not
need to understand the value at all, only the outer provider definition. In
this case, the compiler employs a technique known as "expression lowering",
where it rewrites the provider expression into one that can be represented
in metadata. Chiefly, this involves extracting out the dynamic part (the
`useValue` expression) into an exported constant.
Lowering is applied through a heuristic, which considers the containing
statement as well as the field name of the expression.
Previously, this heuristic was not completely accurate in the case of
route definitions and the `loadChildren` field, which is lowered. If the
route definition using `loadChildren` existed inside a decorator invocation,
lowering was performed correctly. However, if it existed inside a standalone
variable declaration with an export keyword, the heuristic would conclude
that lowering was unnecessary. For ordinary providers this is true; however
the compiler attempts to fully understand the ROUTES token and thus even if
an array of routes is declared in an exported variable, any `loadChildren`
expressions within still need to be lowered.
This commit enables lowering of already exported variables under a limited
set of conditions (where the initializer expression is of a specific form).
This should enable the use of `loadChildren` in route definitions.
PR Close#30038
Previously, during the evaluation of a function call where no argument
was provided for a parameter that has a default value, the default value
would be taken from the context of the caller, instead of the callee.
This commit fixes the behavior by resolving the default value of a
parameter in the context of the callee.
PR Close#29888
Previously, ngtsc's static evaluator did not take spread operators into
account when evaluating function calls, nor did it handle rest arguments
correctly. This commit adds support for static evaluation of these
language features.
PR Close#29888
Template type-checking is enabled by default in the View Engine compiler.
The feature in Ivy is not quite ready for this yet, so this flag will
temporarily control whether templates are type-checked in ngtsc.
The goal is to remove this flag after rolling out template type-checking in
google3 in Ivy mode, and making sure the feature is as compatible with the
View Engine implementation as possible.
Initially, the default value of the flag will leave checking disabled.
PR Close#29698
This commit adds support for template type-checking a pipe binding which
previously was not handled by the type-checking engine. In compatibility
mode, the arguments to transform() are not checked and the type returned
by a pipe is 'any'. In full type-checking mode, the transform() method's
type signature is used to check the pipe usage and infer the return type
of the pipe.
Testing strategy: TCB tests included.
PR Close#29698
The template type-checking engine previously would assemble a type-checking
program by inserting Type Check Blocks (TCBs) into existing user files. This
approach proved expensive, as TypeScript has to re-parse and re-type-check
those files when processing the type-checking program.
Instead, a far more performant approach is to augment the program with a
single type-checking file, into which all TCBs are generated. Additionally,
type constructors are also inlined into this file.
This is not always possible - both TCBs and type constructors can sometimes
require inlining into user code, particularly if bound generic type
parameters are present, so the approach taken is actually a hybrid. These
operations are inlined if necessary, but are otherwise generated in a single
file.
It is critically important that the original program also include an empty
version of the type-checking file, otherwise the shape of the two programs
will be different and TypeScript will throw away all the old program
information. This leads to a painfully slow type checking pass, on the same
order as the original program creation. A shim to generate this file in the
original program is therefore added.
Testing strategy: this commit is largely a refactor with no externally
observable behavioral differences, and thus no tests are needed.
PR Close#29698
This commit adds support in the template type-checking engine for handling
the logical not operation and the safe navigation operation.
Safe navigation in particular is tricky, as the View Engine implementation
has a rather inconvenient flaw. View Engine checks a safe navigation
operation `a?.b` as:
```typescript
(a != null ? a!.b : null as any)
```
The type of this expression is always 'any', as the false branch of the
ternary has type 'any'. Thus, using null-safe navigation throws away the
type of the result, and breaks type-checking for the rest of the expression.
A flag is introduced in the type-checking configuration to allow Ivy to
mimic this behavior when needed.
Testing strategy: TCB tests included.
PR Close#29698
View Engine's implementation of naive template type-checking is less
advanced than the current Ivy implementation. As a result, Ivy catches lots
of typing bugs which VE does not. As a result, it's necessary to tone down
the Ivy template type-checker in the default case.
This commit introduces a mechanism for doing that, by passing a config to
the template type-checking engine. Through this configuration, particular
checks can be loosened or disabled entirely.
Testing strategy: TCB tests included.
PR Close#29698
Previously the template type-checking code only considered the metadata of
directive classes actually referenced in the template. If those directives
had base classes, any inputs/outputs/etc of the base classes were not
tracked when generating the TCB. This resulted in bindings to those inputs
being incorrectly attributed to the host component or element.
This commit uses the new metadata package to follow directive inheritance
chains and use the full metadata for a directive for TCB generation.
Testing strategy: Template type-checking tests included.
PR Close#29698
Previously, metadata registration (the recording of collected metadata
during analysis of directives, pipes, and NgModules) was only used to
produce the `LocalModuleScope`, and thus was handled by the
`LocalModuleScopeRegistry`.
However, the template type-checker also needs information about registered
directives, outside of the NgModule scope determinations. Rather than
reuse the scope registry for an unintended purpose, this commit introduces
new abstractions for metadata registration and lookups in a separate
'metadata' package, which the scope registry implements.
This paves the way for a future commit to make use of this metadata for the
template type-checking system.
Testing strategy: this commit is a refactoring which introduces no new
functionality, so existing tests are sufficient.
PR Close#29698
Previously, bindings to [class] and [style] were treated like any other
property binding. That is, they would result in type-checking code that
attempted to write directly to .class or .style on the element node.
This is incorrect, however - the mapping from Angular's [class] and [style]
onto the DOM properties is non-trivial.
For now, this commit avoids the issue by only checking the expressions
themselves and not the assignment to the element properties.
Testing strategy: TCB tests included.
PR Close#29698
Previously the template type-checking engine processed templates in a linear
manner, and could not handle '#' references within a template. One reason
for this is that '#' references are non-linear - a reference can be used
before its declaration. Consider the template:
```html
{{ref.value}}
<input #ref>
```
Accommodating this required refactoring the type-checking code generator to
be able to produce Type Check Block (TCB) code non-linearly. Now, each
template is processed and a list of TCB operations (`TcbOp`s) are created.
Non-linearity is modeled via dependencies between operations, with the
appropriate protection in place for circular dependencies.
Testing strategy: TCB tests included.
PR Close#29698
This commit adds support for the generation of type-checking expressions for
forms which were previously unsupported:
* array literals
* map literals
* keyed property accesses
* non-null assertions
Testing strategy: TCB tests included.
Fixes#29327
FW-1218 #resolve
PR Close#29698
This commit adds a test suite for the Type Check Block generation which
doesn't require running the entire compiler (specifically, it doesn't even
require the creation of a ts.Program).
PR Close#29698
This commit adds registration of AOT compiled NgModules that have 'id'
properties set in their metadata. Such modules have a call to
registerNgModuleType() emitted as part of compilation.
The JIT behavior of this code is already in place.
This is required for module loading systems (such as g3) which rely on
getModuleFactory().
PR Close#29980
Previously, ngtsc would fail to resolve `forwardRef` calls if they
contained additional parenthesis or casts. This commit changes the
behavior to first unwrap the AST nodes to see past such insignificant
nodes, resolving the issue.
Fixes#29639
PR Close#29886
Previously, only static evaluation of `Array.slice` was implemented in
ngtsc's static evaluator. This commit adds support for `Array.concat`.
Closes#29835
PR Close#29887
The config path is an optional argument to `ts.parseJsonConfigFileContent`. When passed, it is added to the returned object as `options.configFilePath`, and `tsc` itself passes it in.
The new TS 3.4 [incremental](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html) build functionality relies on this property being present: 025d826339/src/compiler/emitter.ts (L56-L57)
When using The compiler-cli `readConfiguration` the config path option isn't passed, preventing consumers (like @ngtools/webpack) from obtaining a complete config object.
This PR fixes this omission and should allow JIT users of @ngtools/webpack to set the `incremental` option in their tsconfig and have it be used by the TS program.
I tested this in JIT and saw a small decrease in build times in a small project. In AOT the incremental option didn't seem to be used at all, due to how `ngc` uses the TS APIs.
Related to https://github.com/angular/angular-cli/issues/13941.
PR Close#29872
Plural ICU expressions depend on the locale (different languages have different plural forms). Until now the locale was hard coded as `en-US`.
For compatibility reasons, if you use ivy with AOT and bootstrap your app with `bootstrapModule` then the `LOCALE_ID` token will be set automatically for ivy, which is then used to get the correct plural form.
If you use JIT, you need to define the `LOCALE_ID` provider on the module that you bootstrap.
For `TestBed` you can use either `configureTestingModule` or `overrideProvider` to define that provider.
If you don't use the compat mode and start your app with `renderComponent` you need to call `ɵsetLocaleId` manually to define the `LOCALE_ID` before bootstrap. We expect this to change once we start adding the new i18n APIs, so don't rely on this function (there's a reason why it's a private export).
PR Close#29249
The `Δ` caused issue with other infrastructure, and we are temporarily
changing it to `ɵɵ`.
This commit also patches ts_api_guardian_test and AIO to understand `ɵɵ`.
PR Close#29850
Previously, if a matching rootDir ended with a slash then the path
returned from `logicalPathOfFile()` would not start with a slash,
which is inconsistent.
PR Close#29627
The defineInjector function specifies its providers and imports array to
be optional, so if no providers/imports are present these keys may be
omitted. This commit updates the compiler to only generate the keys when
necessary.
PR Close#29598
Prior to this change, a module's imports and exports would be used verbatim
as an injectors' imports. This is detrimental for tree-shaking, as a
module's exports could reference declarations that would then prevent such
declarations from being eligible for tree-shaking.
Since an injector actually only needs NgModule references as its imports,
we may safely filter out any declarations from the list of module exports.
This makes them eligible for tree-shaking once again.
PR Close#29598
Prior to this change, all module metadata would be included in the
`defineNgModule` call that is set as the `ngModuleDef` field of module
types. Part of the metadata is scope information like declarations,
imports and exports that is used for computing the transitive module
scope in JIT environments, preventing those references from being
tree-shaken for production builds.
This change moves the metadata for scope computations to a pure function
call that patches the scope references onto the module type. Because the
function is marked pure, it may be tree-shaken out during production builds
such that references to declarations and exports are dropped, which in turn
allows for tree-shaken any declaration that is not otherwise referenced.
Fixes#28077, FW-1035
PR Close#29598
In ES2015, classes could have been emitted as a variable declaration
initialized with a class expression. In certain situations, an intermediary
variable suffixed with `_1` is present such that the variable
declaration's initializer becomes a binary expression with its rhs being
the class expression, and its lhs being the identifier of the intermediate
variable. This structure was not recognized, resulting in such classes not
being considered as a class in `Esm2015ReflectionHost`.
As a consequence, the analysis of functions/methods that return a
`ModuleWithProviders` object did not take the methods of such classes into
account.
Another edge-case with such intermediate variable was that static
properties would not be considered as class members. A testcase was added
to prevent regressions.
Fixes#29078
PR Close#29119
Currently there is no support in ngtsc for imports of the form:
```
import * as core from `@angular/core`
export function forRoot(): core.ModuleWithProviders;
```
This commit modifies the `ReflectionHost.getImportOfIdentifier(id)`
method, so that it supports this kind of return type.
PR Close#27675
This commit introduces a mechanism for incremental compilation to the ngtsc
compiler.
Previously, incremental information was used in the construction of the
ts.Program for subsequent compilations, but was not used in ngtsc itself.
This commit adds an IncrementalState class, which tracks state between ngtsc
compilations. Currently, this supports skipping the TypeScript emit step
when the compiler can prove the contents of emit have not changed.
This is implemented for @Injectables as well as for files which don't
contain any Angular decorated types. These are the only files which can be
proven to be safe today.
See ngtsc/incremental/README.md for more details.
PR Close#29380
This commit adds support for compiling the same program repeatedly in a way
that's similar to how incremental builds work in a tool such as the CLI.
* support is added to the compiler entrypoint for reuse of the Program
object between compilations. This is the basis of the compiler's
incremental compilation model.
* support is added to wrap the CompilerHost the compiler creates and cache
ts.SourceFiles in between compilations.
* support is added to track when files are emitted, for assertion purposes.
* an 'exclude' section is added to the base tsconfig to prevent .d.ts
outputs from the first compilation from becoming inputs to any subsequent
compilations.
PR Close#29380
This commit adds a `tracePerformance` option for tsconfig.json. When
specified, it causes a JSON file with timing information from the ngtsc
compiler to be emitted at the specified path.
This tracing system is used to instrument the analysis/emit phases of
compilation, and will be useful in debugging future integration work with
@angular/cli.
See ngtsc/perf/README.md for more details.
PR Close#29380
Currently, ngtsc decides to use remote scoping if the compilation of a
component may create a cyclic import. This happens if there are two
components in a scope (say, A and B) and A directly uses B. During
compilation of B ngtsc will then note that if B were to use A, a cycle would
be generated, and so it will opt to use remote scoping for B.
ngtsc already uses the R3TargetBinder to correctly track the imports that
are actually required, for future cycle tracking. This commit expands that
usage to not trigger remote scoping unless B actually does consume A in its
template.
PR Close#29404