Commit Graph

166 Commits

Author SHA1 Message Date
Pete Bacon Darwin 85298e345d fix(ngcc): render new definitions using the inner name of the class (#33533)
When decorating classes with ivy definitions (e.g. `ɵfac` or `ɵdir`)
the inner name of the class declaration must be used.

This is because in ES5 the definitions are inside the class's IIFE
where the outer declaration has not yet been initialized.

PR Close #33533
2019-11-05 17:25:02 +00:00
Pete Bacon Darwin 93a23b9ae0 fix(ngcc): override `getInternalNameOfClass()` and `getAdjacentNameOfClass()` for ES5 (#33533)
In ES5 the class consists of an outer variable declaration that is
initialised by an IIFE. Inside the IIFE the class is implemented by
an inner function declaration that is returned from the IIFE.
This inner declaration may have a different name to the outer
declaration.

This commit overrides `getInternalNameOfClass()` and
`getAdjacentNameOfClass()` in `Esm5ReflectionHost` with methods that
can find the correct inner declaration name identifier.

PR Close #33533
2019-11-05 17:25:01 +00:00
Pete Bacon Darwin 1d141a8ab1 fix(compiler-cli): attach the correct `viaModule` to namespace imports (#33495)
Previously declarations that were imported via a namespace import
were given the same `bestGuessOwningModule` as the context
where they were imported to. This causes problems with resolving
`ModuleWithProviders` that have a type that has been imported in
this way, causing errors like:

```
ERROR in Symbol UIRouterModule declared in
.../@uirouter/angular/uiRouterNgModule.d.ts
is not exported from
.../@uirouter/angular/uirouter-angular.d.ts
(import into .../src/app/child.module.ts)
```

This commit modifies the `TypescriptReflectionHost.getDirectImportOfIdentifier()`
method so that it also understands how to attach the correct `viaModule` to
the identifier of the namespace import.

Resolves #32166

PR Close #33495
2019-10-31 22:25:48 +00:00
crisbeto c3e93564d0 perf(ivy): avoid generating selectors array for directives without a selector (#33431)
Now that we've replaced `ngBaseDef` with an abstract directive definition, there are a lot more cases where we generate a directive definition without a selector. These changes make it so that we don't generate the `selectors` array if it's going to be empty.

PR Close #33431
2019-10-29 12:06:15 -07:00
crisbeto 14c4b1b205 refactor(ivy): remove ngBaseDef (#33264)
Removes `ngBaseDef` from the compiler and any runtime code that was still referring to it. In the cases where we'd previously generate a base def we now generate a definition for an abstract directive.

PR Close #33264
2019-10-25 13:11:34 -07:00
Alex Rickabaugh b381497126 feat(ngcc): add a migration for undecorated child classes (#33362)
In Angular View Engine, there are two kinds of decorator inheritance:

1) both the parent and child classes have decorators

This case is supported by InheritDefinitionFeature, which merges some fields
of the definitions (such as the inputs or queries).

2) only the parent class has a decorator

If the child class is missing a decorator, the compiler effectively behaves
as if the parent class' decorator is applied to the child class as well.
This is the "undecorated child" scenario, and this commit adds a migration
to ngcc to support this pattern in Ivy.

This migration has 2 phases. First, the NgModules of the application are
scanned for classes in 'declarations' which are missing decorators, but
whose base classes do have decorators. These classes are the undecorated
children. This scan is performed recursively, so even if a declared class
has a base class that itself inherits a decorator, this case is handled.

Next, a synthetic decorator (either @Component or @Directive) is created
on the child class. This decorator copies some critical information such
as 'selector' and 'exportAs', as well as supports any decorated fields
(@Input, etc). A flag is passed to the decorator compiler which causes a
special feature `CopyDefinitionFeature` to be included on the compiled
definition. This feature copies at runtime the remaining aspects of the
parent definition which `InheritDefinitionFeature` does not handle,
completing the "full" inheritance of the child class' decorator from its
parent class.

PR Close #33362
2019-10-25 09:16:50 -07:00
JoostK 6b267482d7 feat(ngcc): enable migrations to apply schematics to libraries (#33362)
When upgrading an Angular application to a new version using the Angular
CLI, built-in schematics are being run to update user code from
deprecated patterns to the new way of working. For libraries that have
been built for older versions of Angular however, such schematics have
not been executed which means that deprecated code patterns may still be
present, potentially resulting in incorrect behavior.

Some of the logic of schematics has been ported over to ngcc migrations,
which are automatically run on libraries. These migrations achieve the
same goal of the regular schematics, but operating on published library
sources instead of used code.

PR Close #33362
2019-10-25 09:16:50 -07:00
JoostK 2e5e1dd5f5 refactor(ngcc): rework undecorated parent migration (#33362)
Previously, the (currently disabled) undecorated parent migration in
ngcc would produce errors when a base class could not be determined
statically or when a class extends from a class in another package. This
is not ideal, as it would cause the library to fail compilation without
a workaround, whereas those problems are not guaranteed to cause issues.

Additionally, inheritance chains were not handled. This commit reworks
the migration to address these limitations.

PR Close #33362
2019-10-25 09:16:50 -07:00
JoostK 3858b26211 refactor(ivy): mark synthetic decorators explicitly (#33362)
In ngcc's migration system, synthetic decorators can be injected into a
compilation to ensure that certain classes are compiled with Angular
logic, where the original library code did not include the necessary
decorators. Prior to this change, synthesized decorators would have a
fake AST structure as associated node and a made-up identifier. In
theory, this may introduce issues downstream:

1) a decorator's node is used for diagnostics, so it must have position
information. Having fake AST nodes without a position is therefore a
problem. Note that this is currently not a problem in practice, as
injected synthesized decorators would not produce any diagnostics.

2) the decorator's identifier should refer to an imported symbol.
Therefore, it is required that the symbol is actually imported.
Moreover, bundle formats such as UMD and CommonJS use namespaces for
imports, so a bare `ts.Identifier` would not be suitable to use as
identifier. This was also not a problem in practice, as the identifier
is only used in the `setClassMetadata` generated code, which is omitted
for synthetically injected decorators.

To remedy these potential issues, this commit makes a decorator's
identifier optional and switches its node over from a fake AST structure
to the class' name.

PR Close #33362
2019-10-25 09:16:49 -07:00
JoostK 31b9492951 feat(ngcc): migrate services that are missing `@Injectable()` (#33362)
A class that is provided as Angular service is required to have an
`@Injectable()` decorator so that the compiler generates its injectable
definition for the runtime. Applications are automatically migrated
using the "missing-injectable" schematic, however libraries built for
older version of Angular may not yet satisfy this requirement.

This commit ports the "missing-injectable" schematic to a migration that
is ran when ngcc is processing a library. This ensures that any service
that is provided from an NgModule or Directive/Component will have an
`@Injectable()` decorator.

PR Close #33362
2019-10-25 09:16:49 -07:00
JoostK 0de2dbfec1 fix(ngcc): prevent reflected decorators from being clobbered (#33362)
ngcc has an internal cache of computed decorator information for
reflected classes, which could previously be mutated by consumers of the
reflection host. With the ability to inject synthesized decorators, such
decorators would inadvertently be added into the array of decorators
that was owned by the internal cache of the reflection host, incorrectly
resulting in synthesized decorators to be considered real decorators on
a class. This commit fixes the issue by cloning the cached array before
returning it.

PR Close #33362
2019-10-25 09:16:49 -07:00
Alex Rickabaugh e030375d9a feat(ngcc): enable private NgModule re-exports in ngcc on request (#33177)
This commit adapts the private NgModule re-export system (using aliasing) to
ngcc. Not all ngcc compilations are compatible with these re-exports, as
they assume a 1:1 correspondence between .js and .d.ts files. The primary
concern here is supporting them for commonjs-only packages.

PR Close #33177
2019-10-22 13:14:31 -04:00
Pete Bacon Darwin bfd07b3c94 fix(ngcc): Esm5ReflectionHost.getDeclarationOfIdentifier should handle aliased inner declarations (#33252)
In ES5 modules, the class declarations consist of an IIFE with inner
and outer declarations that represent the class. The `EsmReflectionHost`
has logic to ensure that `getDeclarationOfIdentifier()` always returns the
outer declaration.

Before this commit, if an identifier referred to an alias of the inner
declaration, then `getDeclarationOfIdentifier()` was failing to find
the outer declaration - instead returning the inner declaration.

Now the identifier is correctly resolved up to the outer declaration
as expected.

This should fix some of the failing 3rd party packages discussed in
https://github.com/angular/ngcc-validation/issues/57.

PR Close #33252
2019-10-18 14:41:25 -04:00
Alex Rickabaugh 50710838bf fix(ngcc): better detection of end of decorator expression (#33192)
for removal of decorator from __decorate calls.

FW-1629 #resolve

PR Close #33192
2019-10-17 19:43:39 -04:00
Alex Rickabaugh 4da2dda647 feat(ngcc): support ignoreMissingDependencies in ngcc config (#33192)
Normally, when ngcc encounters a package with missing dependencies while
attempting to determine a compilation ordering, it will ignore that package.
This commit adds a configuration for a flag to tell ngcc to compile the
package anyway, regardless of any missing dependencies.

FW-1931 #resolve

PR Close #33192
2019-10-17 19:43:39 -04:00
Alex Rickabaugh afcff73be3 fix(ngcc): report the correct viaModule when reflecting over commonjs (#33192)
In the ReflectionHost API, a 'viaModule' indicates that a particular value
originated in another absolute module. It should always be 'null' for values
originating in relatively-imported modules.

This commit fixes a bug in the CommonJsReflectionHost where viaModule would
be reported even for relatively-imported values, which causes invalid import
statements to be generated during compilation.

A test is added to verify the correct behavior.

FW-1628 #resolve

PR Close #33192
2019-10-17 19:43:39 -04:00
George Kalpakas 78214e72ea fix(ngcc): avoid warning when reflecting on index signature member (#33198)
Previously, when `ngcc` was reflecting on class members it did not
account for the fact that a member could be of the kind
`IndexSignature`. This can happen, for example, on abstract classes (as
is the case for [JsonCallbackContext][1]).

Trying to reflect on such members (and failing to recognize their kind),
resulted in warnings, such as:
```
Warning: Unknown member type: "[key: string]: (data: any) => void;
```

While these warnings are harmless, they can be confusing and worrisome
for users.

This commit avoids such warnings by detecting class members of the
`IndexSignature` kind and ignoring them.

[1]: https://github.com/angular/angular/blob/4659cc26e/packages/common/http/src/jsonp.ts#L39

PR Close #33198
2019-10-17 16:05:48 -04:00
Kara Erickson cda9248b33 refactor(core): rename ngInjectorDef to ɵinj (#33151)
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
2019-10-16 16:36:19 -04:00
Kara Erickson fc93dafab1 refactor(core): rename ngModuleDef to ɵmod (#33142)
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
2019-10-14 23:08:10 +00:00
Kara Erickson 0de2a5e408 refactor(core): rename ngFactoryDef to ɵfac (#33116)
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
2019-10-14 20:27:25 +00:00
Kara Erickson 1a67d70bf8 refactor(core): rename ngDirectiveDef to ɵdir (#33110)
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
2019-10-14 16:20:11 +00:00
Kara Erickson 64fd0d6db9 refactor(core): rename ngComponentDef to ɵcmp (#33088)
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
2019-10-11 15:45:22 -07:00
Pete Bacon Darwin 90007e97ca feat(ngcc): support version ranges in project/default configurations (#33008)
By appending a version range to the package name, it is now possible to
target configuration to specific versions of a package.

PR Close #33008
2019-10-10 13:59:57 -07:00
Pete Bacon Darwin 916762440c feat(ngcc): support fallback to a default configuration (#33008)
It is now possible to include a set of default ngcc configurations
that ship with ngcc out of the box. This allows ngcc to handle a
set of common packages, which are unlikely to be fixed, without
requiring the application developer to write their own configuration
for them.

Any packages that are configured at the package or project level
will override these default configurations. This allows a reasonable
level of control at the package and user level.

PR Close #33008
2019-10-10 13:59:57 -07:00
crisbeto d5b87d32b0 perf(ivy): move attributes array into component def (#32798)
Currently Ivy stores the element attributes into an array above the component def and passes it into the relevant instructions, however the problem is that upon minification the array will get a unique name which won't compress very well. These changes move the attributes array into the component def and pass in the index into the instructions instead.

Before:
```
const _c0 = ['foo', 'bar'];

SomeComp.ngComponentDef = defineComponent({
  template: function() {
    element(0, 'div', _c0);
  }
});
```

After:
```
SomeComp.ngComponentDef = defineComponent({
  consts: [['foo', 'bar']],
  template: function() {
    element(0, 'div', 0);
  }
});
```

A couple of cases that this PR doesn't handle:
* Template references are still in a separate array.
* i18n attributes are still in a separate array.

PR Close #32798
2019-10-09 13:16:55 -07:00
JoostK 747f0cff9e fix(ngcc): handle presence of both `ctorParameters` and `__decorate` (#32901)
Recently ng-packagr was updated to include a transform that used to be
done in tsickle (https://github.com/ng-packagr/ng-packagr/pull/1401),
where only constructor parameter decorators are emitted in tsickle's
format, not any of the other decorators.

ngcc used to extract decorators from only a single format, so once it
saw the `ctorParameters` static property it assumed the library is using
the tsickle format. Therefore, none of the `__decorate` calls were
considered. This resulted in missing decorator information, preventing
proper processing of a package.

This commit changes how decorators are extracted by always looking at
both the static properties and the `__decorate` calls, merging these
sources appropriately.

Resolves FW-1573

PR Close #32901
2019-09-30 14:11:45 -07:00
JoostK 002a97d852 fix(ngcc): ensure private exports are added for `ModuleWithProviders` (#32902)
ngcc may need to insert public exports into the bundle's source as well
as to the entry-point's declaration file, as the Ivy compiler may need
to create import statements to internal library types. The way ngcc
knows which exports to add is through the references registry, to which
references to things that require a public export are added by the
various analysis steps that are executed.

One of these analysis steps is the augmentation of declaration files
where functions that return `ModuleWithProviders` are updated so that a
generic type argument is added that corresponds with the `NgModule` that
is actually imported. This type has to be publicly exported, so the
analyzer step has to add the module type to the references registry.

A problem occurs when `ModuleWithProviders` already has a generic type
argument, in which case no update of the declaration file is necessary.
This may happen when 1) ngcc is processing additional bundle formats, so
that the declaration file has already been updated while processing the
first bundle format, or 2) when a package is processed which already
contains the generic type in its source. In both scenarios it may occur
that the referenced `NgModule` type does not yet have a public export,
so it is crucial that a reference to the type is added to the
references registry, which ngcc failed to do.

This commit fixes the issue by always adding the referenced `NgModule`
type to the references registry, so that a public export will always be
created if necessary.

Resolves FW-1575

PR Close #32902
2019-09-30 14:11:16 -07:00
Pete Bacon Darwin 0ea4875b10 fix(ngcc): make the build-marker error more clear (#32712)
The previous message was confusing as it could be
interpreted as only deleting the package mentioned.

Now we compute and display the actual node_modules
path to remove.

See https://github.com/angular/angular/issues/31354#issuecomment-532080537

PR Close #32712
2019-09-25 11:29:45 -07:00
Pete Bacon Darwin e5a3de575f fix(ngcc): support UMD global factory in comma lists (#32709)
Previously we were looking for a global factory call that looks like:

```ts
(factory((global.ng = global.ng || {}, global.ng.common = {}), global.ng.core))"
```

but in some cases it looks like:

```ts
(global = global || self, factory((global.ng = global.ng || {}, global.ng.common = {}), global.ng.core))"
```

Note the `global = global || self` at the start of the statement.

This commit makes the test when finding the global factory
function call resilient to being in a comma list.

PR Close #32709
2019-09-17 09:16:08 -07:00
JoostK 3c7da767d8 fix(ngcc): resolve imports in `.d.ts` files for UMD/CommonJS bundles (#32619)
In ngcc's reflection host for UMD and CommonJS bundles, custom logic is
present to resolve import details of an identifier. However, this custom
logic is unable to resolve an import for an identifier inside of
declaration files, as such files use the regular ESM import syntax.

As a consequence of this limitation, ngtsc is unable to resolve
`ModuleWithProviders` imports that are declared in an external library.
In that situation, ngtsc determines the type of the actual `NgModule`
that is imported, by looking in the library's declaration files for the
generic type argument on `ModuleWithProviders`. In this process, ngtsc
resolves the import for the `ModuleWithProviders` identifier to verify
that it is indeed the `ModuleWithProviders` type from `@angular/core`.
So, when the UMD reflection host was in use this resolution would fail,
therefore no `NgModule` type could be detected.

This commit fixes the bug by using the regular import resolution logic
in addition to the custom resolution logic that is required for UMD
and CommonJS bundles.

Fixes #31791

PR Close #32619
2019-09-12 13:18:20 -07:00
JoostK c4e039a43a fix(ngcc): correctly read static properties for aliased classes (#32619)
In ESM2015 bundles, a class with decorators may be emitted as follows:

```javascript
var MyClass_1;
let MyClass = MyClass_1 = class MyClass {};
MyClass.decorators = [/* here be decorators */];
```

Such a class has two declarations: the publicly visible `let MyClass`
and the implementation `class MyClass {}` node. In #32539 a refactoring
took place to handle such classes more consistently, however the logic
to find static properties was mistakenly kept identical to its broken
state before the refactor, by looking for static properties on the
implementation symbol (the one for `class MyClass {}`) whereas the
static properties need to be obtained from the symbol corresponding with
the `let MyClass` declaration, as that is where the `decorators`
property is assigned to in the example above.

This commit fixes the behavior by looking for static properties on the
public declaration symbol. This fixes an issue where decorators were not
found for classes that do in fact have decorators, therefore preventing
the classes from being compiled for Ivy.

Fixes #31791

PR Close #32619
2019-09-12 13:18:20 -07:00
JoostK 373e1337de fix(ngcc): consistently use outer declaration for classes (#32539)
In ngcc's reflection hosts for compiled JS bundles, such as ESM2015,
special care needs to be taken for classes as there may be an outer
declaration (referred to as "declaration") and an inner declaration
(referred to as "implementation") for a given class. Therefore, there
will also be two `ts.Symbol`s bound per class, and ngcc needs to switch
between those declarations and symbols depending on where certain
information can be found.

Prior to this commit, the `NgccReflectionHost` interface had methods
`getClassSymbol` and `findClassSymbols` that would return a `ts.Symbol`.
These class symbols would be used to kick off compilation of components
using ngtsc, so it is important for these symbols to correspond with the
publicly visible outer declaration of the class. However, the ESM2015
reflection host used to return the `ts.Symbol` for the inner
declaration, if the class was declared as follows:

```javascript
var MyClass = class MyClass {};
```

For the above code, `Esm2015ReflectionHost.getClassSymbol` would return
the `ts.Symbol` corresponding with the `class MyClass {}` declaration,
whereas it should have corresponded with the `var MyClass` declaration.
As a consequence, no `NgModule` could be resolved for the component, so
no components/directives would be in scope for the component. This
resulted in errors during runtime.

This commit resolves the issue by introducing a `NgccClassSymbol` that
contains references to both the outer and inner `ts.Symbol`, instead of
just a single `ts.Symbol`. This avoids the unclarity of whether a
`ts.Symbol` corresponds with the outer or inner declaration.

More details can be found here: https://hackmd.io/7nkgWOFWQlSRAuIW_8KPPw

Fixes #32078
Closes FW-1507

PR Close #32539
2019-09-12 11:12:10 -07:00
JoostK 2279cb8dc0 refactor(ngcc): move `ClassSymbol` to become `NgccClassSymbol` (#32539)
PR Close #32539
2019-09-12 11:12:10 -07:00
George Kalpakas e36e6c85ef perf(ngcc): process tasks in parallel in async mode (#32427)
`ngcc` supports both synchronous and asynchronous execution. The default
mode when using `ngcc` programmatically (which is how `@angular/cli` is
using it) is synchronous. When running `ngcc` from the command line
(i.e. via the `ivy-ngcc` script), it runs in async mode.

Previously, the work would be executed in the same way in both modes.

This commit improves the performance of `ngcc` in async mode by
processing tasks in parallel on multiple processes. It uses the Node.js
built-in [`cluster` module](https://nodejs.org/api/cluster.html) to
launch a cluster of Node.js processes and take advantage of multi-core
systems.

Preliminary comparisons indicate a 1.8x to 2.6x speed improvement when
processing the angular.io app (apparently depending on the OS, number of
available cores, system load, etc.). Further investigation is needed to
better understand these numbers and identify potential areas of
improvement.

Inspired by/Based on @alxhub's prototype: alxhub/angular@cb631bdb1
Original design doc: https://hackmd.io/uYG9CJrFQZ-6FtKqpnYJAA?view

Jira issue: [FW-1460](https://angular-team.atlassian.net/browse/FW-1460)

PR Close #32427
2019-09-09 15:55:13 -04:00
George Kalpakas f4e4bb2085 refactor(ngcc): implement task selection for parallel task execution (#32427)
This commit adds a new `TaskQueue` implementation that supports
executing multiple tasks in parallel (while respecting interdependencies
between them).

This new implementation is currently not used, thus the behavior of
`ngcc` is not affected by this change. The parallel `TaskQueue` will be
used in a subsequent commit that will introduce parallel task execution.

PR Close #32427
2019-09-09 15:55:13 -04:00
George Kalpakas 2844dd2972 refactor(ngcc): abstract task selection behind an interface (#32427)
This change does not alter the current behavior, but makes it easier to
introduce `TaskQueue`s implementing different task selection algorithms,
for example to support executing multiple tasks in parallel (while
respecting interdependencies between them).

Inspired by/Based on @alxhub's prototype: alxhub/angular@cb631bdb1

PR Close #32427
2019-09-09 15:55:13 -04:00
George Kalpakas 9270d3f279 refactor(ngcc): take advantage of early knowledge about format property processability (#32427)
In the past, a task's processability didn't use to be known in advance.
It was possible that a task would be created and added to the queue
during the analysis phase and then later (during the compilation phase)
it would be found out that the task (i.e. the associated format
property) was not processable.

As a result, certain checks had to be delayed, until a task's processing
had started or even until all tasks had been processed. Examples of
checks that had to be delayed are:
- Whether a task can be skipped due to `compileAllFormats: false`.
- Whether there were entry-points for which no format at all was
  successfully processed.

It turns out that (as made clear by the refactoring in 9537b2ff8), once
a task starts being processed it is expected to either complete
successfully (with the associated format being processed) or throw an
error (in which case the process will exit). In other words, a task's
processability is known in advance.

This commit takes advantage of this fact by moving certain checks
earlier in the process (e.g. in the analysis phase instead of the
compilation phase), which in turn allows avoiding some unnecessary work.
More specifically:

- When `compileAllFormats` is `false`, tasks are created _only_ for the
  first suitable format property for each entry-point, since the rest of
  the tasks would have been skipped during the compilation phase anyway.
  This has the following advantages:
  1. It avoids the slight overhead of generating extraneous tasks and
     then starting to process them (before realizing they should be
     skipped).
  2. In a potential future parallel execution mode, unnecessary tasks
     might start being processed at the same time as the first (useful)
     task, even if their output would be later discarded, wasting
     resources. Alternatively, extra logic would have to be added to
     prevent this from happening. The change in this commit avoids these
     issues.
- When an entry-point is not processable, an error will be thrown
  upfront without having to wait for other tasks to be processed before
  failing.

PR Close #32427
2019-09-09 15:55:13 -04:00
George Kalpakas 3127ba3c35 refactor(ngcc): add support for asynchronous execution (#32427)
Previously, `ngcc`'s programmatic API would run and complete
synchronously. This was necessary for specific usecases (such as how the
`@angular/cli` invokes `ngcc` as part of the TypeScript module
resolution process), but not for others (e.g. running `ivy-ngcc` as a
`postinstall` script).

This commit adds a new option (`async`) that enables turning on
asynchronous execution. I.e. it signals that the caller is OK with the
function call to complete asynchronously, which allows `ngcc` to
potentially run in a more efficient mode.

Currently, there is no difference in the way tasks are executed in sync
vs async mode, but this change sets the ground for adding new execution
options (that require asynchronous operation), such as processing tasks
in parallel on multiple processes.

NOTE:
When using the programmatic API, the default value for `async` is
`false`, thus retaining backwards compatibility.
When running `ngcc` from the command line (i.e. via the `ivy-ngcc`
script), it runs in async mode (to be able to take advantage of future
optimizations), but that is transparent to the caller.

PR Close #32427
2019-09-09 15:55:13 -04:00
George Kalpakas 3d9dd6df0e refactor(ngcc): abstract updating `package.json` files behind an interface (#32427)
To persist some of its state, `ngcc` needs to update `package.json`
files (both in memory and on disk).

This refactoring abstracts these operations behind the
`PackageJsonUpdater` interface, making it easier to orchestrate them
from different contexts (e.g. when running tasks in parallel on multiple
processes).

Inspired by/Based on @alxhub's prototype: alxhub/angular@cb631bdb1

PR Close #32427
2019-09-09 15:55:13 -04:00
George Kalpakas 38359b166e fix(ngcc): only back up the original `prepublishOnly` script and not the overwritten one (#32427)
In order to prevent `ngcc`'d packages (e.g. libraries) from getting
accidentally published, `ngcc` overwrites the `prepublishOnly` npm
script to log a warning and exit with an error. In case we want to
restore the original script (e.g. "undo" `ngcc` processing), we keep a
backup of the original `prepublishOnly` script.

Previously, running `ngcc` a second time (e.g. for a different format)
would create a backup of the overwritten `prepublishOnly` script (if
there was originally no `prepublishOnly` script). As a result, if we
ever tried to "undo" `ngcc` processing and restore the original
`prepublishOnly` script, the error-throwing script would be restored
instead.

This commit fixes it by ensuring that we only back up a `prepublishOnly`
script, iff it is not the one we created ourselves (i.e. the
error-throwing one).

PR Close #32427
2019-09-09 15:55:13 -04:00
JoostK f7471eea3c fix(ngcc): handle compilation diagnostics (#31996)
Previously, any diagnostics reported during the compilation of an
entry-point would not be shown to the user, but either be ignored or
cause a hard crash in case of a `FatalDiagnosticError`. This is
unfortunate, as such error instances contain information on which code
was responsible for producing the error, whereas only its error message
would not. Therefore, it was quite hard to determine where the error
originates from.

This commit introduces behavior to deal with error diagnostics in a more
graceful way. Such diagnostics will still cause the compilation to fail,
however the error message now contains formatted diagnostics.

Closes #31977
Resolves FW-1374

PR Close #31996
2019-08-29 12:38:02 -07:00
Pete Bacon Darwin d5101dff3b fix(ivy): ngcc - improve the "ngcc version changed" error message (#32396)
If a project has nested projects that contain node_modules folders
that get processed by ngcc, it can be confusing when the ngcc
version changes since the error message is very generic:

```
The ngcc compiler has changed since the last ngcc build.
Please completely remove `node_modules` and try again.
```

This commit augments the error message with the path of
the entry-point that failed so that it is more obvious which
node_modules folder to remove.

BREAKING CHANGE:

This commit removes the public export of `hasBeenProcessed()`.

This was exported to be availble to the CLI integration but was never
used. The change to the function signature is a breaking change in itself
so we remove the function altogether to simplify and lower the public
API surface going forward.

PR Close #32396
2019-08-29 12:32:54 -07:00
Kristiyan Kostadinov c885178d5f refactor(ivy): move directive, component and pipe factories to ngFactoryFn (#31953)
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
2019-08-27 13:57:00 -07:00
JoostK e563d77128 fix(ngcc): do not analyze dependencies for non Angular entry-points (#32303)
When ngcc is called for a specific entry-point, it has to determine
which dependencies to transitively process. To accomplish this, ngcc
traverses the full import graph of the entry-points it encounters, for
which it uses a dependency host to find all module imports. Since
imports look different in the various bundle formats ngcc supports, a
specific dependency host is used depending on the information provided
in an entry-points `package.json` file. If there's not enough
information in the `package.json` file for ngcc to be able to determine
which dependency host to use, ngcc would fail with an error.

If, however, the entry-point is not compiled by Angular, it is not
necessary to process any of its dependencies. None of them can have
been compiled by Angular so ngcc does not need to know about them.
Therefore, this commit changes the behavior to avoid recursing into
dependencies of entry-points that are not compiled by Angular.

In particular, this fixes an issue for packages that have dependencies
on the `date-fns` package. This package has various secondary
entry-points that have a `package.json` file only containing a `typings`
field, without providing additional fields for ngcc to know which
dependency host to use. By not needing a dependency host at all, the
error is avoided.

Fixes #32302

PR Close #32303
2019-08-26 10:08:44 -07:00
Elvis Begovic f8b995dbf9 fix(ngcc): ignore format properties that exist but are undefined (#32205)
Previously, `ngcc` assumed that if a format property was defined in
`package.json` it would point to a valid format-path (i.e. a file that
is an entry-point for a specific format). This is generally the case,
except if a format property is set to a non-string value (such as
`package.json`) - either directly in the `package.json` (which is unusual)
or in ngcc.config.js (which is a valid usecase, when one wants a
format property to be ignored by `ngcc`).

For example, the following config file would cause `ngcc` to throw:

```
module.exports = {
  packages: {
    'test-package': {
      entryPoints: {
        '.': {
          override: {
            fesm2015: undefined,
          },
        },
      },
    },
  },
};
```

This commit fixes it by ensuring that only format properties whose value
is a string are considered by `ngcc`.

For reference, this regression was introduced in #32052.

Fixes #32188

PR Close #32205
2019-08-20 09:55:25 -07:00
JoostK 4bbf16e654 fix(ngcc): handle deep imports that already have an extension (#32181)
During the dependency analysis phase of ngcc, imports are resolved to
files on disk according to certain module resolution rules. Since module
specifiers are typically missing extensions, or can refer to index.js
barrel files within a directory, the module resolver attempts several
postfixes when searching for a module import on disk. Module  specifiers
that already include an extension, however, would fail to be resolved as
ngcc's module resolver failed to check the location on disk without
adding any postfixes.

Closes #32097

PR Close #32181
2019-08-19 10:12:03 -07:00
Alex Rickabaugh 964d72610f fix(ivy): ngcc should only index .d.ts exports within the package (#32129)
ngcc needs to solve a unique problem when compiling typings for an
entrypoint: it must resolve a declaration within a .js file to its
representation in a .d.ts file. Since such .d.ts files can be used in deep
imports without ever being referenced from the "root" .d.ts, it's not enough
to simply match exported types to the root .d.ts. ngcc must build an index
of all .d.ts files.

Previously, this operation had a bug: it scanned all .d.ts files in the
.d.ts program, not only those within the package. Thus, if a class in the
program happened to share a name with a class exported from a dependency's
.d.ts, ngcc might accidentally modify the wrong .d.ts file, causing a
variety of issues downstream.

To fix this issue, ngcc's .d.ts scanner now limits the .d.ts files it
indexes to only those declared in the current package.

PR Close #32129
2019-08-15 14:46:00 -07:00
Alex Rickabaugh 02bab8cf90 fix(ivy): in ngcc, handle inline exports in commonjs code (#32129)
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
2019-08-15 14:45:59 -07:00
Kristiyan Kostadinov 4ea3e7e000 refactor(ivy): combine query load instructions (#32100)
Combines the `loadViewQuery` and `loadContentQuery` instructions since they have the exact same internal logic. Based on a discussion here: https://github.com/angular/angular/pull/32067#pullrequestreview-273001730

PR Close #32100
2019-08-12 10:32:08 -07:00
Alan Agius 46304a4f83 feat(ivy): show error when trying to publish NGCC'd packages (#32031)
Publishing of NGCC packages should not be allowed. It is easy for a user to publish an NGCC'd version of a library they have workspace libraries which are being used in a workspace application.

If a users builds a library and afterwards the application, the library will be transformed with NGCC and since NGCC taints the distributed files that should be published.

With this change we use the npm/yarn `prepublishOnly` hook to display and error and abort the process with a non zero error code when a user tries to publish an NGCC version of the package.

More info: https://docs.npmjs.com/misc/scripts

PR Close #32031
2019-08-08 11:17:38 -07:00