This commit updates the Testability-related tests to reset the testability getter class after each test to avoid leaking the state between tests. This should improve the stability of the testability tests that are currently flaky on CI.
PR Close#45947
The Testability-related logic was refactored in https://github.com/angular/angular/pull/45657 to become tree-shaking-friendly: it was decoupled from the core providers of the `BrowserModule`. This commit updates the newly-introduced `bootstrapApplication` function to exclude Testability-providers by default (note: the Testability is still included in the NgModule-based bootstrap).
In order to add the Testability to the app bootstrapped via `bootstrapApplication`, the `provideProtractorTestingSupport` function is introduced.
PR Close#45885
Previously, using `FormBuilder` with a union type would produce unions of *controls*:
```
// `foo` has type `FormControl<string>|FormControl<number>`.
const c = fb.nonNullable.group({foo: 'bar' as string | number});
```
This actually works in many cases, due to how extraordinarily powerful Typescript's distributive types are (e.g. `value` still has type `string|number`), but it is subtly incorrect. Here is a code example that exposes the reason the inference is incorrect. It exploits the fact that Typescript will not "un-distribute" a type, producing an obviously spurious error:
```
// fc gets an inferred distributive union type `FormControl<string> | FormControl<number>`
let fc = c.controls.foo;
// Error: Type 'FormControl<string | number>' is not assignable to type 'FormControl<string> | FormControl<number>'.
fc = new FormControl<string|number>('', {initialValueIsDefault: true});
```
Instead, we want the union to apply to the *values*:
```
// `foo` should have type `FormControl<string|number>`.
const c = fb.nonNullable.group({foo: 'bar' as string | number});
```
Essentially, we want to prevent Typescript from distributing the type. [As specified in the handbook](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types):
> Typically, distributivity is the desired behavior. To avoid that behavior, you can surround each side of the extends keyword with square brackets.
This PR applies this suggestion to `FormBuilder`'s type inference.
Fixes#45912.
PR Close#45942
We've had a TODO to expose ManualOnPush for a long time, but it hasn't moved since then. These changes remove it since it would be easy to re-introduce if we wanted to, it frees up an extra space in the flags bitmap and it removes some `render3` tests that we won't have to migrate to `TestBed`.
PR Close#45943
When an external template is read, adds the template file to to the project which contains.
This is necessary to keep the projects open when navigating away from HTML files.
Since a `tsconfig` cannot express including non-TS files,
we need another way to indicate the template files are considered part of the project.
Note that this does not ensure that the project in question _directly_ contains the component
file. That is, the project might just include the component file through the program rather
than directly in the `include` glob of the `tsconfig`. This distinction is somewhat important
because the TypeScript language service/server prefers projects which _directly_ contain the TS
file (see `projectContainsInfoDirectly` in the TS codebase). What this means it that there can
possibly be a different project used between the TS and HTML files.
For example, in Nx projects, the referenced configs are `tsconfig.app.json` and
`tsconfig.editor.json`. `tsconfig.app.json` comes first in the base `tsconfig.json` and
contains the entry point of the app. `tsconfig.editor.json` contains the `**.ts` glob of all TS
files. This means that `tsconfig.editor.json` will be preferred by the TS server for TS files
but the `tsconfig.app.json` will be used for HTML files since it comes first and we cannot
effectively express `projectContainsInfoDirectly` for HTML files.
We could consider also updating the language server implementation to attempt
to select the project to use for the template file based on which project
contains its component file directly, using either the internal `project.projectContainsInfoDirectly`
or as a workaround, check `project.isRoot(componentTsFile)`.
Finally, keeping the projects open is hugely important in the solution style config case like
Nx. When a TS file is opened, TypeScript will only retain `tsconfig.editor.json` and not
`tsconfig.app.json`. However, if our extension does not also know to select
`tsconfig.editor.json`, it will automatically select `tsconfig.app.json` since it is defined
first in the `tsconfig.json` file. So we need to teach TS server that we are (1) interested in
keeping projects open when there is an HTML file open and (2) optionally attempt to do this
_only_ for projects that we know the TS language service will prioritize in TS files (i.e.,
attempt to only keep `tsconfig.editor.json` open and allow `tsconfig.app.json` to close)
and prioritize that project for all requests.
fixes https://github.com/angular/vscode-ng-language-service/issues/1623
fixes https://github.com/angular/vscode-ng-language-service/issues/876
PR Close#45601
Based on early feedback, calling `fb.nonNullable.group(...)` continues to be clunky for a form with many such groups. Allowing `NonNullableFormBuilder` to be directly injected enables the following:
```
constructor(private fb: NonNullableFormBuilder) {}
```
PR Close#45904
This allows the documentation for the options `errorOnUnknownElements` and `errorOnUnknownProperties` to be displayed in the docs.
They aren't currently displayed, as `TestModuleMetadata` is a type and not an interface.
See https://next.angular.io/api/core/testing/TestModuleMetadata
PR Close#45891
In PR #45405, the Angular Package Format (APF) was updated so that
secondary entry-points (such as `@angular/common/http`) do not have
their own `package.json` file, as they used to. Instead, the paths to
their various formats and types are exposed via the primary
`package.json` file's `exports` property. As an example, see the v13
[@angular/common/http/package.json][1] and compare it with the v14
[@angular/common/package.json > exports][2].
Previously, `ngcc` was not able to analyze such v14+ entry-points and
would instead error as it considered such entry-points missing.
This commit addresses the issue by detecting this situation and
synthesizing a `package.json` file for the secondary entry-points based
on the `exports` property of the primary `package.json` file. This data
is only used by `ngcc` in order to determine that the entry-point does
not need further processing, since it is already in Ivy format.
[1]: https://unpkg.com/browse/@angular/common@13.3.5/http/package.json
[2]: https://unpkg.com/browse/@angular/common@14.0.0-next.15/package.json
PR Close#45833
Move the `loadPackageJson()` helper (and associated generic types, such
as `JsonObject`) from `packages/entry_point.ts` to `utils.ts` and also
rename it to `loadJson()`. This way, they can be used in other places in
future commits, without introducing cyclical dependencies.
PR Close#45833
Speeds up the `d.ts` bundling by configuring it as a Bazel
persistent worker. Also improve logging for the ng packager
rule to make it easier to spot which actions/bundles take
up significant time.
Type bundling will occur for every entry-point so for machines
with rather limited cores/threads, this will be useful to save
NodeJS boot and resolution time.
PR Close#45900
This commit refactors the `Testability`-related logic to extract the necessary providers into a separate array, so that it can later become it's own NgModule (or exposed as an array of providers) and be excluded from the new APIs by default.
PR Close#45657
This commit renames an internal function that implements the core bootstrap logic. The function is exported as a private symbol (with `ɵ`), but in order to avoid any possible confusion, we include "internal" into the function name as well.
PR Close#45896
The NodeJS Bazel linker does not work well on Windows because there
is no sandboxing and linker processes from different tests will attempt
to modify the same `node_modules`, causing concurrency race conditions
and resulting in flakiness.
PR Close#45872
With typed forms, all `FormControl`s are nullable by default, because they can be reset to `null`. This behavior is possible to change by passing the option `initialValueIsDefault: true`. However, in a large form, this is extremely cumbersome, as the option must be repeated over and over. Additionally, it is not possible to take full advantage of `FormBuilder`, since `FormBuilder.group` and `FormBuilder.array` will produce nullable controls.
This PR introduces a new accessor `FormBuilder.nonNullable`, which produces *non-nullable* controls. Specifically, any call to `.control` will produce controls with `{initialValueIsDefault: true}`, and calls to `.array` or `.group` that implicitly build inner controls will have the same effect.
```ts
let nfb = new FormBuilder().nonNullable;
let name = nfb.group({who: 'Alex'}); // FormGroup<{who: FormControl<string>}>
name.reset();
console.log(name); // {who: 'Alex'}
```
PR Close#45852
All router events now have a `type` property with a string name identifying the specific type of the event.
The `type` property can be used to perform TypeScript type narrowing using an `if` statement, `switch`
statement, or similar. This removes the need to perform `instanceof` checks but still allows them if
preferred. An `instanceof` check requires the use of the event class value which may not be available
or preferred in certain situations.
The Router's `enableTracing` option is also now guarded with the `ngDevMode` flag which combined with
the use of a new `stringifyEvent` function allows the tree-shaking of the string generation code for
each router event class. However, the original `toString` class methods are still present to prevent
a potential breaking change. As a result, full benefits of the tree-shaking potential will not be realized
until they are removed.
PR Close#44189
Before this commit, when initializing `HttpParams` with:
const body = new HttpParams({fromObject: {b: 2}});
then `body.get('b')` returned `2` instead of `'2'` as expected.
This commit makes sure the values are converted to strings in such cases.
Fixes#42641
PR Close#42643
This commit updates the logic of the `BrowserModule` to detect a situation when it's used in the `bootstrapApplication` case, which already includes `BrowserModule` providers.
PR Close#45826
Allows to provide a TestBed option to throw on unknown properties in templates:
```ts
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(), {
errorOnUnknownProperties: true
}
);
```
The default value of `errorOnUnknownProperties` is `false`, so this is not a breaking change.
PR Close#45853
This commit narrows down acceptable argument types of the
`importProvidersFrom` function. More specifically, it rejects
standalone components as a source of imports.
PR Close#45837
This commit improves the error message for using `imports` on a component
that isn't set to `standalone: true`. Two concrete improvements are made:
* A related information message is added to the diagnostic which suggests
the fix of adding `standalone: true`.
* The component is marked as poisoned, preventing other errors which might
be caused by an incorrectly configured template scope from being generated
and thus masking the original problem.
Fixes#45850
PR Close#45851
In AOT compilations, the `strictInjectionParameters` compiler option can
be enabled to report errors when an `@Injectable` annotated class has a
constructor with parameters that do not provide an injection token, e.g.
only a primitive type or interface.
Since Ivy it's become required that any class with Angular behavior
(e.g. the `ngOnDestroy` lifecycle hook) is decorated using an Angular
decorator, which meant that `@Injectable()` may need to have been added
to abstract base classes. Doing so would then report an error if
`strictInjectionParameters` is enabled, if the abstract class has an
incompatible constructor for DI purposes. This may be fine though, as
a subclass may call the constructor explicitly without relying on
Angular's DI mechanism.
Therefore, this commit excludes abstract classes from the
`strictInjectionParameters` check. This avoids an error from being
reported at compile time. If the constructor ends up being used by
Angular's DI system at runtime, then the factory function of the
abstract class will throw an error by means of the `ɵɵinvalidFactory`
instruction.
In addition to the runtime error, this commit also analyzes the inheritance
chain of an injectable without a constructor to verify that their inherited
constructor is valid.
Closes#37914
PR Close#44615
This commit updates an internal logic of the TestBed to recognize Standalone Components to be able to apply the necessary overrides correctly.
PR Close#45809
Excludes styles that resolve to empty strings from the emitted metadata so that they don't result in empty `<style>` tags at runtime.
Fixes#31191.
PR Close#45459
`importProvidersFrom` provides a bridge from the world of NgModule-based DI
configuration to the new, "standalone" world of direct providers and
environment injectors. Early user feedback suggested some confusion around
where this function was supposed to be used, particularly around importing
NgModule-based providers into standalone component `providers` arrays, which
is not the intended use. This confusion is exacerbated by the fact that due
to the unified `Provider` type, this kind of misconfiguration was happily
accepted by the type system.
This commit changes the return type of `importProvidersFrom` to wrap the
returned providers in an opaque type that prevents them from being used in
component provider contexts. This, together with stronger documentation
around the purpose and functionality of `importProvidersFrom`, should
address some of the above confusion.
PR Close#45838
Changes the message from:
```
The component 'HelloComponent' appears in 'imports', but is not standalone
and cannot be imported directly It must be imported via an NgModule.
```
to
```
The component 'HelloComponent' appears in 'imports', but is not standalone
and cannot be imported directly. It must be imported via an NgModule.
```
PR Close#45827
The analysis phase of the compiler should operate on individual classes, independently
of the analysis of other classes. The validation that `Component.imports` only
contains standalone entities or NgModules however did happen during the analysis phase,
introducing a dependency on other classes and causing inconsistencies due to ordering
and/or asynchronous timing differences.
This commit fixes the issue by moving the validation to the resolve phase, which occurs
after all classes have been analyzed.
Fixes#45819
PR Close#45827
This commit updates the `renderApplication` function to move the `appId` argument to the options object. The goal is to achieve a symmetry with the `bootstrapApplication` call (use to bootstrap apps for the browser environment).
PR Close#45844
This commit updates the logic to detect a situation when a standalone component is used in the NgModule-based bootstrap (`@NgModule.bootstrap`). Both AOT and JIT compilers are updated to handle this situation.
PR Close#45825
Allows to provide a TestBed option to throw on unknown elements in templates:
```ts
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(), {
errorOnUnknownElements: true
}
);
```
The default value of `errorOnUnknownElements` is `false`, so this is not a breaking change.
PR Close#45479
Allows to provide a TestBed option to throw on unknown elements in templates:
```ts
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(), {
errorOnUnknownElements: true
}
);
```
The default value of `errorOnUnknownElements` is `false`, so this is not a breaking change.
PR Close#45479
In v14, the partial compilation output of components have changed in a way
that prevents older versions of Angular to compile the partial declarations
correctly.
In particular, we used to emit used directives/components in separate arrays called
`components` and `directives`, and used pipes in a property called `pipes`:
```js
TestComponent.ɵcmp = i0.ɵɵngDeclareComponent({
minVersion: "12.0.0",
version: "13.3.0",
type: TestComponent,
selector: "ng-component",
ngImport: i0,
template: ``,
isInline: true,
directives: [{ type: i1.SomeDir, selector: "[some-dir]" }],
components: [{ type: i1.SomeCmp, selector: "some-cmp" }],
pipes: { 'async': i2.AsyncPipe },
});
```
In the above example, the `version` property indicates which exact compiler
version was used to compile the component, but the `minVersion` allows older
versions of the compiler/Angular linker to "link" the partial declaration to
its final AOT compilation output.
In v14, the used directives, components and pipes are now emitted together
into a single array under the `dependencies` property:
```js
TestComponent.ɵcmp = i0.ɵɵngDeclareComponent({
minVersion: "12.0.0",
version: "13.3.0",
type: TestComponent,
selector: "ng-component",
ngImport: i0,
template: ``,
isInline: true,
dependencies: [
{ kind: "directive", type: i1.SomeDir, selector: "[some-dir]" },
{ kind: "component", type: i1.SomeCmp, selector: "some-cmp" },
{ kind: "pipe", type: i2.AsyncPipe },
],
});
```
This change has been made in support of standalone components, but it does mean
that older compiler versions can no longer link these partial declarations
as desirable as none of the components, directives and pipes would be included
in the AOT-compiled code.
By increasing the `minVersion` property, we hint to older compiler versions that
they are not capable of processing the partial declaration. This allows reporting
an error at compile time instead of resulting in runtime failures due to missing
components, directives and pipes.
PR Close#45782
This commit adds the `renderApplication` function to bootstrap an Angular app using a root standalone component to support SSR scenarios.
PR Close#45785
Update CLDR, which is used to generate the locales files, to version 41.
Also, make necessary code changes to account for changes in the CLDR
data.
Fixes#43301
PR Close#45714
While generating locales, two sets of data (both derived from the
[CLDR project][1]) are used:
- JSON data with the [`cldrjs` package][2], which is used for most
operations.
- XML data with the [`cldr` package][3], which is used for generating
plural-related data.
The JSON data is brought in from the [unicode-org/cldr-json][4]
repository. Since we control the version of the repository that we use,
we can control the CLDR version that these correspond to.
Previously, however, we used the XML data that were bundled with the
[`cldr` package[3]. As a result, the two sets of data could correspond
to different CLDR versions, resulting in incorrect/inconsistent locales
files.
This commit addresses the problem by utilizing the `load()` method of
the [`cldr` package][3], which allows passing in a custom path to the
CLDR XML data (instead of using the bundled data. This way, we can
ensure that the data used for all operations correspond to the same CLDR
version.
Related discussion: #43301
[1]: https://github.com/unicode-org/cldr
[2]: https://www.npmjs.com/package/cldrjs
[3]: https://www.npmjs.com/package/cldr
[4]: https://github.com/unicode-org/cldr-json
PR Close#45714
Previously, some functions/targets related to the
generation/verification of the `closure-locale.ts` file included
`closure_locales` instead of `closure_locale` in their name, which was
inconsistent and confusing.
Rename all tooling to use `closure_locale` (which more closely matches
the generated file's name).
PR Close#45714