Updates to rules_nodejs 2.2.0. This is the first major release in 7 months and includes a number of features as well
as breaking changes.
Release notes: https://github.com/bazelbuild/rules_nodejs/releases/tag/2.0.0
Features of note for angular/angular:
* stdout/stderr/exit code capture; this could be potentially be useful
* TypeScript (ts_project); a simpler tsc rule that ts_library that can be used in the repo where ts_library is too
heavy weight
Breaking changes of note for angular/angular:
* loading custom rules from npm packages: `ts_library` is no longer loaded from `@npm_bazel_typescript//:index.bzl`
(which no longer exists) but is now loaded from `@npm//@bazel/typescript:index.bzl`
* with the loading changes above, `load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")` is
no longer needed in the WORKSPACE which also means that yarn_install does not need to run unless building/testing
a target that depends on @npm. In angular/angular this is a minor improvement as almost everything depends on @npm.
* @angular/bazel package is also updated in this PR to support the new load location; Angular + Bazel users that
require it for ng_package (ng_module is no longer needed in OSS with Angular 10) will need to load from
`@npm//@angular/bazel:index.bzl`. I investigated if it was possible to maintain backward compatability for the old
load location `@npm_angular_bazel` but it is not since the package itself needs to be updated to load from
`@npm//@bazel/typescript:index.bzl` instead of `@npm_bazel_typescript//:index.bzl` as it depends on ts_library
internals for ng_module.
* runfiles.resolve will now throw instead of returning undefined to match behavior of node require
Other changes in angular/angular:
* integration/bazel has been updated to use both ng_module and ts_libary with use_angular_plugin=true.
The latter is the recommended way for rules_nodejs users to compile Angular 10 with Ivy. Bazel + Angular ViewEngine is
supported with @angular/bazel <= 9.0.5 and Angular <= 8. There is still Angular ViewEngine example on rules_nodejs
https://github.com/bazelbuild/rules_nodejs/tree/stable/examples/angular_view_engine on these older versions but users
that want to update to Angular 10 and are on Bazel must switch to Ivy and at that point ts_library with
use_angular_plugin=true is more performant that ng_module. Angular example in rules_nodejs is configured this way
as well: https://github.com/bazelbuild/rules_nodejs/tree/stable/examples/angular. As an aside, we also have an
example of building Angular 10 with architect() rule directly instead of using ts_library with angular plugin:
https://github.com/bazelbuild/rules_nodejs/tree/stable/examples/angular_bazel_architect.
NB: ng_module is still required for angular/angular repository as it still builds ViewEngine & @angular/bazel
also provides the ng_package rule. ng_module can be removed in the future if ViewEngine is no longer needed in
angular repo.
* JSModuleInfo provider added to ng_module. this is for forward compat for future rules_nodejs versions.
@josephperrott, this touches `packages/bazel/src/external.bzl` which will make the sync to g3 non-trivial.
PR Close#37727
This updates the migration to align with the style guide and work with default lint rules. It avoids a lint error on
newly migrated projects and fixes a test in the CLI repo.
PR Close#39070
`NodeInjector` is store in expando as a list of values in an array. The
offset constant into the array have been brought together into a single
`NodeInjectorOffset` enum with better documentation explaining their usage.
PR Close#38707
This change makes `getPreviousOrParentTNode` return `TNode|null` (rather
than just `TNode`) which is more reflective of the reality. The
`getPreviousOrParentTNode` can be `null` upon entering the `LView`.
PR Close#38707
`TNodeType.View` was created to support inline views. That feature did
not materialize and we have since removed the instructions for it, leave
an unneeded `TNodeType.View` which was still used in a very
inconsistent way. This change no longer created `TNodeType.View` (and
there will be a follow up chang to completely remove it.)
Also simplified the mental model so that `LView[HOST]`/`LView[T_HOST]`
always point to the insertion location of the `LView`.
PR Close#38707
Host `TNode` was passed into `getOrCreateTNode` just so that we can
compute weather or not we are a root node. This was needed because
`previousOrParentTNode` could have `TNode` from `TView` other then
current `TView`. This is confusing mental model. Previous change
ensured that `previousOrParentTNode` must always be part of `TView`,
which enabled this change to remove the unneeded argument.
PR Close#38707
`previousOrParentTNode` stores current `TNode`. Due to inconsistent
implementation the value stored would sometimes belong to the current
`TView` and sometimes to the parent. We have extra logic which accounts
for it. A better solution is to just ensure that `previousOrParentTNode`
always belongs to current `TNode`. This simplifies the mental model
and cleans up some code.
PR Close#38707
The default value for `relativeLinkResolution` is changing from 'legacy' to 'corrected'.
This migration updates `RouterModule` configurations that use the default value to
now specifically use 'legacy' to prevent breakages when updating.
PR Close#38698
There is an inconsistency in overrideProvider behaviour. Testing documentation says
(https://angular.io/guide/testing-components-basics#createcomponent) that all override...
methods throw error if TestBed is already instantiated. However overrideProvider doesn't throw any error, but (same as
other override... methods) doesn't replace providers if TestBed is instantiated. Add TestBed instantiation check to
overrideProvider method to make it consistent.
BREAKING CHANGE:
If you call `TestBed.overrideProvider` after TestBed initialization, provider overrides are not applied. This
behavior is consistent with other override methods (such as `TestBed.overrideDirective`, etc) but they
throw an error to indicate that, when the check was missing in the `TestBed.overrideProvider` function.
Now calling `TestBed.overrideProvider` after TestBed initialization also triggers an
error, thus there is a chance that some tests (where `TestBed.overrideProvider` is
called after TestBed initialization) will start to fail and require updates to move `TestBed.overrideProvider` calls
before TestBed initialization is completed.
Issue mentioned here: https://github.com/angular/angular/issues/13460#issuecomment-636005966
Documentation: https://angular.io/guide/testing-components-basics#createcomponent
PR Close#38717
This commit updates several import statements in the core package to decrease the number of
cycles detected by the dependency checker tool.
PR Close#38805
In #38227 the signatures of `navigateByUrl` and `createUrlTree` were updated to exclude unsupported
properties from their `extras` parameter. This migration looks for the relevant method calls that
pass in an `extras` parameter and drops the unsupported properties.
**Before:**
```
this._router.navigateByUrl('/', {skipLocationChange: false, fragment: 'foo'});
```
**After:**
```
this._router.navigateByUrl('/', {
/* Removed unsupported properties by Angular migration: fragment. */
skipLocationChange: false
});
```
These changes also move the method call detection logic out of the `Renderer2` migration and into
a common place so that it can be reused in other migrations.
PR Close#38825
This commit creates a sample router test application to introduce the
symbol tests. It serves as a guard to ensure that any future work on the
router package does not unintentionally increase the payload size.
PR Close#38714
The `RefreshTransplantedView` flag is used to indicate that the view or one of its children
is transplanted and dirty, so it should still be refreshed as part of change detection.
This flag is set on the transplanted view itself as well setting a
counter on as its parents.
When a transplanted view is detached and still has this flag, it means
it got detached before it was refreshed. This can happen for "backwards
references" or transplanted views that are inserted at a location that
was already checked. In this case, we should decrement the parent
counters _and_ clear the flag on the detached view so it's not seen as
"transplanted" anymore (it is detached and has no parent counters to
adjust).
fixes#38619
PR Close#38768
This commit adds `ngDevMode` guard to throw some errors only in dev mode
(similar to how things work in other parts of Ivy runtime code). The
`ngDevMode` flag helps to tree-shake these error messages from production
builds (in dev mode everything will work as it works right now) to decrease
production bundle size.
PR Close#38612
`tView` that is stored on a component def contains information about directives and pipes
that are available in the scope of this component. Patching component scope causes `tView` to be
updated. Prior to this commit, the `tView` information was not restored/reset in case component
class is not declared in the `declarations` field while calling `TestBed.configureTestingModule`,
thus causing `tView` to be reused between tests (thus preserving scopes information between tests).
This commit updates TestBed logic to preserve `tView` value before applying scope changes and
reset it back to the previous state between tests.
Closes#38600.
PR Close#38659
Remove CollectionChangeRecord as it was deprecated for removal in v4, use
IterableChangeRecord instead.
BREAKING CHANGE: CollectionChangeRecord has been removed, use IterableChangeRecord
instead
PR Close#38668
This commit adds a guard before throwing any forms errors. This will tree-shake
error messages which cannot be minified. It should also help to reduce the
bundle size of the `forms` package in production by ~20%.
Closes#37697
PR Close#37821
Fix a bug in the HTML sanitizer where an unclosed iframe tag would
result in an escaped closing body tag as the output:
_sanitizeHtml(document, '<iframe>') => '</body>'
This closing body tag comes from the DOMParserHelper where the HTML to be
sanitized is wrapped with surrounding body tags. When an opening iframe
tag is parsed by DOMParser, which DOMParserHelper uses, everything up
until its matching closing tag is consumed as a text node. In the above
example this includes the appended closing body tag.
By removing the explicit closing body tag from the DOMParserHelper and
relying on the body tag being closed implicitly at the end, the above
example is sanitized as expected:
_sanitizeHtml(document, '<iframe>') => ''
PR Close#38454
Similarly to the change we landed in the `@angular/core` reflection
capabilities, we need to make sure that ngcc can detect pass-through
delegate constructors for classes using downleveled ES2015 output.
More details can be found in the preceding commit, and in the issue
outlining the problem: #38453.
Fixes#38453.
PR Close#38463
In the Angular Package Format, we always shipped UMD bundles and previously even ES5 module output.
With V10, we removed the ES5 module output but kept the UMD ES5 output.
For this, we were able to remove our second TypeScript transpilation. Instead we started only
building ES2015 output and then downleveled it to ES5 UMD for the NPM packages. This worked
as expected but unveiled an issue in the `@angular/core` reflection capabilities.
In JIT mode, Angular determines constructor parameters (for DI) using the `ReflectionCapabilities`. The
reflection capabilities basically read runtime metadata of classes to determine the DI parameters. Such
metadata can be either stored in static class properties like `ctorParameters` or within TypeScript's `design:params`.
If Angular comes across a class that does not have any parameter metadata, it tries to detect if the
given class is actually delegating to an inherited class. It does this naively in JIT by checking if the
stringified class (function in ES5) matches a certain pattern. e.g.
```js
function MatTable() {
var _this = _super.apply(this, arguments) || this;
```
These patterns are reluctant to changes of the class output. If a class is not recognized properly, the
DI parameters will be assumed empty and the class is **incorrectly** constructed without arguments.
This actually happened as part of v10 now. Since we downlevel ES2015 to ES5 (instead of previously
compiling sources directly to ES5), the class output changed slightly so that Angular no longer detects
it. e.g.
```js
var _this = _super.apply(this, __spread(arguments)) || this;
```
This happens because the ES2015 output will receive an auto-generated constructor if the class
defines class properties. This constructor is then already containing an explicit `super` call.
```js
export class MatTable extends CdkTable {
constructor() {
super(...arguments);
this.disabled = true;
}
}
```
If we then downlevel this file to ES5 with `--downlevelIteration`, TypeScript adjusts the `super` call so that
the spread operator is no longer used (not supported in ES5). The resulting super call is different to the
super call that would have been emitted if we would directly transpile to ES5. Ultimately, Angular no
longer detects such classes as having an delegate constructor -> and DI breaks.
We fix this by expanding the rather naive RegExp patterns used for the reflection capabilities
so that downleveled pass-through/delegate constructors are properly detected. There is a risk
of a false-positive as we cannot detect whether `__spread` is actually the TypeScript spread
helper, but given the reflection patterns already make lots of assumptions (e.g. that `super` is
actually the superclass, we should be fine making this assumption too. The false-positive would
not result in a broken app, but rather in unnecessary providers being injected (as a noop).
Fixes#38453
PR Close#38463
This commit updates the code to move generated i18n statements into the `consts` field of
ComponentDef to avoid invoking `$localize` function before component initialization (to better
support runtime translations) and also avoid problems with lazy-loading when i18n defs may not
be present in a chunk where it's referenced.
Prior to this change the i18n statements were generated at the top leve:
```
var I18N_0;
if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) {
var MSG_X = goog.getMsg(“…”);
I18N_0 = MSG_X;
} else {
I18N_0 = $localize('...');
}
defineComponent({
// ...
template: function App_Template(rf, ctx) {
i0.ɵɵi18n(2, I18N_0);
}
});
```
This commit updates the logic to generate the following code instead:
```
defineComponent({
// ...
consts: function() {
var I18N_0;
if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) {
var MSG_X = goog.getMsg(“…”);
I18N_0 = MSG_X;
} else {
I18N_0 = $localize('...');
}
return [
I18N_0
];
},
template: function App_Template(rf, ctx) {
i0.ɵɵi18n(2, 0);
}
});
```
Also note that i18n template instructions now refer to the `consts` array using an index
(similar to other template instructions).
PR Close#38404
When removal of one view causes removal of another one from the same
ViewContainerRef it triggers an error with views length calculation. This commit
fixes this bug by removing a view from the list of available views before invoking
actual view removal (which might be recursive and relies on the length of the list
of available views).
Fixes#38201.
PR Close#38317
Fixes an error if a CSS custom property, used inside a host binding, has a
number in its name. The error is thrown because the styling parser only
expects characters from A to Z,dashes, underscores and a handful of other
characters.
Fixes#37292.
PR Close#38432
When using the safe navigation operator in a binding expression, a temporary
variable may be used for storing the result of a side-effectful call.
For example, the following template uses a pipe and a safe property access:
```html
<app-person-view [enabled]="enabled" [firstName]="(person$ | async)?.name"></app-person-view>
```
The result of the pipe evaluation is stored in a temporary to be able to check
whether it is present. The temporary variable needs to be declared in a separate
statement and this would also cause the full expression itself to be pulled out
into a separate statement. This would compile into the following
pseudo-code instructions:
```js
var temp = null;
var firstName = (temp = pipe('async', ctx.person$)) == null ? null : temp.name;
property('enabled', ctx.enabled)('firstName', firstName);
```
Notice that the pipe evaluation happens before evaluating the `enabled` binding,
such that the runtime's internal binding index would correspond with `enabled`,
not `firstName`. This introduces a problem when the pipe uses `WrappedValue` to
force a change to be detected, as the runtime would then mark the binding slot
corresponding with `enabled` as dirty, instead of `firstName`. This results
in the `enabled` binding to be updated, triggering setters and affecting how
`OnChanges` is called.
In the pseudo-code above, the intermediate `firstName` variable is not strictly
necessary---it only improved readability a bit---and emitting it inline with
the binding itself avoids the out-of-order execution of the pipe:
```js
var temp = null;
property('enabled', ctx.enabled)
('firstName', (temp = pipe('async', ctx.person$)) == null ? null : temp.name);
```
This commit introduces a new `BindingForm` that results in the above code to be
generated and adds compiler and acceptance tests to verify the proper behavior.
Fixes#37194
PR Close#37911
In JIT compiled apps, component definitions are compiled upon first
access. For a component class `A` that extends component class `B`, the
`B` component is also compiled when the `InheritDefinitionFeature` runs
during the compilation of `A` before it has finalized. A problem arises
when the compilation of `B` would flush the NgModule scoping queue,
where the NgModule declaring `A` is still pending. The scope information
would be applied to the definition of `A`, but its compilation is still
in progress so requesting the component definition would compile `A`
again from scratch. This "inner compilation" is correctly assigned the
NgModule scope, but once the "outer compilation" of `A` finishes it
would overwrite the inner compilation's definition, losing the NgModule
scope information.
In summary, flushing the NgModule scope queue could trigger a reentrant
compilation, where JIT compilation is non-reentrant. To avoid the
reentrant compilation, a compilation depth counter is introduced to
avoid flushing the NgModule scope during nested compilations.
Fixes#37105
PR Close#37795
Queries weren't matching directives that provide themselves via string
injection tokens, because the assumption was that any string passed to
a query decorator refers to a template reference.
These changes make it so we match both template references and
providers while giving precedence to the template references.
Fixes#38313.
Fixes#38315.
PR Close#38321
This commit contains no changes to code. It only breaks `i18n.ts` file
into `i18n.ts` + `i18n_apply.ts` + `i18n_parse.ts` +
`i18n_postprocess.ts` for easier maintenance.
PR Close#38368
The currently selected ICU was incorrectly being stored it `TNode`
rather than in `LView`.
Remove: `TIcuContainerNode.activeCaseIndex`
Add: `LView[TIcu.currentCaseIndex]`
PR Close#38345
This commit performs minor refactoring in Forms package to get rid of duplicate functions.
It looks like the functions were duplicated due to a slightly different type signatures, but
their logic is completely identical. The logic in retained functions remains the same and now
these function also accept a generic type to achieve the same level of type safety.
PR Close#38371
This change provides better typing for the `LView.debug` property which
is intended to be used by humans while debugging the application with
`ngDevMode` turned on.
In addition this chang also adds jasmine matchers for better asserting
that `LView` is in the correct state.
PR Close#38359
I18n code breaks up internationalization into opCodes which are then stored
in arrays. To make it easier to debug the codebase this PR adds `debug`
property to the arrays which presents the data in human readable format.
PR Close#38154