mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9136dbd65c | |||
| 4a1d9a78fa | |||
| 0f8ae8bf7f | |||
| c42b50cfbe | |||
| a3bc29bbb2 | |||
| 387dcc6621 | |||
| 029060f2d6 | |||
| a53d26847c | |||
| 21e2b93046 | |||
| 92012ec4fd | |||
| 6ca81a706c | |||
| 0baabcb7da | |||
| dc6cb5a3d4 | |||
| 7da3570be8 | |||
| ec192b2b71 | |||
| 55fe2c667d | |||
| 8a3d2aad30 | |||
| dd3abdb9d9 | |||
| d93427b806 | |||
| 032e65c895 | |||
| ee05a285f9 | |||
| 4371ff9092 | |||
| a26b0dcc72 | |||
| 30c5b9c144 | |||
| 673f7a7954 | |||
| cdc8c7cad0 | |||
| bd7f0d8b70 | |||
| 3a9ce61ea4 | |||
| ae98b24eb7 | |||
| 4997a3f692 | |||
| 6a59e6b009 | |||
| 6f80c55dbd | |||
| 07846e550c | |||
| f18131f372 | |||
| f24b94f5d9 | |||
| 6caafc2062 | |||
| f883aaeb89 | |||
| 2215af252c | |||
| db4147b4d2 | |||
| 2dc6efed4e | |||
| 1d307bc5bf | |||
| aace1e71d8 | |||
| fbfec946a7 | |||
| 0e47334db8 | |||
| e4f62c12f5 | |||
| ea3a14805e | |||
| a96f9c91a2 | |||
| a8c0f4f1ba | |||
| 11ef03b36f | |||
| 8e798effe4 | |||
| 54f73530a8 | |||
| 61080ea4bc | |||
| 4116d5d18f | |||
| 5572278826 | |||
| b442c4991d | |||
| 014763e42c | |||
| 86cfbf8c8a | |||
| 3b92b4abd3 | |||
| dd6e80aac5 | |||
| da50b9b5e7 | |||
| 86e4b3cdf9 | |||
| 3fddcb5364 | |||
| d5cc87dc88 | |||
| b075721a49 | |||
| 3346cb6e4e |
@@ -1,3 +1,56 @@
|
||||
<a name="12.2.1"></a>
|
||||
# 12.2.1 (2021-08-11)
|
||||
### router
|
||||
| Commit | Description |
|
||||
| -- | -- |
|
||||
| [dd3abdb9d9](https://github.com/angular/angular/commit/dd3abdb9d9b2c4363fb1f468a05bf449b55f55a5) | fix(router): ensure check for match options is compatible with property renaming ([#43086](https://github.com/angular/angular/pull/43086)) |
|
||||
## Special Thanks:
|
||||
Amadou Sall, Andrew Kushnir, Andrew Scott, Daniel Trevino, Erik Slack, Fabien BERNARD, George Kalpakas, Jeroen van Warmerdam, Joey Perrott, Tim Gates and Vugar_Abdullayev
|
||||
|
||||
|
||||
<a name="12.2.0"></a>
|
||||
# 12.2.0 (2021-08-04)
|
||||
### core
|
||||
| Commit | Description |
|
||||
| -- | -- |
|
||||
| [bd7f0d8b70](https://github.com/angular/angular/commit/bd7f0d8b70150a7e4e7550f4380a2e731cf2b942) | fix(core): incorrect error reported when trying to re-create view which had an error during creation ([#43005](https://github.com/angular/angular/pull/43005)) |
|
||||
### language-service
|
||||
| Commit | Description |
|
||||
| -- | -- |
|
||||
| [aace1e71d8](https://github.com/angular/angular/commit/aace1e71d8fb5e1e52fcd86e2a26892d1016c43e) | fix(language-service): global autocomplete doesn't work when the user tries to modify the symbol ([#42923](https://github.com/angular/angular/pull/42923)) |
|
||||
## Special Thanks:
|
||||
Alex Rickabaugh, Joe Martin, Joey Perrott, Kristiyan Kostadinov, Nichola Alkhouri, Paul Gschwendtner, Pete Bacon Darwin, atscott, dario-piotrowicz and ivanwonder
|
||||
|
||||
|
||||
<a name="12.2.0-rc.0"></a>
|
||||
# 12.2.0-rc.0 (2021-07-28)
|
||||
### compiler-cli
|
||||
| Commit | Description |
|
||||
| -- | -- |
|
||||
| [ed9cfb674f](https://github.com/angular/angular/commit/ed9cfb674f8e52b416ccdaf9aa9c46955b8448f5) | fix(compiler-cli): use correct module resolution context for absolute imports in .d.ts files ([#42879](https://github.com/angular/angular/pull/42879)) |
|
||||
| [5fb23eccea](https://github.com/angular/angular/commit/5fb23ecceaccf0629308dd50210b65f67d51f024) | perf(compiler-cli): skip analysis in incremental builds for files without Angular behavior ([#42562](https://github.com/angular/angular/pull/42562)) |
|
||||
### core
|
||||
| Commit | Description |
|
||||
| -- | -- |
|
||||
| [eefe1682e8](https://github.com/angular/angular/commit/eefe1682e8099b73b6e50bb227b5a7f63105c63d) | fix(core): correctly handle `null` or `undefined` in `ErrorHandler#handleError()` ([#42881](https://github.com/angular/angular/pull/42881)) |
|
||||
### forms
|
||||
| Commit | Description |
|
||||
| -- | -- |
|
||||
| [1d9d02696e](https://github.com/angular/angular/commit/1d9d02696eadbee2c2f719e432efca22f1e494e9) | feat(forms): add hasValidators, addValidators, and removeValidators methods (for both sync and async) ([#42838](https://github.com/angular/angular/pull/42838)) |
|
||||
| [a502279592](https://github.com/angular/angular/commit/a50227959222f39884aac284544d1626aee5ca64) | feat(forms): allow minLength/maxLength validator to be bound to `null` ([#42565](https://github.com/angular/angular/pull/42565)) |
|
||||
### language-service
|
||||
| Commit | Description |
|
||||
| -- | -- |
|
||||
| [7c35ca0e00](https://github.com/angular/angular/commit/7c35ca0e0030f2ded12ddca9092e31f510cebeb1) | feat(language-service): support autocomplete string literal union types in templates ([#42729](https://github.com/angular/angular/pull/42729)) |
|
||||
### router
|
||||
| Commit | Description |
|
||||
| -- | -- |
|
||||
| [0d81b007e4](https://github.com/angular/angular/commit/0d81b007e48a0ac801d2614601fb8180a3517865) | fix(router): add missing outlet events to RouterOutletContract ([#42431](https://github.com/angular/angular/pull/42431)) |
|
||||
| [dbae00195e](https://github.com/angular/angular/commit/dbae00195e114ac8b967201283962a7e2c0581b4) | feat(router): ability to provide custom route reuse strategy via DI for `RouterTestingModule` ([#42434](https://github.com/angular/angular/pull/42434)) |
|
||||
## Special Thanks:
|
||||
Andrew Scott, Daniel Trevino, Dmitrij Kuba, Dylan Hunn, George Kalpakas, Joey Perrott, JoostK, Paul Gschwendtner, Pete Bacon Darwin, Steven Masala, Teri Glover, Vladyslav, Yuvaraj, codebriefcase, iRealNirmal and ivanwonder
|
||||
|
||||
|
||||
<a name="12.1.4"></a>
|
||||
# 12.1.4 (2021-07-28)
|
||||
### compiler-cli
|
||||
|
||||
@@ -25,7 +25,7 @@ describe('AppComponent', () => {
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.nativeElement;
|
||||
expect(compiled.querySelector('.content span').textContent).toContain('component-overview app is running!');
|
||||
const compiled = fixture.nativeElement as HTMLElement;
|
||||
expect(compiled.querySelector('.content span')?.textContent).toContain('component-overview app is running!');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ export class AdBannerComponent implements OnInit, OnDestroy {
|
||||
@Input() ads: AdItem[] = [];
|
||||
currentAdIndex = -1;
|
||||
@ViewChild(AdDirective, {static: true}) adHost!: AdDirective;
|
||||
interval: any;
|
||||
interval: number | undefined;
|
||||
|
||||
constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"tests": [
|
||||
{"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadless", "--no-watch"]},
|
||||
{"cmd": "yarn", "args": ["e2e", "--prod", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]}
|
||||
{"cmd": "yarn", "args": ["e2e", "--configuration=production", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ describe('AppComponent', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
expect(compiled.querySelector('h1').textContent).toContain('Forms Overview');
|
||||
const compiled = fixture.nativeElement as HTMLElement;
|
||||
expect(compiled.querySelector('h1')?.textContent).toContain('Forms Overview');
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
"projectType": "testing",
|
||||
"tests": [
|
||||
{"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadless", "--no-watch"]},
|
||||
{"cmd": "yarn", "args": ["e2e", "--prod", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]}
|
||||
{"cmd": "yarn", "args": ["e2e", "--configuration=production", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"projectType": "service-worker",
|
||||
"tests": [
|
||||
{"cmd": "yarn", "args": ["e2e", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]},
|
||||
{"cmd": "yarn", "args": ["build", "--prod"]},
|
||||
{"cmd": "yarn", "args": ["build"]},
|
||||
{"cmd": "node", "args": ["--eval", "assert(fs.existsSync('./dist/ngsw.json'), 'ngsw.json is missing')"]},
|
||||
{"cmd": "node", "args": ["--eval", "assert(fs.existsSync('./dist/ngsw-worker.js'), 'ngsw-worker.js is missing')"]},
|
||||
{"cmd": "node", "args": ["--eval", "assert(require('./package.json').dependencies['@angular/service-worker'], '@angular/service-worker is missing')"]}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"tests": [
|
||||
{"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadless", "--no-watch"]},
|
||||
{"cmd": "yarn", "args": ["e2e", "--prod", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]}
|
||||
{"cmd": "yarn", "args": ["e2e", "--configuration=production", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
"projectType": "testing",
|
||||
"tests": [
|
||||
{"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadless", "--no-watch"]},
|
||||
{"cmd": "yarn", "args": ["e2e", "--prod", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]}
|
||||
{"cmd": "yarn", "args": ["e2e", "--configuration=production", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ describe('AppComponent (initial CLI version)', () => {
|
||||
it('should render title', waitForAsync(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.nativeElement;
|
||||
expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
|
||||
const compiled = fixture.nativeElement as HTMLElement;
|
||||
expect(compiled.querySelector('h1')?.textContent).toContain('Welcome to app!');
|
||||
}));
|
||||
});
|
||||
// #enddocregion
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"tests": [
|
||||
{"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadless", "--no-watch"]},
|
||||
{"cmd": "yarn", "args": ["e2e", "--prod", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]}
|
||||
{"cmd": "yarn", "args": ["e2e", "--configuration=production", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"projectType": "universal",
|
||||
"e2e": [
|
||||
{"cmd": "yarn", "args": ["e2e", "--prod", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]},
|
||||
{"cmd": "yarn", "args": ["e2e", "--configuration=production", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]},
|
||||
{"cmd": "yarn", "args": ["run", "build:ssr"]}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ The template options object, `angularCompilerOptions`, is a sibling to the `comp
|
||||
{@a tsconfig-extends}
|
||||
## Configuration inheritance with extends
|
||||
|
||||
Like the TypeScript compiler, The Angular AOT compiler also supports `extends` in the `angularCompilerOptions` section of the TypeScript configuration file.
|
||||
Like the TypeScript compiler, the Angular AOT compiler also supports `extends` in the `angularCompilerOptions` section of the TypeScript configuration file.
|
||||
The `extends` property is at the top level, parallel to `compilerOptions` and `angularCompilerOptions`.
|
||||
|
||||
A TypeScript configuration can inherit settings from another file using the `extends` property.
|
||||
|
||||
@@ -249,7 +249,7 @@ See the [Styles configuration guide](guide/workspace-config#styles-and-scripts-c
|
||||
### Non-CSS style files
|
||||
|
||||
If you're building with the CLI,
|
||||
you can write style files in [sass](https://sass-lang.com/), [less](http://lesscss.org/), or [stylus](https://stylus-lang.com/) and specify those files in the `@Component.styleUrls` metadata with the appropriate extensions (`.scss`, `.less`, `.styl`) as in the following example:
|
||||
you can write style files in [sass](https://sass-lang.com/), or [less](http://lesscss.org/), and specify those files in the `@Component.styleUrls` metadata with the appropriate extensions (`.scss`, `.less`) as in the following example:
|
||||
|
||||
<code-example>
|
||||
@Component({
|
||||
|
||||
@@ -23,43 +23,43 @@ The most basic form of content projection is *single-slot content projection*. S
|
||||
|
||||
To create a component that uses single-slot content projection:
|
||||
|
||||
1. [Create](guide/component-overview) a component.
|
||||
1. [Create a component](guide/component-overview#creating-a-component).
|
||||
|
||||
1. In the template for your component, add an `ng-content` element where you want the projected content to appear.
|
||||
1. In the template for your component, add an `<ng-content>` element where you want the projected content to appear.
|
||||
|
||||
For example, the following component uses an `ng-content` element to display a message.
|
||||
For example, the following component uses an `<ng-content>` element to display a message.
|
||||
|
||||
<code-example path="content-projection/src/app/zippy-basic/zippy-basic.component.ts" header="content-projection/src/app/zippy-basic/zippy-basic.component.ts"></code-example>
|
||||
|
||||
With the `ng-content` element in place, users of this component can now project their own message into the component. For example:
|
||||
With the `<ng-content>` element in place, users of this component can now project their own message into the component. For example:
|
||||
|
||||
<code-example path="content-projection/src/app/app.component.html" header="content-projection/src/app/app.component.html"
|
||||
region="single-slot"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
The `ng-content` element is a placeholder that does not create a real DOM element. Custom attributes applied to `ng-content` are ignored.
|
||||
The `<ng-content>` element is a placeholder that does not create a real DOM element. Custom attributes applied to `<ng-content>` are ignored.
|
||||
|
||||
</div>
|
||||
|
||||
{@a multi-slot}
|
||||
## Multi-slot content projection
|
||||
|
||||
A component can have multiple slots. Each slot can specify a CSS selector that determines which content goes into that slot. This pattern is referred to as *multi-slot content projection*. With this pattern, you must specify where you want the projected content to appear. You accomplish this task by using the `select` attribute of `ng-content`.
|
||||
A component can have multiple slots. Each slot can specify a CSS selector that determines which content goes into that slot. This pattern is referred to as *multi-slot content projection*. With this pattern, you must specify where you want the projected content to appear. You accomplish this task by using the `select` attribute of `<ng-content>`.
|
||||
|
||||
To create a component that uses multi-slot content projection:
|
||||
|
||||
1. [Create](guide/component-overview) a component.
|
||||
1. [Create a component](guide/component-overview#creating-a-component).
|
||||
|
||||
1. In the template for your component, add an `ng-content` element where you want the projected content to appear.
|
||||
1. In the template for your component, add an `<ng-content>` element where you want the projected content to appear.
|
||||
|
||||
1. Add a `select` attribute to the `ng-content` elements. Angular supports [selectors](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors) for any combination of tag name, attribute, CSS class, and the `:not` pseudo-class.
|
||||
1. Add a `select` attribute to the `<ng-content>` elements. Angular supports [selectors](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors) for any combination of tag name, attribute, CSS class, and the `:not` pseudo-class.
|
||||
|
||||
For example, the following component uses two `ng-content` elements.
|
||||
For example, the following component uses two `<ng-content>` elements.
|
||||
|
||||
<code-example path="content-projection/src/app/zippy-multislot/zippy-multislot.component.ts" header="content-projection/src/app/zippy-multislot/zippy-multislot.component.ts"></code-example>
|
||||
|
||||
Content that uses the `question` attribute is projected into the `ng-content` element with the `select=[question]` attribute.
|
||||
Content that uses the `question` attribute is projected into the `<ng-content>` element with the `select=[question]` attribute.
|
||||
|
||||
<code-example path="content-projection/src/app/app.component.html" header="content-projection/src/app/app.component.html"
|
||||
region="multi-slot"></code-example>
|
||||
@@ -68,9 +68,9 @@ region="multi-slot"></code-example>
|
||||
|
||||
<header>ng-content without a select attribute</header>
|
||||
|
||||
If your component includes an `ng-content` element without a `select` attribute, that instance receives all projected components that do not match any of the other `ng-content` elements.
|
||||
If your component includes an `<ng-content>` element without a `select` attribute, that instance receives all projected components that do not match any of the other `<ng-content>` elements.
|
||||
|
||||
In the preceding example, only the second `ng-content` element defines a `select` attribute. As a result, the first `ng-content` element receives any other content projected into the component.
|
||||
In the preceding example, only the second `<ng-content>` element defines a `select` attribute. As a result, the first `<ng-content>` element receives any other content projected into the component.
|
||||
|
||||
</div>
|
||||
|
||||
@@ -78,41 +78,41 @@ In the preceding example, only the second `ng-content` element defines a `select
|
||||
|
||||
## Conditional content projection
|
||||
|
||||
If your component needs to _conditionally_ render content, or render content multiple times, you should configure that component to accept an `ng-template` element that contains the content you want to conditionally render.
|
||||
If your component needs to _conditionally_ render content, or render content multiple times, you should configure that component to accept an `<ng-template>` element that contains the content you want to conditionally render.
|
||||
|
||||
Using an `ng-content` element in these cases is not recommended, because when the consumer of a component supplies the content, that content is _always_ initialized, even if the component does not define an `ng-content` element or if that `ng-content` element is inside of an `ngIf` statement.
|
||||
Using an `<ng-content>` element in these cases is not recommended, because when the consumer of a component supplies the content, that content is _always_ initialized, even if the component does not define an `<ng-content>` element or if that `<ng-content>` element is inside of an `ngIf` statement.
|
||||
|
||||
With an `ng-template` element, you can have your component explicitly render content based on any condition you want, as many times as you want. Angular will not initialize the content of an `ng-template` element until that element is explicitly rendered.
|
||||
With an `<ng-template>` element, you can have your component explicitly render content based on any condition you want, as many times as you want. Angular will not initialize the content of an `<ng-template>` element until that element is explicitly rendered.
|
||||
|
||||
The following steps demonstrate a typical implementation of conditional content projection using `ng-template`.
|
||||
The following steps demonstrate a typical implementation of conditional content projection using `<ng-template>`.
|
||||
|
||||
1. [Create](guide/component-overview) a component.
|
||||
1. [Create a component](guide/component-overview#creating-a-component).
|
||||
|
||||
1. In the component that accepts an `ng-template` element, use an `ng-container` element to render that template, such as:
|
||||
1. In the component that accepts an `<ng-template>` element, use an `<ng-container>` element to render that template, such as:
|
||||
|
||||
<code-example path="content-projection/src/app/example-zippy.template.html" header="content-projection/src/app/example-zippy.template.html" region="ng-container">
|
||||
</code-example>
|
||||
|
||||
This example uses the `ngTemplateOutlet` directive to render a given `ng-template` element, which you will define in a later step. You can apply an `ngTemplateOutlet` directive to any type of element. This example assigns the directive to an `ng-container` element because the component does not need to render a real DOM element.
|
||||
This example uses the `ngTemplateOutlet` directive to render a given `<ng-template>` element, which you will define in a later step. You can apply an `ngTemplateOutlet` directive to any type of element. This example assigns the directive to an `<ng-container>` element because the component does not need to render a real DOM element.
|
||||
|
||||
1. Wrap the `ng-container` element in another element, such as a `div` element, and apply your conditional logic.
|
||||
1. Wrap the `<ng-container>` element in another element, such as a `div` element, and apply your conditional logic.
|
||||
|
||||
<code-example path="content-projection/src/app/example-zippy.template.html" header="content-projection/src/app/example-zippy.template.html" region="ngif">
|
||||
</code-example>
|
||||
|
||||
1. In the template where you want to project content, wrap the projected content in an `ng-template` element, such as:
|
||||
1. In the template where you want to project content, wrap the projected content in an `<ng-template>` element, such as:
|
||||
|
||||
<code-example path="content-projection/src/app/app.component.html" region="ng-template">
|
||||
</code-example>
|
||||
|
||||
The `ng-template` element defines a block of content that a component can render based on its own logic. A component can get a reference to this template content, or [`TemplateRef`](/api/core/TemplateRef), by using either the [`@ContentChild`](/api/core/ContentChild) or [`@ContentChildren`](/api/core/ContentChildren) decorators. The preceding example creates a custom directive, `appExampleZippyContent`, as an API to mark the `ng-template` for the component's content. With the `TemplateRef`, the component can render the referenced content by using either the [`ngTemplateOutlet`](/api/common/NgTemplateOutlet) directive, or with [`ViewContainerRef.createEmbeddedView`](/api/core/ViewContainerRef#createembeddedview).
|
||||
The `<ng-template>` element defines a block of content that a component can render based on its own logic. A component can get a reference to this template content, or `TemplateRef`, by using either the `@ContentChild` or `@ContentChildren` decorators. The preceding example creates a custom directive, `appExampleZippyContent`, as an API to mark the `<ng-template>` for the component's content. With the `TemplateRef`, the component can render the referenced content by using either the `ngTemplateOutlet` directive, or with the `ViewContainerRef` method `createEmbeddedView()`.
|
||||
|
||||
1. Create a directive with a selector that matches the custom attribute for your template. In this directive, inject a TemplateRef instance.
|
||||
1. [Create an attribute directive](guide/attribute-directives#building-an-attribute-directive) with a selector that matches the custom attribute for your template. In this directive, inject a TemplateRef instance.
|
||||
|
||||
<code-example path="content-projection/src/app/app.component.ts" header="content-projection/src/app/app.component.ts" region="zippycontentdirective">
|
||||
</code-example>
|
||||
|
||||
In the previous step, you added an `ng-template` element with a custom attribute, `appExampleZippyDirective`. This code provides the logic that Angular will use when it encounters that custom attribute. In this case, that logic instructs Angular to instantiate a template reference.
|
||||
In the previous step, you added an `<ng-template>` element with a custom attribute, `appExampleZippyDirective`. This code provides the logic that Angular will use when it encounters that custom attribute. In this case, that logic instructs Angular to instantiate a template reference.
|
||||
|
||||
1. In the component you want to project content into, use `@ContentChild` to get the template of the projected content.
|
||||
|
||||
@@ -144,14 +144,14 @@ For instance, consider the following HTML snippet:
|
||||
<code-example path="content-projection/src/app/app.component.html" header="content-projection/src/app/app.component.html" region="ngprojectas">
|
||||
</code-example>
|
||||
|
||||
This example uses an `ng-container` attribute to simulate projecting a component into a more complex structure.
|
||||
This example uses an `<ng-container>` attribute to simulate projecting a component into a more complex structure.
|
||||
|
||||
<div class="callout is-helpful">
|
||||
|
||||
<header>Reminder!</header>
|
||||
|
||||
The `ng-container` element is a logical construct that you can use to group other DOM elements; however, the `ng-container` itself is not rendered in the DOM tree.
|
||||
The `<ng-container>` element is a logical construct that you can use to group other DOM elements; however, the `<ng-container>` itself is not rendered in the DOM tree.
|
||||
|
||||
</div>
|
||||
|
||||
In this example, the content we want to project resides inside another element. To project this content as intended, the template uses the `ngProjectAs` attribute. With `ngProjectAs`, the entire `ng-container` element is projected into a component using the `[question]` selector.
|
||||
In this example, the content we want to project resides inside another element. To project this content as intended, the template uses the `ngProjectAs` attribute. With `ngProjectAs`, the entire `<ng-container>` element is projected into a component using the `[question]` selector.
|
||||
|
||||
@@ -1092,7 +1092,7 @@ See [custom element](#custom-element).
|
||||
|
||||
## workspace
|
||||
|
||||
A collection of Angular [projects](#project) (that is, applications and libraries) powered by the [Angular CLI] (#cli) that are typically co-located in a single source-control repository (such as [git](https://git-scm.com/)).
|
||||
A collection of Angular [projects](#project) (that is, applications and libraries) powered by the [Angular CLI](#cli) that are typically co-located in a single source-control repository (such as [git](https://git-scm.com/)).
|
||||
|
||||
The [CLI](#cli) [`ng new` command](cli/new) creates a file system directory (the "workspace root").
|
||||
In the workspace root, it also creates the workspace [configuration file](#configuration) (`angular.json`) and, by default, an initial application project with the same name.
|
||||
|
||||
@@ -1021,8 +1021,8 @@ The logical tree representation shows why this is:
|
||||
@Inject(AnimalService, @Optional)=>"🦔">
|
||||
<!-- ^^@SkipSelf() starts here, @Host() stops here^^ -->
|
||||
<app-child>
|
||||
<#VIEW @Provide(AnimalService="🦔")
|
||||
@Inject(AnimalService, @SkipSelf, @Host, @Optional)=>"🐶">
|
||||
<#VIEW @Provide(AnimalService="🐶")
|
||||
@Inject(AnimalService, @SkipSelf, @Host, @Optional)=>"🦔">
|
||||
<!-- Add @SkipSelf ^^-->
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
|
||||
@@ -582,7 +582,7 @@ For example, the following excerpt of an `angular.json` file sets the source loc
|
||||
<code-example language="json" header="angular.json">
|
||||
...
|
||||
"projects": {
|
||||
"angular.io-example": {
|
||||
"my-project": {
|
||||
...
|
||||
"i18n": {
|
||||
"sourceLocale": "en-US",
|
||||
@@ -712,18 +712,19 @@ For production builds, you can use configuration composition to execute both con
|
||||
...
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "my-project:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "my-project:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "my-project:build:development"
|
||||
},
|
||||
"fr": {
|
||||
"browserTarget": "my-project:build:fr"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
}
|
||||
</code-example>
|
||||
|
||||
@@ -759,7 +760,7 @@ The HTML `base` tag with the `href` attribute specifies the base URI, or URL, fo
|
||||
<code-example language="json" header="angular.json">
|
||||
...
|
||||
"projects": {
|
||||
"angular.io-example": {
|
||||
"my-project": {
|
||||
...
|
||||
"i18n": {
|
||||
"sourceLocale": "en-US",
|
||||
@@ -984,4 +985,4 @@ Both elements now use the same translation (`Bonjour`) because they were defined
|
||||
<p>Bonjour</p>
|
||||
```
|
||||
|
||||
@reviewed 2020-04-10
|
||||
@reviewed 2020-04-10
|
||||
|
||||
@@ -197,8 +197,7 @@ By using the long form, the schematic can provide more explicit formatting of th
|
||||
"css",
|
||||
"scss",
|
||||
"sass",
|
||||
"less",
|
||||
"styl"
|
||||
"less"
|
||||
],
|
||||
"x-prompt": {
|
||||
"message": "Which stylesheet format would you like to use?",
|
||||
@@ -207,8 +206,7 @@ By using the long form, the schematic can provide more explicit formatting of th
|
||||
{ "value": "css", "label": "CSS" },
|
||||
{ "value": "scss", "label": "SCSS [ https://sass-lang.com/documentation/syntax#scss ]" },
|
||||
{ "value": "sass", "label": "Sass [ https://sass-lang.com/documentation/syntax#the-indented-syntax ]" },
|
||||
{ "value": "less", "label": "Less [ http://lesscss.org/ ]" },
|
||||
{ "value": "styl", "label": "Stylus [ https://stylus-lang.com/ ]" }
|
||||
{ "value": "less", "label": "Less [ http://lesscss.org/ ]" }
|
||||
]
|
||||
},
|
||||
},
|
||||
|
||||
@@ -203,7 +203,7 @@ The important bit in the `server.ts` file is the `ngExpressEngine()` function.
|
||||
The `ngExpressEngine()` function is a wrapper around Universal's `renderModule()` function which turns a client's
|
||||
requests into server-rendered HTML pages. It accepts an object with the following properties:
|
||||
|
||||
* `bootstrap`: The root `NgModule` or `NgModule` factory to use for bootstraping the application when rendering on the server. For the example app, it is `AppServerModule`. It's the bridge between the Universal server-side renderer and the Angular application.
|
||||
* `bootstrap`: The root `NgModule` or `NgModule` factory to use for bootstrapping the application when rendering on the server. For the example app, it is `AppServerModule`. It's the bridge between the Universal server-side renderer and the Angular application.
|
||||
* `extraProviders`: This is optional and lets you specify dependency providers that apply only when rendering the application on the server. You can do this when your application needs information that can only be determined by the currently running server instance.
|
||||
|
||||
The `ngExpressEngine()` function returns a `Promise` callback that resolves to the rendered page.
|
||||
|
||||
@@ -590,7 +590,7 @@ The safest bet for ensuring compatibility is using the
|
||||
[component API](https://docs.angularjs.org/api/ng/type/angular.Module)
|
||||
introduced in AngularJS 1.5.
|
||||
|
||||
An example of an upgradable component is one that just has a template
|
||||
An example of an upgradeable component is one that just has a template
|
||||
and a controller:
|
||||
|
||||
<code-example path="upgrade-module/src/app/upgrade-static/hero-detail.component.ts" region="hero-detail" header="hero-detail.component.ts">
|
||||
|
||||
@@ -191,10 +191,10 @@ Some additional options can only be set through the configuration file, either b
|
||||
| OPTIONS PROPERTIES | DESCRIPTION |
|
||||
| :------------------------- | :---------------------------- |
|
||||
| `assets` | An object containing paths to static assets to add to the global context of the project. The default paths point to the project's icon file and its `assets` folder. See more in [Assets configuration](#asset-config) below. |
|
||||
| `styles` | An array of style files to add to the global context of the project. Angular CLI supports CSS imports and all major CSS preprocessors: [sass/scss](https://sass-lang.com/), [less](http://lesscss.org/), and [stylus](https://stylus-lang.com/). See more in [Styles and scripts configuration](#style-script-config) below. |
|
||||
| `styles` | An array of style files to add to the global context of the project. Angular CLI supports CSS imports and all major CSS preprocessors: [sass/scss](https://sass-lang.com/) and [less](http://lesscss.org/). See more in [Styles and scripts configuration](#style-script-config) below. |
|
||||
| `stylePreprocessorOptions` | An object containing option-value pairs to pass to style preprocessors. See more in [Styles and scripts configuration](#style-script-config) below. |
|
||||
| `scripts` | An object containing JavaScript script files to add to the global context of the project. The scripts are loaded exactly as if you had added them in a `<script>` tag inside `index.html`. See more in [Styles and scripts configuration](#style-script-config) below. |
|
||||
| `budgets` | Default size-budget type and threshholds for all or parts of your application. You can configure the builder to report a warning or an error when the output reaches or exceeds a threshold size. See [Configure size budgets](guide/build#configure-size-budgets). (Not available in `test` section.) |
|
||||
| `budgets` | Default size-budget type and thresholds for all or parts of your application. You can configure the builder to report a warning or an error when the output reaches or exceeds a threshold size. See [Configure size budgets](guide/build#configure-size-budgets). (Not available in `test` section.) |
|
||||
| `fileReplacements` | An object containing files and their compile-time replacements. See more in [Configure target-specific file replacements](guide/build#configure-target-specific-file-replacements).|
|
||||
|
||||
{@a complex-config}
|
||||
@@ -330,7 +330,7 @@ You can mix simple and complex file references for styles and scripts.
|
||||
|
||||
#### Style preprocessor options
|
||||
|
||||
In Sass and Stylus you can make use of the `includePaths` functionality for both component and global styles, which allows you to add extra base paths that will be checked for imports.
|
||||
In Sass you can make use of the `includePaths` functionality for both component and global styles, which allows you to add extra base paths that will be checked for imports.
|
||||
|
||||
To add paths, use the `stylePreprocessorOptions` option:
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
@@ -459,6 +459,13 @@
|
||||
"groups": ["Angular"],
|
||||
"lead": "igorminar"
|
||||
},
|
||||
"josmar-crwdstffng": {
|
||||
"name": "Joe Martin",
|
||||
"picture": "josephmmartin.jpg",
|
||||
"bio": "Joe is a technical writer working on the Angular docs.",
|
||||
"groups": ["Angular"],
|
||||
"lead": "aikidave"
|
||||
},
|
||||
"jschwarty": {
|
||||
"name": "Justin Schwartzenberger",
|
||||
"picture": "justinschwartzenberger.jpg",
|
||||
|
||||
@@ -49,6 +49,11 @@
|
||||
"desc": "Add API Based CMS to your Angular app",
|
||||
"url": "https://github.com/ButterCMS/buttercms-angular-tutorial",
|
||||
"title": "API Based CMS with Butter"
|
||||
},
|
||||
"angular-community-meetup": {
|
||||
"desc": "Come learn technical skills and network at this monthly, multi-series, multi-event, multi-timezone online meetup.",
|
||||
"url": "https://ngxp.show",
|
||||
"title": "Angular Community Meetup"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -90,6 +95,12 @@
|
||||
"logo": "",
|
||||
"title": "NgRuAir",
|
||||
"url": "https://github.com/ngRuAir/ngruair"
|
||||
},
|
||||
"ngxp": {
|
||||
"desc": "Weekly technical-adjacent podcast by Brooke Avery & Erik Slack.on't just code in Angular, come enjoy the Angular Experience!",
|
||||
"logo": "",
|
||||
"title": "Angular Experience (NgXP)",
|
||||
"url": "https://ngxp.show"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
"build-local": "yarn ~~build",
|
||||
"prebuild-local-ci": "yarn setup-local-ci",
|
||||
"build-local-ci": "yarn ~~build --progress=false",
|
||||
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js a57976b98",
|
||||
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js 7c2d76d9e",
|
||||
"lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint && yarn tools-lint",
|
||||
"test": "yarn check-env && ng test",
|
||||
"pree2e": "yarn check-env && yarn update-webdriver",
|
||||
|
||||
@@ -149,7 +149,7 @@ export class DocViewerComponent implements OnDestroy {
|
||||
this.setNoIndex(true);
|
||||
|
||||
// TODO(gkalpak): Remove this once gathering debug info is no longer needed.
|
||||
if (/loading chunk \d+ failed/i.test(errorMessage)) {
|
||||
if (/loading chunk \S+ failed/i.test(errorMessage)) {
|
||||
// Print some info to help with debugging.
|
||||
// (There is no reason to wait for this async call to complete before continuing.)
|
||||
printSwDebugInfo();
|
||||
|
||||
@@ -86,7 +86,7 @@ The file is expected to contain a JSON object with zero or more of the following
|
||||
"cmd": "yarn",
|
||||
"args": [
|
||||
"e2e",
|
||||
"--prod",
|
||||
"--configuration=production",
|
||||
"--protractor-config=e2e/protractor-puppeteer.conf.js",
|
||||
"--no-webdriver-update",
|
||||
"--port={PORT}"
|
||||
|
||||
@@ -266,7 +266,7 @@ function runE2eTestsCLI(appDir, outputFile, bufferOutput, port) {
|
||||
cmd: 'yarn',
|
||||
args: [
|
||||
'e2e',
|
||||
'--prod',
|
||||
'--configuration=production',
|
||||
'--protractor-config=e2e/protractor-puppeteer.conf.js',
|
||||
'--no-webdriver-update',
|
||||
'--port={PORT}',
|
||||
|
||||
@@ -7,47 +7,48 @@
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~12.0.0",
|
||||
"@angular/common": "~12.0.0",
|
||||
"@angular/compiler": "~12.0.0",
|
||||
"@angular/core": "~12.0.0",
|
||||
"@angular/forms": "~12.0.0",
|
||||
"@angular/platform-browser": "~12.0.0",
|
||||
"@angular/platform-browser-dynamic": "~12.0.0",
|
||||
"@angular/router": "~12.0.0",
|
||||
"@angular/animations": "~12.1.0-",
|
||||
"@angular/common": "~12.1.0-",
|
||||
"@angular/compiler": "~12.1.0-",
|
||||
"@angular/core": "~12.1.0-",
|
||||
"@angular/forms": "~12.1.0-",
|
||||
"@angular/platform-browser": "~12.1.0-",
|
||||
"@angular/platform-browser-dynamic": "~12.1.0-",
|
||||
"@angular/router": "~12.1.0-",
|
||||
"angular": "1.8.0",
|
||||
"angular-in-memory-web-api": "~0.11.0",
|
||||
"angular-route": "1.8.0",
|
||||
"rxjs": "~6.6.0",
|
||||
"tslib": "^2.0.0",
|
||||
"tslib": "^2.2.0",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~12.0.0",
|
||||
"@angular/cli": "~12.0.0",
|
||||
"@angular/compiler-cli": "~12.0.0",
|
||||
"@angular-devkit/build-angular": "~12.1.3",
|
||||
"@angular/cli": "~12.1.3",
|
||||
"@angular/compiler-cli": "~12.1.0-",
|
||||
"@types/angular": "1.7.3",
|
||||
"@types/angular-route": "1.7.1",
|
||||
"@types/jasmine": "~3.6.0",
|
||||
"@types/jasmine": "~3.8.0",
|
||||
"@types/node": "^12.11.1",
|
||||
"codelyzer": "^6.0.0",
|
||||
"jasmine-core": "~3.7.0",
|
||||
"jasmine-marbles": "~0.6.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"jasmine-core": "~3.8.0",
|
||||
"jasmine-marbles": "~0.8.3",
|
||||
"jasmine-spec-reporter": "~7.0.0",
|
||||
"karma": "~6.3.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.0.3",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"karma-jasmine-html-reporter": "~1.7.0",
|
||||
"protractor": "~7.0.0",
|
||||
"ts-node": "~8.3.0",
|
||||
"ts-node": "~10.1.0",
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "~4.2.3"
|
||||
"typescript": "~4.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,29 +29,10 @@
|
||||
"styles": [
|
||||
"src/styles.css"
|
||||
],
|
||||
"scripts": [],
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"buildOptimizer": false,
|
||||
"sourceMap": true,
|
||||
"optimization": false,
|
||||
"namedChunks": true
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"namedChunks": false,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
@@ -63,20 +44,37 @@
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "4kb"
|
||||
}
|
||||
]
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "angular.io-example:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "angular.io-example:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "angular.io-example:build:development"
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
|
||||
@@ -7,43 +7,44 @@
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~12.0.0",
|
||||
"@angular/common": "~12.0.0",
|
||||
"@angular/compiler": "~12.0.0",
|
||||
"@angular/core": "~12.0.0",
|
||||
"@angular/forms": "~12.0.0",
|
||||
"@angular/platform-browser": "~12.0.0",
|
||||
"@angular/platform-browser-dynamic": "~12.0.0",
|
||||
"@angular/router": "~12.0.0",
|
||||
"@angular/animations": "~12.1.0-",
|
||||
"@angular/common": "~12.1.0-",
|
||||
"@angular/compiler": "~12.1.0-",
|
||||
"@angular/core": "~12.1.0-",
|
||||
"@angular/forms": "~12.1.0-",
|
||||
"@angular/platform-browser": "~12.1.0-",
|
||||
"@angular/platform-browser-dynamic": "~12.1.0-",
|
||||
"@angular/router": "~12.1.0-",
|
||||
"angular-in-memory-web-api": "~0.11.0",
|
||||
"rxjs": "~6.6.0",
|
||||
"tslib": "^2.0.0",
|
||||
"tslib": "^2.2.0",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~12.0.0",
|
||||
"@angular/cli": "~12.0.0",
|
||||
"@angular/compiler-cli": "~12.0.0",
|
||||
"@types/jasmine": "~3.6.0",
|
||||
"@angular-devkit/build-angular": "~12.1.3",
|
||||
"@angular/cli": "~12.1.3",
|
||||
"@angular/compiler-cli": "~12.1.0-",
|
||||
"@types/jasmine": "~3.8.0",
|
||||
"@types/node": "^12.11.1",
|
||||
"codelyzer": "^6.0.0",
|
||||
"jasmine-core": "~3.7.0",
|
||||
"jasmine-marbles": "~0.6.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"jasmine-core": "~3.8.0",
|
||||
"jasmine-marbles": "~0.8.3",
|
||||
"jasmine-spec-reporter": "~7.0.0",
|
||||
"karma": "~6.3.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.0.3",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"karma-jasmine-html-reporter": "~1.7.0",
|
||||
"protractor": "~7.0.0",
|
||||
"ts-node": "~8.3.0",
|
||||
"ts-node": "~10.1.0",
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "~4.2.3"
|
||||
"typescript": "~4.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// This file can be replaced during build by using the `fileReplacements` array.
|
||||
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
|
||||
// `ng build` replaces `environment.ts` with `environment.prod.ts`.
|
||||
// The list of file replacements can be found in `angular.json`.
|
||||
|
||||
export const environment = {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"target": "es2015",
|
||||
"target": "es2017",
|
||||
"module": "es2020",
|
||||
"lib": [
|
||||
"es2018",
|
||||
|
||||
@@ -7,45 +7,46 @@
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~12.0.0",
|
||||
"@angular/common": "~12.0.0",
|
||||
"@angular/compiler": "~12.0.0",
|
||||
"@angular/core": "~12.0.0",
|
||||
"@angular/elements": "~12.0.0",
|
||||
"@angular/forms": "~12.0.0",
|
||||
"@angular/platform-browser": "~12.0.0",
|
||||
"@angular/platform-browser-dynamic": "~12.0.0",
|
||||
"@angular/router": "~12.0.0",
|
||||
"@angular/animations": "~12.1.0-",
|
||||
"@angular/common": "~12.1.0-",
|
||||
"@angular/compiler": "~12.1.0-",
|
||||
"@angular/core": "~12.1.0-",
|
||||
"@angular/elements": "~12.1.0-",
|
||||
"@angular/forms": "~12.1.0-",
|
||||
"@angular/platform-browser": "~12.1.0-",
|
||||
"@angular/platform-browser-dynamic": "~12.1.0-",
|
||||
"@angular/router": "~12.1.0-",
|
||||
"@webcomponents/custom-elements": "^1.4.2",
|
||||
"angular-in-memory-web-api": "~0.11.0",
|
||||
"rxjs": "~6.6.0",
|
||||
"tslib": "^2.0.0",
|
||||
"tslib": "^2.2.0",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~12.0.0",
|
||||
"@angular/cli": "~12.0.0",
|
||||
"@angular/compiler-cli": "~12.0.0",
|
||||
"@types/jasmine": "~3.6.0",
|
||||
"@angular-devkit/build-angular": "~12.1.3",
|
||||
"@angular/cli": "~12.1.3",
|
||||
"@angular/compiler-cli": "~12.1.0-",
|
||||
"@types/jasmine": "~3.8.0",
|
||||
"@types/node": "^12.11.1",
|
||||
"codelyzer": "^6.0.0",
|
||||
"jasmine-core": "~3.7.0",
|
||||
"jasmine-marbles": "~0.6.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"jasmine-core": "~3.8.0",
|
||||
"jasmine-marbles": "~0.8.3",
|
||||
"jasmine-spec-reporter": "~7.0.0",
|
||||
"karma": "~6.3.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.0.3",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"karma-jasmine-html-reporter": "~1.7.0",
|
||||
"protractor": "~7.0.0",
|
||||
"ts-node": "~8.3.0",
|
||||
"ts-node": "~10.1.0",
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "~4.2.3"
|
||||
"typescript": "~4.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"aot": true,
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
@@ -41,19 +40,6 @@
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"namedChunks": false,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
@@ -65,28 +51,45 @@
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "4kb"
|
||||
}
|
||||
]
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
},
|
||||
"fr": {
|
||||
"localize": [
|
||||
"fr"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "angular.io-example:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "angular.io-example:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "angular.io-example:build:development"
|
||||
},
|
||||
"fr": {
|
||||
"browserTarget": "angular.io-example:build:fr"
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"start:fr": "ng serve --configuration=fr",
|
||||
"build": "ng build",
|
||||
"build:fr": "ng build --configuration=production-fr",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e",
|
||||
@@ -16,38 +17,38 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~12.0.0",
|
||||
"@angular/common": "~12.0.0",
|
||||
"@angular/compiler": "~12.0.0",
|
||||
"@angular/core": "~12.0.0",
|
||||
"@angular/forms": "~12.0.0",
|
||||
"@angular/localize": "~12.0.0",
|
||||
"@angular/platform-browser": "~12.0.0",
|
||||
"@angular/platform-browser-dynamic": "~12.0.0",
|
||||
"@angular/router": "~12.0.0",
|
||||
"@angular/animations": "~12.1.0-",
|
||||
"@angular/common": "~12.1.0-",
|
||||
"@angular/compiler": "~12.1.0-",
|
||||
"@angular/core": "~12.1.0-",
|
||||
"@angular/forms": "~12.1.0-",
|
||||
"@angular/localize": "~12.1.0-",
|
||||
"@angular/platform-browser": "~12.1.0-",
|
||||
"@angular/platform-browser-dynamic": "~12.1.0-",
|
||||
"@angular/router": "~12.1.0-",
|
||||
"angular-in-memory-web-api": "~0.11.0",
|
||||
"rxjs": "~6.6.0",
|
||||
"tslib": "^2.0.0",
|
||||
"tslib": "^2.2.0",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~12.0.0",
|
||||
"@angular/cli": "~12.0.0",
|
||||
"@angular/compiler-cli": "~12.0.0",
|
||||
"@types/jasmine": "~3.6.0",
|
||||
"@angular-devkit/build-angular": "~12.1.3",
|
||||
"@angular/cli": "~12.1.3",
|
||||
"@angular/compiler-cli": "~12.1.0-",
|
||||
"@types/jasmine": "~3.8.0",
|
||||
"@types/node": "^12.11.1",
|
||||
"codelyzer": "^6.0.0",
|
||||
"jasmine-core": "~3.7.0",
|
||||
"jasmine-marbles": "~0.6.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"jasmine-core": "~3.8.0",
|
||||
"jasmine-marbles": "~0.8.3",
|
||||
"jasmine-spec-reporter": "~7.0.0",
|
||||
"karma": "~6.3.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.0.3",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"karma-jasmine-html-reporter": "~1.7.0",
|
||||
"protractor": "~7.0.0",
|
||||
"ts-node": "~8.3.0",
|
||||
"ts-node": "~10.1.0",
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "~4.2.3"
|
||||
"typescript": "~4.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"aot": true,
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
@@ -34,19 +33,6 @@
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"namedChunks": false,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
@@ -58,20 +44,37 @@
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "4kb"
|
||||
}
|
||||
]
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "angular.io-example:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "angular.io-example:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "angular.io-example:build:development"
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"aot": true,
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
@@ -30,24 +29,12 @@
|
||||
"styles": [
|
||||
"src/styles.css"
|
||||
],
|
||||
"scripts": []
|
||||
"scripts": [],
|
||||
"serviceWorker": true,
|
||||
"ngswConfigPath": "ngsw-config.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"namedChunks": false,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"serviceWorker": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
@@ -59,20 +46,37 @@
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "4kb"
|
||||
}
|
||||
]
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "angular.io-example:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "angular.io-example:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "angular.io-example:build:development"
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
|
||||
@@ -7,44 +7,45 @@
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~12.0.0",
|
||||
"@angular/common": "~12.0.0",
|
||||
"@angular/compiler": "~12.0.0",
|
||||
"@angular/core": "~12.0.0",
|
||||
"@angular/forms": "~12.0.0",
|
||||
"@angular/platform-browser": "~12.0.0",
|
||||
"@angular/platform-browser-dynamic": "~12.0.0",
|
||||
"@angular/router": "~12.0.0",
|
||||
"@angular/service-worker": "~12.0.0",
|
||||
"@angular/animations": "~12.1.0-",
|
||||
"@angular/common": "~12.1.0-",
|
||||
"@angular/compiler": "~12.1.0-",
|
||||
"@angular/core": "~12.1.0-",
|
||||
"@angular/forms": "~12.1.0-",
|
||||
"@angular/platform-browser": "~12.1.0-",
|
||||
"@angular/platform-browser-dynamic": "~12.1.0-",
|
||||
"@angular/router": "~12.1.0-",
|
||||
"@angular/service-worker": "~12.1.0-",
|
||||
"angular-in-memory-web-api": "~0.11.0",
|
||||
"rxjs": "~6.6.0",
|
||||
"tslib": "^2.0.0",
|
||||
"tslib": "^2.2.0",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~12.0.0",
|
||||
"@angular/cli": "~12.0.0",
|
||||
"@angular/compiler-cli": "~12.0.0",
|
||||
"@types/jasmine": "~3.6.0",
|
||||
"@angular-devkit/build-angular": "~12.1.3",
|
||||
"@angular/cli": "~12.1.3",
|
||||
"@angular/compiler-cli": "~12.1.0-",
|
||||
"@types/jasmine": "~3.8.0",
|
||||
"@types/node": "^12.11.1",
|
||||
"codelyzer": "^6.0.0",
|
||||
"jasmine-core": "~3.7.0",
|
||||
"jasmine-marbles": "~0.6.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"jasmine-core": "~3.8.0",
|
||||
"jasmine-marbles": "~0.8.3",
|
||||
"jasmine-spec-reporter": "~7.0.0",
|
||||
"karma": "~6.3.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.0.3",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"karma-jasmine-html-reporter": "~1.7.0",
|
||||
"protractor": "~7.0.0",
|
||||
"ts-node": "~8.3.0",
|
||||
"ts-node": "~10.1.0",
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "~4.2.3"
|
||||
"typescript": "~4.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,36 +26,36 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~12.0.0",
|
||||
"@angular/common": "~12.0.0",
|
||||
"@angular/compiler": "~12.0.0",
|
||||
"@angular/core": "~12.0.0",
|
||||
"@angular/forms": "~12.0.0",
|
||||
"@angular/platform-browser": "~12.0.0",
|
||||
"@angular/platform-browser-dynamic": "~12.0.0",
|
||||
"@angular/router": "~12.0.0",
|
||||
"@angular/upgrade": "~12.0.0",
|
||||
"@angular/animations": "~12.1.0-",
|
||||
"@angular/common": "~12.1.0-",
|
||||
"@angular/compiler": "~12.1.0-",
|
||||
"@angular/core": "~12.1.0-",
|
||||
"@angular/forms": "~12.1.0-",
|
||||
"@angular/platform-browser": "~12.1.0-",
|
||||
"@angular/platform-browser-dynamic": "~12.1.0-",
|
||||
"@angular/router": "~12.1.0-",
|
||||
"@angular/upgrade": "~12.1.0-",
|
||||
"core-js": "^2.5.4",
|
||||
"rxjs": "~6.6.0",
|
||||
"tslib": "^2.0.0",
|
||||
"tslib": "^2.2.0",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/compiler-cli": "~12.0.0",
|
||||
"@angular/compiler-cli": "~12.1.0-",
|
||||
"@types/angular": "1.7.3",
|
||||
"@types/angular-animate": "1.5.10",
|
||||
"@types/angular-mocks": "1.7.0",
|
||||
"@types/angular-resource": "1.5.16",
|
||||
"@types/angular-route": "1.7.1",
|
||||
"@types/jasmine": "~3.6.0",
|
||||
"@types/jasmine": "~3.8.0",
|
||||
"@types/node": "^12.11.1",
|
||||
"concurrently": "^5.0.1",
|
||||
"http-server": "^0.12.0",
|
||||
"jasmine-core": "~3.7.0",
|
||||
"jasmine-core": "~3.8.0",
|
||||
"karma": "~6.3.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"karma-jasmine-html-reporter": "~1.7.0",
|
||||
"lite-server": "^2.6.1",
|
||||
"protractor": "~7.0.0",
|
||||
"rollup": "^1.1.0",
|
||||
@@ -63,6 +63,6 @@
|
||||
"rollup-plugin-node-resolve": "^4.0.0",
|
||||
"rollup-plugin-terser": "^5.3.0",
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "~4.2.3"
|
||||
"typescript": "~4.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"aot": true,
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
@@ -35,19 +34,6 @@
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"namedChunks": false,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
@@ -59,20 +45,37 @@
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "4kb"
|
||||
}
|
||||
]
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "angular.io-example:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "angular.io-example:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "angular.io-example:build:development"
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"aot": true,
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
@@ -34,19 +33,6 @@
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"namedChunks": false,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
@@ -58,20 +44,37 @@
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "4kb"
|
||||
}
|
||||
]
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "angular.io-example:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "angular.io-example:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "angular.io-example:build:development"
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
@@ -136,37 +139,48 @@
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"sourceMap": false,
|
||||
"optimization": true
|
||||
]
|
||||
},
|
||||
"development": {
|
||||
"optimization": false,
|
||||
"sourceMap": true,
|
||||
"extractLicenses": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve-ssr": {
|
||||
"builder": "@nguniversal/builders:ssr-dev-server",
|
||||
"options": {
|
||||
"browserTarget": "angular.io-example:build",
|
||||
"serverTarget": "angular.io-example:server"
|
||||
},
|
||||
"configurations": {
|
||||
"development": {
|
||||
"browserTarget": "angular.io-example:build:development",
|
||||
"serverTarget": "angular.io-example:server:development"
|
||||
},
|
||||
"production": {
|
||||
"browserTarget": "angular.io-example:build:production",
|
||||
"serverTarget": "angular.io-example:server:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"prerender": {
|
||||
"builder": "@nguniversal/builders:prerender",
|
||||
"options": {
|
||||
"browserTarget": "angular.io-example:build:production",
|
||||
"serverTarget": "angular.io-example:server:production",
|
||||
"routes": [
|
||||
"/"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {}
|
||||
}
|
||||
"production": {
|
||||
"browserTarget": "angular.io-example:build:production",
|
||||
"serverTarget": "angular.io-example:server:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "angular.io-example:build:development",
|
||||
"serverTarget": "angular.io-example:server:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,52 +7,53 @@
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e",
|
||||
"dev:ssr": "ng run angular.io-example:serve-ssr",
|
||||
"serve:ssr": "node dist/server/main.js",
|
||||
"build:ssr": "ng build --prod && ng run angular.io-example:server:production",
|
||||
"build:ssr": "ng build && ng run angular.io-example:server",
|
||||
"prerender": "ng run angular.io-example:prerender"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~12.0.0",
|
||||
"@angular/common": "~12.0.0",
|
||||
"@angular/compiler": "~12.0.0",
|
||||
"@angular/core": "~12.0.0",
|
||||
"@angular/forms": "~12.0.0",
|
||||
"@angular/platform-browser": "~12.0.0",
|
||||
"@angular/platform-browser-dynamic": "~12.0.0",
|
||||
"@angular/platform-server": "~12.0.0",
|
||||
"@angular/router": "~12.0.0",
|
||||
"@nguniversal/express-engine": "^12.0.0",
|
||||
"@angular/animations": "~12.1.0-",
|
||||
"@angular/common": "~12.1.0-",
|
||||
"@angular/compiler": "~12.1.0-",
|
||||
"@angular/core": "~12.1.0-",
|
||||
"@angular/forms": "~12.1.0-",
|
||||
"@angular/platform-browser": "~12.1.0-",
|
||||
"@angular/platform-browser-dynamic": "~12.1.0-",
|
||||
"@angular/platform-server": "~12.1.0-",
|
||||
"@angular/router": "~12.1.0-",
|
||||
"@nguniversal/express-engine": "~12.1.0",
|
||||
"angular-in-memory-web-api": "~0.11.0",
|
||||
"express": "^4.15.2",
|
||||
"rxjs": "~6.6.0",
|
||||
"tslib": "^2.0.0",
|
||||
"tslib": "^2.2.0",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~12.0.0",
|
||||
"@angular/cli": "~12.0.0",
|
||||
"@angular/compiler-cli": "~12.0.0",
|
||||
"@nguniversal/builders": "^12.0.0",
|
||||
"@angular-devkit/build-angular": "~12.1.3",
|
||||
"@angular/cli": "~12.1.3",
|
||||
"@angular/compiler-cli": "~12.1.0-",
|
||||
"@nguniversal/builders": "~12.1.0",
|
||||
"@types/express": "^4.17.8",
|
||||
"@types/jasmine": "~3.6.0",
|
||||
"@types/jasmine": "~3.8.0",
|
||||
"@types/node": "^12.11.1",
|
||||
"codelyzer": "^6.0.0",
|
||||
"jasmine-core": "~3.7.0",
|
||||
"jasmine-marbles": "~0.6.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"jasmine-core": "~3.8.0",
|
||||
"jasmine-marbles": "~0.8.3",
|
||||
"jasmine-spec-reporter": "~7.0.0",
|
||||
"karma": "~6.3.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.0.3",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"karma-jasmine-html-reporter": "~1.7.0",
|
||||
"protractor": "~7.0.0",
|
||||
"ts-node": "~8.3.0",
|
||||
"ts-node": "~10.1.0",
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "~4.2.3"
|
||||
"typescript": "~4.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,20 +21,20 @@
|
||||
"license": "MIT",
|
||||
"repository": {},
|
||||
"dependencies": {
|
||||
"@angular/animations": "~12.0.0",
|
||||
"@angular/common": "~12.0.0",
|
||||
"@angular/compiler": "~12.0.0",
|
||||
"@angular/core": "~12.0.0",
|
||||
"@angular/elements": "~12.0.0",
|
||||
"@angular/forms": "~12.0.0",
|
||||
"@angular/localize": "~12.0.0",
|
||||
"@angular/platform-browser": "~12.0.0",
|
||||
"@angular/platform-browser-dynamic": "~12.0.0",
|
||||
"@angular/platform-server": "~12.0.0",
|
||||
"@angular/router": "~12.0.0",
|
||||
"@angular/service-worker": "~12.0.0",
|
||||
"@angular/upgrade": "~12.0.0",
|
||||
"@nguniversal/express-engine": "^12.0.0",
|
||||
"@angular/animations": "~12.1.0-",
|
||||
"@angular/common": "~12.1.0-",
|
||||
"@angular/compiler": "~12.1.0-",
|
||||
"@angular/core": "~12.1.0-",
|
||||
"@angular/elements": "~12.1.0-",
|
||||
"@angular/forms": "~12.1.0-",
|
||||
"@angular/localize": "~12.1.0-",
|
||||
"@angular/platform-browser": "~12.1.0-",
|
||||
"@angular/platform-browser-dynamic": "~12.1.0-",
|
||||
"@angular/platform-server": "~12.1.0-",
|
||||
"@angular/router": "~12.1.0-",
|
||||
"@angular/service-worker": "~12.1.0-",
|
||||
"@angular/upgrade": "~12.1.0-",
|
||||
"@nguniversal/express-engine": "~12.1.0",
|
||||
"@webcomponents/custom-elements": "^1.4.2",
|
||||
"angular": "1.8.0",
|
||||
"angular-in-memory-web-api": "~0.11.0",
|
||||
@@ -43,35 +43,35 @@
|
||||
"express": "^4.15.2",
|
||||
"rxjs": "~6.6.0",
|
||||
"systemjs": "0.19.39",
|
||||
"tslib": "^2.0.0",
|
||||
"tslib": "^2.2.0",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~12.0.0",
|
||||
"@angular/cli": "~12.0.0",
|
||||
"@angular/compiler-cli": "~12.0.0",
|
||||
"@nguniversal/builders": "^12.0.0",
|
||||
"@angular-devkit/build-angular": "~12.1.3",
|
||||
"@angular/cli": "~12.1.3",
|
||||
"@angular/compiler-cli": "~12.1.0-",
|
||||
"@nguniversal/builders": "~12.1.0",
|
||||
"@types/angular": "1.7.3",
|
||||
"@types/angular-animate": "1.5.10",
|
||||
"@types/angular-mocks": "1.7.0",
|
||||
"@types/angular-resource": "1.5.16",
|
||||
"@types/angular-route": "1.7.1",
|
||||
"@types/express": "^4.17.8",
|
||||
"@types/jasmine": "~3.6.0",
|
||||
"@types/jasmine": "~3.8.0",
|
||||
"@types/jquery": "3.5.1",
|
||||
"@types/node": "^12.11.1",
|
||||
"canonical-path": "1.0.0",
|
||||
"codelyzer": "^6.0.0",
|
||||
"concurrently": "^5.0.1",
|
||||
"http-server": "^0.12.0",
|
||||
"jasmine-core": "~3.7.0",
|
||||
"jasmine-marbles": "~0.6.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"jasmine-core": "~3.8.0",
|
||||
"jasmine-marbles": "~0.8.3",
|
||||
"jasmine-spec-reporter": "~7.0.0",
|
||||
"karma": "~6.3.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.0.3",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"karma-jasmine-html-reporter": "~1.7.0",
|
||||
"lite-server": "^2.6.1",
|
||||
"lodash": "^4.16.2",
|
||||
"protractor": "~7.0.0",
|
||||
@@ -82,8 +82,8 @@
|
||||
"rollup-plugin-node-resolve": "^4.0.0",
|
||||
"rollup-plugin-terser": "^5.3.0",
|
||||
"source-map-explorer": "^1.3.2",
|
||||
"ts-node": "~8.3.0",
|
||||
"ts-node": "~10.1.0",
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "~4.2.3"
|
||||
"typescript": "~4.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
// see boilerplate/tsconfig.json for the tsconfig used in examples
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"target": "es2017",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": ["es2015", "dom"],
|
||||
"lib": ["es2018", "dom"],
|
||||
"noImplicitAny": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"typeRoots": [
|
||||
|
||||
+1494
-1358
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,27 @@
|
||||
"""Implementation of the `browser_archive` rule."""
|
||||
|
||||
def _browser_archive_impl(ctx):
|
||||
ctx.report_progress("Downloading browser archive from: %s" % ctx.attr.url)
|
||||
ctx.download_and_extract(
|
||||
url = ctx.attr.url,
|
||||
sha256 = ctx.attr.sha256,
|
||||
)
|
||||
url = ctx.attr.url
|
||||
sha256 = ctx.attr.sha256
|
||||
|
||||
# If the URL resolves to a `.dmg` file, then we need to convert the file
|
||||
# to a zip so that we can extract the actual binaries. We use the `convert_dmg`
|
||||
# script provided by the webtesting Bazel rules.
|
||||
if url.endswith(".dmg"):
|
||||
download_file_name = "_download_file_%s.dmg" % ctx.attr.name
|
||||
result_zip_name = "_converted_file_%s.zip" % ctx.attr.name
|
||||
|
||||
ctx.download(url, download_file_name, sha256)
|
||||
ctx.execute([ctx.path(Label("@io_bazel_rules_webtesting//web/internal:convert_dmg.sh")), download_file_name, result_zip_name])
|
||||
ctx.extract(result_zip_name)
|
||||
|
||||
ctx.delete(result_zip_name)
|
||||
ctx.delete(download_file_name)
|
||||
else:
|
||||
ctx.download_and_extract(
|
||||
url = url,
|
||||
sha256 = sha256,
|
||||
)
|
||||
|
||||
# The browser archive has been downloaded and extracted. We now generate a repository
|
||||
# `BUILD.bazel` file that exposes the archive files, together with the specified
|
||||
|
||||
+54
-27
@@ -3427,7 +3427,7 @@ function checkOutPullRequestLocally(prNumber, githubToken, opts = {}) {
|
||||
// never accidentally override upstream changes that have been pushed in the meanwhile.
|
||||
// See:
|
||||
// https://git-scm.com/docs/git-push#Documentation/git-push.txt---force-with-leaseltrefnamegtltexpectgt
|
||||
/** Flag for a force push with leage back to upstream. */
|
||||
/** Flag for a force push with lease back to upstream. */
|
||||
const forceWithLeaseFlag = `--force-with-lease=${headRefName}:${pr.headRefOid}`;
|
||||
// If the PR does not allow maintainers to modify it, exit as the rebased PR cannot
|
||||
// be pushed up.
|
||||
@@ -3541,7 +3541,7 @@ function discoverNewConflictsForPr(newPrNumber, updatedAfter) {
|
||||
/* PRs which were found to be conflicting. */
|
||||
const conflicts = [];
|
||||
info(`Requesting pending PRs from Github`);
|
||||
/** List of PRs from github currently known as mergable. */
|
||||
/** List of PRs from github currently known as mergeable. */
|
||||
const allPendingPRs = (yield getPendingPrs(PR_SCHEMA$1, git)).map(processPr);
|
||||
/** The PR which is being checked against. */
|
||||
const requestedPr = allPendingPRs.find(pr => pr.number === newPrNumber);
|
||||
@@ -3554,7 +3554,7 @@ function discoverNewConflictsForPr(newPrNumber, updatedAfter) {
|
||||
return (
|
||||
// PRs being merged into the same target branch as the requested PR
|
||||
pr.baseRef.name === requestedPr.baseRef.name &&
|
||||
// PRs which either have not been processed or are determined as mergable by Github
|
||||
// PRs which either have not been processed or are determined as mergeable by Github
|
||||
pr.mergeable !== 'CONFLICTING' &&
|
||||
// PRs updated after the provided date
|
||||
pr.updatedAt >= updatedAfter);
|
||||
@@ -7746,8 +7746,13 @@ function buildEnvStamp(mode) {
|
||||
}
|
||||
/** Whether the repo has local changes. */
|
||||
function hasLocalChanges() {
|
||||
const git = GitClient.get();
|
||||
return git.hasUncommittedChanges();
|
||||
try {
|
||||
const git = GitClient.get();
|
||||
return git.hasUncommittedChanges();
|
||||
}
|
||||
catch (_a) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the versions for generated packages.
|
||||
@@ -7756,41 +7761,63 @@ function hasLocalChanges() {
|
||||
* In release mode, the version is based on the base package.json version.
|
||||
*/
|
||||
function getSCMVersions(mode) {
|
||||
const git = GitClient.get();
|
||||
if (mode === 'release') {
|
||||
const packageJsonPath = path.join(git.baseDir, 'package.json');
|
||||
const { version } = new semver.SemVer(require(packageJsonPath).version);
|
||||
const { version: experimentalVersion } = createExperimentalSemver(new semver.SemVer(version));
|
||||
return { version, experimentalVersion };
|
||||
try {
|
||||
const git = GitClient.get();
|
||||
if (mode === 'snapshot') {
|
||||
const localChanges = hasLocalChanges() ? '.with-local-changes' : '';
|
||||
const { stdout: rawVersion } = git.run(['describe', '--match', '*[0-9]*.[0-9]*.[0-9]*', '--abbrev=7', '--tags', 'HEAD']);
|
||||
const { version } = new semver.SemVer(rawVersion);
|
||||
const { version: experimentalVersion } = createExperimentalSemver(version);
|
||||
return {
|
||||
version: `${version.replace(/-([0-9]+)-g/, '+$1.sha-')}${localChanges}`,
|
||||
experimentalVersion: `${experimentalVersion.replace(/-([0-9]+)-g/, '+$1.sha-')}${localChanges}`,
|
||||
};
|
||||
}
|
||||
else {
|
||||
const packageJsonPath = path.join(git.baseDir, 'package.json');
|
||||
const { version } = new semver.SemVer(require(packageJsonPath).version);
|
||||
const { version: experimentalVersion } = createExperimentalSemver(new semver.SemVer(version));
|
||||
return { version, experimentalVersion };
|
||||
}
|
||||
}
|
||||
if (mode === 'snapshot') {
|
||||
const localChanges = hasLocalChanges() ? '.with-local-changes' : '';
|
||||
const { stdout: rawVersion } = git.run(['describe', '--match', '*[0-9]*.[0-9]*.[0-9]*', '--abbrev=7', '--tags', 'HEAD~100']);
|
||||
const { version } = new semver.SemVer(rawVersion);
|
||||
const { version: experimentalVersion } = createExperimentalSemver(version);
|
||||
catch (_a) {
|
||||
return {
|
||||
version: `${version.replace(/-([0-9]+)-g/, '+$1.sha-')}${localChanges}`,
|
||||
experimentalVersion: `${experimentalVersion.replace(/-([0-9]+)-g/, '+$1.sha-')}${localChanges}`,
|
||||
version: '',
|
||||
experimentalVersion: '',
|
||||
};
|
||||
}
|
||||
throw Error('No environment stamp mode was provided.');
|
||||
}
|
||||
/** Get the current branch or revision of HEAD. */
|
||||
function getCurrentBranchOrRevision() {
|
||||
const git = GitClient.get();
|
||||
return git.getCurrentBranchOrRevision();
|
||||
try {
|
||||
const git = GitClient.get();
|
||||
return git.getCurrentBranchOrRevision();
|
||||
}
|
||||
catch (_a) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
/** Get the currently checked out branch. */
|
||||
function getCurrentBranch() {
|
||||
const git = GitClient.get();
|
||||
return git.run(['symbolic-ref', '--short', 'HEAD']).stdout.trim();
|
||||
try {
|
||||
const git = GitClient.get();
|
||||
return git.run(['symbolic-ref', '--short', 'HEAD']).stdout.trim();
|
||||
}
|
||||
catch (_a) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
/** Get the current git user based on the git config. */
|
||||
function getCurrentGitUser() {
|
||||
const git = GitClient.get();
|
||||
let userName = git.runGraceful(['config', 'user.name']).stdout.trim() || 'Unknown User';
|
||||
let userEmail = git.runGraceful(['config', 'user.email']).stdout.trim() || 'unknown_email';
|
||||
return `${userName} <${userEmail}>`;
|
||||
try {
|
||||
const git = GitClient.get();
|
||||
let userName = git.runGraceful(['config', 'user.name']).stdout.trim() || 'Unknown User';
|
||||
let userEmail = git.runGraceful(['config', 'user.email']).stdout.trim() || 'unknown_email';
|
||||
return `${userName} <${userEmail}>`;
|
||||
}
|
||||
catch (_a) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -90,7 +90,7 @@ export async function checkOutPullRequestLocally(
|
||||
// never accidentally override upstream changes that have been pushed in the meanwhile.
|
||||
// See:
|
||||
// https://git-scm.com/docs/git-push#Documentation/git-push.txt---force-with-leaseltrefnamegtltexpectgt
|
||||
/** Flag for a force push with leage back to upstream. */
|
||||
/** Flag for a force push with lease back to upstream. */
|
||||
const forceWithLeaseFlag = `--force-with-lease=${headRefName}:${pr.headRefOid}`;
|
||||
|
||||
// If the PR does not allow maintainers to modify it, exit as the rebased PR cannot
|
||||
|
||||
@@ -70,7 +70,7 @@ export async function discoverNewConflictsForPr(newPrNumber: number, updatedAfte
|
||||
const conflicts: Array<PullRequest> = [];
|
||||
|
||||
info(`Requesting pending PRs from Github`);
|
||||
/** List of PRs from github currently known as mergable. */
|
||||
/** List of PRs from github currently known as mergeable. */
|
||||
const allPendingPRs = (await getPendingPrs(PR_SCHEMA, git)).map(processPr);
|
||||
/** The PR which is being checked against. */
|
||||
const requestedPr = allPendingPRs.find(pr => pr.number === newPrNumber);
|
||||
@@ -85,7 +85,7 @@ export async function discoverNewConflictsForPr(newPrNumber: number, updatedAfte
|
||||
return (
|
||||
// PRs being merged into the same target branch as the requested PR
|
||||
pr.baseRef.name === requestedPr.baseRef.name &&
|
||||
// PRs which either have not been processed or are determined as mergable by Github
|
||||
// PRs which either have not been processed or are determined as mergeable by Github
|
||||
pr.mergeable !== 'CONFLICTING' &&
|
||||
// PRs updated after the provided date
|
||||
pr.updatedAt >= updatedAfter);
|
||||
|
||||
@@ -37,8 +37,12 @@ export function buildEnvStamp(mode: EnvStampMode) {
|
||||
|
||||
/** Whether the repo has local changes. */
|
||||
function hasLocalChanges() {
|
||||
const git = GitClient.get();
|
||||
return git.hasUncommittedChanges();
|
||||
try {
|
||||
const git = GitClient.get();
|
||||
return git.hasUncommittedChanges();
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,44 +52,61 @@ function hasLocalChanges() {
|
||||
* In release mode, the version is based on the base package.json version.
|
||||
*/
|
||||
function getSCMVersions(mode: EnvStampMode): {version: string, experimentalVersion: string} {
|
||||
const git = GitClient.get();
|
||||
if (mode === 'release') {
|
||||
const packageJsonPath = join(git.baseDir, 'package.json');
|
||||
const {version} = new SemVer(require(packageJsonPath).version);
|
||||
const {version: experimentalVersion} = createExperimentalSemver(new SemVer(version));
|
||||
return {version, experimentalVersion};
|
||||
}
|
||||
if (mode === 'snapshot') {
|
||||
const localChanges = hasLocalChanges() ? '.with-local-changes' : '';
|
||||
const {stdout: rawVersion} = git.run(
|
||||
['describe', '--match', '*[0-9]*.[0-9]*.[0-9]*', '--abbrev=7', '--tags', 'HEAD~100']);
|
||||
const {version} = new SemVer(rawVersion);
|
||||
const {version: experimentalVersion} = createExperimentalSemver(version);
|
||||
try {
|
||||
const git = GitClient.get();
|
||||
if (mode === 'snapshot') {
|
||||
const localChanges = hasLocalChanges() ? '.with-local-changes' : '';
|
||||
const {stdout: rawVersion} =
|
||||
git.run(['describe', '--match', '*[0-9]*.[0-9]*.[0-9]*', '--abbrev=7', '--tags', 'HEAD']);
|
||||
const {version} = new SemVer(rawVersion);
|
||||
const {version: experimentalVersion} = createExperimentalSemver(version);
|
||||
return {
|
||||
version: `${version.replace(/-([0-9]+)-g/, '+$1.sha-')}${localChanges}`,
|
||||
experimentalVersion:
|
||||
`${experimentalVersion.replace(/-([0-9]+)-g/, '+$1.sha-')}${localChanges}`,
|
||||
};
|
||||
} else {
|
||||
const packageJsonPath = join(git.baseDir, 'package.json');
|
||||
const {version} = new SemVer(require(packageJsonPath).version);
|
||||
const {version: experimentalVersion} = createExperimentalSemver(new SemVer(version));
|
||||
return {version, experimentalVersion};
|
||||
}
|
||||
} catch {
|
||||
return {
|
||||
version: `${version.replace(/-([0-9]+)-g/, '+$1.sha-')}${localChanges}`,
|
||||
experimentalVersion:
|
||||
`${experimentalVersion.replace(/-([0-9]+)-g/, '+$1.sha-')}${localChanges}`,
|
||||
version: '',
|
||||
experimentalVersion: '',
|
||||
};
|
||||
}
|
||||
throw Error('No environment stamp mode was provided.');
|
||||
}
|
||||
|
||||
/** Get the current branch or revision of HEAD. */
|
||||
function getCurrentBranchOrRevision() {
|
||||
const git = GitClient.get();
|
||||
return git.getCurrentBranchOrRevision();
|
||||
try {
|
||||
const git = GitClient.get();
|
||||
return git.getCurrentBranchOrRevision();
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the currently checked out branch. */
|
||||
function getCurrentBranch() {
|
||||
const git = GitClient.get();
|
||||
return git.run(['symbolic-ref', '--short', 'HEAD']).stdout.trim();
|
||||
try {
|
||||
const git = GitClient.get();
|
||||
return git.run(['symbolic-ref', '--short', 'HEAD']).stdout.trim();
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the current git user based on the git config. */
|
||||
function getCurrentGitUser() {
|
||||
const git = GitClient.get();
|
||||
let userName = git.runGraceful(['config', 'user.name']).stdout.trim() || 'Unknown User';
|
||||
let userEmail = git.runGraceful(['config', 'user.email']).stdout.trim() || 'unknown_email';
|
||||
return `${userName} <${userEmail}>`;
|
||||
try {
|
||||
const git = GitClient.get();
|
||||
let userName = git.runGraceful(['config', 'user.name']).stdout.trim() || 'Unknown User';
|
||||
let userEmail = git.runGraceful(['config', 'user.email']).stdout.trim() || 'unknown_email';
|
||||
return `${userName} <${userEmail}>`;
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ export enum ErrorCode {
|
||||
INJECTABLE_DUPLICATE_PROV = 9001,
|
||||
INLINE_TCB_REQUIRED = 8900,
|
||||
INLINE_TYPE_CTOR_REQUIRED = 8901,
|
||||
INVALID_BANANA_IN_BOX = 8101,
|
||||
MISSING_PIPE = 8004,
|
||||
MISSING_REFERENCE_TARGET = 8003,
|
||||
NGMODULE_DECLARATION_NOT_UNIQUE = 6007,
|
||||
@@ -67,7 +68,6 @@ export enum ErrorCode {
|
||||
WRITE_TO_READ_ONLY_VARIABLE = 8005
|
||||
}
|
||||
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
|
||||
```
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"master": {
|
||||
"uncompressed": {
|
||||
"runtime-es2015": 1190,
|
||||
"main-es2015": 136546,
|
||||
"main-es2015": 137055,
|
||||
"polyfills-es2015": 37641
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ INTEGRATION_TESTS = {
|
||||
"service-worker-schema": {},
|
||||
"side-effects": {"tags": ["no-ivy-aot"]},
|
||||
"terser": {},
|
||||
"typings_test_rxjs7": {},
|
||||
"typings_test_ts41": {
|
||||
# Special case for `typings_test_ts41` test as we want to pin
|
||||
# `typescript` at version 4.1.x for that test and not link to the
|
||||
|
||||
@@ -43,7 +43,7 @@ const lockfilePath = `${projectDir}/yarn.lock`;
|
||||
console.log(`Checking dependencies for '${projectDir}'...`);
|
||||
|
||||
// Collect non-local dependencies (in `[name, version]` pairs).
|
||||
// (Also ingore `git+https:` dependencies, because checking them is not straight-forward.)
|
||||
// (Also ignore `git+https:` dependencies, because checking them is not straight-forward.)
|
||||
const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf8'));
|
||||
const deps = [
|
||||
...Object.entries(pkgJson.dependencies || {}),
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
|
||||
|
||||
import * as animations from '@angular/animations';
|
||||
import * as animationsBrowser from '@angular/animations/browser';
|
||||
import * as animationsBrowserTesting from '@angular/animations/browser/testing';
|
||||
import * as common from '@angular/common';
|
||||
import * as commonHttp from '@angular/common/http';
|
||||
import * as commonTesting from '@angular/common/testing';
|
||||
import * as commonHttpTesting from '@angular/common/testing';
|
||||
import * as compiler from '@angular/compiler';
|
||||
import * as compilerTesting from '@angular/compiler/testing';
|
||||
import * as core from '@angular/core';
|
||||
import * as coreTesting from '@angular/core/testing';
|
||||
import * as elements from '@angular/elements';
|
||||
import * as forms from '@angular/forms';
|
||||
import * as platformBrowser from '@angular/platform-browser';
|
||||
import * as platformBrowserDynamic from '@angular/platform-browser-dynamic';
|
||||
import * as platformBrowserDynamicTesting from '@angular/platform-browser-dynamic/testing';
|
||||
import * as platformBrowserAnimations from '@angular/platform-browser/animations';
|
||||
import * as platformBrowserTesting from '@angular/platform-browser/testing';
|
||||
import * as platformServer from '@angular/platform-server';
|
||||
import * as platformServerInit from '@angular/platform-server/init';
|
||||
import * as platformServerTesting from '@angular/platform-server/testing';
|
||||
import * as router from '@angular/router';
|
||||
import * as routerTesting from '@angular/router/testing';
|
||||
import * as routerUpgrade from '@angular/router/upgrade';
|
||||
import * as serviceWorker from '@angular/service-worker';
|
||||
import * as upgrade from '@angular/upgrade';
|
||||
import * as upgradeStatic from '@angular/upgrade/static';
|
||||
import * as upgradeTesting from '@angular/upgrade/static/testing';
|
||||
|
||||
export default {
|
||||
animations,
|
||||
animationsBrowser,
|
||||
animationsBrowserTesting,
|
||||
common,
|
||||
commonTesting,
|
||||
commonHttp,
|
||||
commonHttpTesting,
|
||||
compiler,
|
||||
compilerTesting,
|
||||
core,
|
||||
coreTesting,
|
||||
elements,
|
||||
forms,
|
||||
platformBrowser,
|
||||
platformBrowserTesting,
|
||||
platformBrowserDynamic,
|
||||
platformBrowserDynamicTesting,
|
||||
platformBrowserAnimations,
|
||||
platformServer,
|
||||
platformServerInit,
|
||||
platformServerTesting,
|
||||
router,
|
||||
routerTesting,
|
||||
routerUpgrade,
|
||||
serviceWorker,
|
||||
upgrade,
|
||||
upgradeStatic,
|
||||
upgradeTesting,
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "angular-integration",
|
||||
"description": "Assert that users with rxjs 7 can type-check an Angular application",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@angular/animations": "file:../../dist/packages-dist/animations",
|
||||
"@angular/common": "file:../../dist/packages-dist/common",
|
||||
"@angular/compiler": "file:../../dist/packages-dist/compiler",
|
||||
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
|
||||
"@angular/core": "file:../../dist/packages-dist/core",
|
||||
"@angular/elements": "file:../../dist/packages-dist/elements",
|
||||
"@angular/forms": "file:../../dist/packages-dist/forms",
|
||||
"@angular/platform-browser": "file:../../dist/packages-dist/platform-browser",
|
||||
"@angular/platform-browser-dynamic": "file:../../dist/packages-dist/platform-browser-dynamic",
|
||||
"@angular/platform-server": "file:../../dist/packages-dist/platform-server",
|
||||
"@angular/router": "file:../../dist/packages-dist/router",
|
||||
"@angular/service-worker": "file:../../dist/packages-dist/service-worker",
|
||||
"@angular/upgrade": "file:../../dist/packages-dist/upgrade",
|
||||
"@types/jasmine": "file:../../node_modules/@types/jasmine",
|
||||
"rxjs": "^7.3.0",
|
||||
"typescript": "file:../../node_modules/typescript",
|
||||
"zone.js": "file:../../dist/zone.js-dist/archive/zone.js.tgz"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "tsc"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"experimentalDecorators": true,
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "./dist/out-tsc",
|
||||
"rootDir": ".",
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"es5",
|
||||
"dom",
|
||||
"es2015.collection",
|
||||
"es2015.iterable",
|
||||
"es2015.promise"
|
||||
],
|
||||
"types": [],
|
||||
},
|
||||
"files": [
|
||||
"include-all.ts",
|
||||
"node_modules/@types/jasmine/index.d.ts"
|
||||
]
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "angular-srcs",
|
||||
"version": "12.2.0-next.3",
|
||||
"version": "12.2.1",
|
||||
"private": true,
|
||||
"description": "Angular - a web framework for modern web apps",
|
||||
"homepage": "https://github.com/angular/angular",
|
||||
|
||||
@@ -298,98 +298,8 @@ export function compile({
|
||||
};
|
||||
|
||||
const ngHost = ng.createCompilerHost({options: compilerOpts, tsHost: bazelHost});
|
||||
const fileNameToModuleNameCache = new Map<string, string>();
|
||||
ngHost.fileNameToModuleName = (importedFilePath: string, containingFilePath?: string) => {
|
||||
const cacheKey = `${importedFilePath}:${containingFilePath}`;
|
||||
// Memoize this lookup to avoid expensive re-parses of the same file
|
||||
// When run as a worker, the actual ts.SourceFile is cached
|
||||
// but when we don't run as a worker, there is no cache.
|
||||
// For one example target in g3, we saw a cache hit rate of 7590/7695
|
||||
if (fileNameToModuleNameCache.has(cacheKey)) {
|
||||
return fileNameToModuleNameCache.get(cacheKey);
|
||||
}
|
||||
const result = doFileNameToModuleName(importedFilePath, containingFilePath);
|
||||
fileNameToModuleNameCache.set(cacheKey, result);
|
||||
return result;
|
||||
};
|
||||
|
||||
function doFileNameToModuleName(importedFilePath: string, containingFilePath?: string): string {
|
||||
const relativeTargetPath =
|
||||
relativeToRootDirs(importedFilePath, compilerOpts.rootDirs).replace(EXT, '');
|
||||
const manifestTargetPath = `${bazelOpts.workspaceName}/${relativeTargetPath}`;
|
||||
if (useManifestPathsAsModuleName === true) {
|
||||
return manifestTargetPath;
|
||||
}
|
||||
|
||||
// Unless manifest paths are explicitly enforced, we initially check if a module name is
|
||||
// set for the given source file. The compiler host from `@bazel/typescript` sets source
|
||||
// file module names if the compilation targets either UMD or AMD. To ensure that the AMD
|
||||
// module names match, we first consider those.
|
||||
try {
|
||||
const sourceFile = ngHost.getSourceFile(importedFilePath, ts.ScriptTarget.Latest);
|
||||
if (sourceFile && sourceFile.moduleName) {
|
||||
return sourceFile.moduleName;
|
||||
}
|
||||
} catch (err) {
|
||||
// File does not exist or parse error. Ignore this case and continue onto the
|
||||
// other methods of resolving the module below.
|
||||
}
|
||||
|
||||
// It can happen that the ViewEngine compiler needs to write an import in a factory file,
|
||||
// and is using an ngsummary file to get the symbols.
|
||||
// The ngsummary comes from an upstream ng_module rule.
|
||||
// The upstream rule based its imports on ngsummary file which was generated from a
|
||||
// metadata.json file that was published to npm in an Angular library.
|
||||
// However, the ngsummary doesn't propagate the 'importAs' from the original metadata.json
|
||||
// so we would normally not be able to supply the correct module name for it.
|
||||
// For example, if the rootDir-relative filePath is
|
||||
// node_modules/@angular/material/toolbar/typings/index
|
||||
// we would supply a module name
|
||||
// @angular/material/toolbar/typings/index
|
||||
// but there is no JavaScript file to load at this path.
|
||||
// This is a workaround for https://github.com/angular/angular/issues/29454
|
||||
if (importedFilePath.indexOf('node_modules') >= 0) {
|
||||
const maybeMetadataFile = importedFilePath.replace(EXT, '') + '.metadata.json';
|
||||
if (fs.existsSync(maybeMetadataFile)) {
|
||||
const moduleName = (JSON.parse(fs.readFileSync(maybeMetadataFile, {encoding: 'utf-8'})) as {
|
||||
importAs: string
|
||||
}).importAs;
|
||||
if (moduleName) {
|
||||
return moduleName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((compilerOpts.module === ts.ModuleKind.UMD || compilerOpts.module === ts.ModuleKind.AMD) &&
|
||||
ngHost.amdModuleName) {
|
||||
return ngHost.amdModuleName({fileName: importedFilePath} as ts.SourceFile);
|
||||
}
|
||||
|
||||
// If no AMD module name has been set for the source file by the `@bazel/typescript` compiler
|
||||
// host, and the target file is not part of a flat module node module package, we use the
|
||||
// following rules (in order):
|
||||
// 1. If target file is part of `node_modules/`, we use the package module name.
|
||||
// 2. If no containing file is specified, or the target file is part of a different
|
||||
// compilation unit, we use a Bazel manifest path. Relative paths are not possible
|
||||
// since we don't have a containing file, and the target file could be located in the
|
||||
// output directory, or in an external Bazel repository.
|
||||
// 3. If both rules above didn't match, we compute a relative path between the source files
|
||||
// since they are part of the same compilation unit.
|
||||
// Note that we don't want to always use (2) because it could mean that compilation outputs
|
||||
// are always leaking Bazel-specific paths, and the output is not self-contained. This could
|
||||
// break `esm2015` or `esm5` output for Angular package release output
|
||||
// Omit the `node_modules` prefix if the module name of an NPM package is requested.
|
||||
if (relativeTargetPath.startsWith(NODE_MODULES)) {
|
||||
return relativeTargetPath.substr(NODE_MODULES.length);
|
||||
} else if (
|
||||
containingFilePath == null || !bazelOpts.compilationTargetSrc.includes(importedFilePath)) {
|
||||
return manifestTargetPath;
|
||||
}
|
||||
const containingFileDir =
|
||||
path.dirname(relativeToRootDirs(containingFilePath, compilerOpts.rootDirs));
|
||||
const relativeImportPath = path.posix.relative(containingFileDir, relativeTargetPath);
|
||||
return relativeImportPath.startsWith('.') ? relativeImportPath : `./${relativeImportPath}`;
|
||||
}
|
||||
patchNgHostWithFileNameToModuleName(
|
||||
ngHost, compilerOpts, bazelOpts, useManifestPathsAsModuleName);
|
||||
|
||||
ngHost.toSummaryFileName = (fileName: string, referringSrcFileName: string) => path.posix.join(
|
||||
bazelOpts.workspaceName,
|
||||
@@ -553,3 +463,108 @@ function gatherDiagnosticsForInputsOnly(
|
||||
if (require.main === module) {
|
||||
process.exitCode = main(process.argv.slice(2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds support for the optional `fileNameToModuleName` operation to a given `ng.CompilerHost`.
|
||||
*
|
||||
* This is used within `ngc-wrapped` and the Bazel compilation flow, but is exported here to allow
|
||||
* for other consumers of the compiler to access this same logic. For example, the xi18n operation
|
||||
* in g3 configures its own `ng.CompilerHost` which also requires `fileNameToModuleName` to work
|
||||
* correctly.
|
||||
*/
|
||||
export function patchNgHostWithFileNameToModuleName(
|
||||
ngHost: ng.CompilerHost, compilerOpts: ng.CompilerOptions, bazelOpts: BazelOptions,
|
||||
useManifestPathsAsModuleName: boolean): void {
|
||||
const fileNameToModuleNameCache = new Map<string, string>();
|
||||
ngHost.fileNameToModuleName = (importedFilePath: string, containingFilePath?: string) => {
|
||||
const cacheKey = `${importedFilePath}:${containingFilePath}`;
|
||||
// Memoize this lookup to avoid expensive re-parses of the same file
|
||||
// When run as a worker, the actual ts.SourceFile is cached
|
||||
// but when we don't run as a worker, there is no cache.
|
||||
// For one example target in g3, we saw a cache hit rate of 7590/7695
|
||||
if (fileNameToModuleNameCache.has(cacheKey)) {
|
||||
return fileNameToModuleNameCache.get(cacheKey);
|
||||
}
|
||||
const result = doFileNameToModuleName(importedFilePath, containingFilePath);
|
||||
fileNameToModuleNameCache.set(cacheKey, result);
|
||||
return result;
|
||||
};
|
||||
|
||||
function doFileNameToModuleName(importedFilePath: string, containingFilePath?: string): string {
|
||||
const relativeTargetPath =
|
||||
relativeToRootDirs(importedFilePath, compilerOpts.rootDirs).replace(EXT, '');
|
||||
const manifestTargetPath = `${bazelOpts.workspaceName}/${relativeTargetPath}`;
|
||||
if (useManifestPathsAsModuleName === true) {
|
||||
return manifestTargetPath;
|
||||
}
|
||||
|
||||
// Unless manifest paths are explicitly enforced, we initially check if a module name is
|
||||
// set for the given source file. The compiler host from `@bazel/typescript` sets source
|
||||
// file module names if the compilation targets either UMD or AMD. To ensure that the AMD
|
||||
// module names match, we first consider those.
|
||||
try {
|
||||
const sourceFile = ngHost.getSourceFile(importedFilePath, ts.ScriptTarget.Latest);
|
||||
if (sourceFile && sourceFile.moduleName) {
|
||||
return sourceFile.moduleName;
|
||||
}
|
||||
} catch (err) {
|
||||
// File does not exist or parse error. Ignore this case and continue onto the
|
||||
// other methods of resolving the module below.
|
||||
}
|
||||
|
||||
// It can happen that the ViewEngine compiler needs to write an import in a factory file,
|
||||
// and is using an ngsummary file to get the symbols.
|
||||
// The ngsummary comes from an upstream ng_module rule.
|
||||
// The upstream rule based its imports on ngsummary file which was generated from a
|
||||
// metadata.json file that was published to npm in an Angular library.
|
||||
// However, the ngsummary doesn't propagate the 'importAs' from the original metadata.json
|
||||
// so we would normally not be able to supply the correct module name for it.
|
||||
// For example, if the rootDir-relative filePath is
|
||||
// node_modules/@angular/material/toolbar/typings/index
|
||||
// we would supply a module name
|
||||
// @angular/material/toolbar/typings/index
|
||||
// but there is no JavaScript file to load at this path.
|
||||
// This is a workaround for https://github.com/angular/angular/issues/29454
|
||||
if (importedFilePath.indexOf('node_modules') >= 0) {
|
||||
const maybeMetadataFile = importedFilePath.replace(EXT, '') + '.metadata.json';
|
||||
if (fs.existsSync(maybeMetadataFile)) {
|
||||
const moduleName = (JSON.parse(fs.readFileSync(maybeMetadataFile, {encoding: 'utf-8'})) as {
|
||||
importAs: string
|
||||
}).importAs;
|
||||
if (moduleName) {
|
||||
return moduleName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((compilerOpts.module === ts.ModuleKind.UMD || compilerOpts.module === ts.ModuleKind.AMD) &&
|
||||
ngHost.amdModuleName) {
|
||||
return ngHost.amdModuleName({fileName: importedFilePath} as ts.SourceFile);
|
||||
}
|
||||
|
||||
// If no AMD module name has been set for the source file by the `@bazel/typescript` compiler
|
||||
// host, and the target file is not part of a flat module node module package, we use the
|
||||
// following rules (in order):
|
||||
// 1. If target file is part of `node_modules/`, we use the package module name.
|
||||
// 2. If no containing file is specified, or the target file is part of a different
|
||||
// compilation unit, we use a Bazel manifest path. Relative paths are not possible
|
||||
// since we don't have a containing file, and the target file could be located in the
|
||||
// output directory, or in an external Bazel repository.
|
||||
// 3. If both rules above didn't match, we compute a relative path between the source files
|
||||
// since they are part of the same compilation unit.
|
||||
// Note that we don't want to always use (2) because it could mean that compilation outputs
|
||||
// are always leaking Bazel-specific paths, and the output is not self-contained. This could
|
||||
// break `esm2015` or `esm5` output for Angular package release output
|
||||
// Omit the `node_modules` prefix if the module name of an NPM package is requested.
|
||||
if (relativeTargetPath.startsWith(NODE_MODULES)) {
|
||||
return relativeTargetPath.substr(NODE_MODULES.length);
|
||||
} else if (
|
||||
containingFilePath == null || !bazelOpts.compilationTargetSrc.includes(importedFilePath)) {
|
||||
return manifestTargetPath;
|
||||
}
|
||||
const containingFileDir =
|
||||
path.dirname(relativeToRootDirs(containingFilePath, compilerOpts.rootDirs));
|
||||
const relativeImportPath = path.posix.relative(containingFileDir, relativeTargetPath);
|
||||
return relativeImportPath.startsWith('.') ? relativeImportPath : `./${relativeImportPath}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/core": "0.0.0-PLACEHOLDER",
|
||||
"rxjs": "^6.5.3"
|
||||
"rxjs": "^6.5.3 || ^7.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -22,7 +22,7 @@ import {Subscribable, Unsubscribable} from 'rxjs';
|
||||
// the implementation does not rely on other methods:
|
||||
const wrapSubscribable = <T>(input: Subscribable<T>): Subscribable<T> => ({
|
||||
subscribe(...args: any): Unsubscribable {
|
||||
const subscription = input.subscribe(...args);
|
||||
const subscription = input.subscribe.apply(input, args);
|
||||
return {
|
||||
unsubscribe() {
|
||||
subscription.unsubscribe();
|
||||
|
||||
@@ -172,6 +172,16 @@ export enum ErrorCode {
|
||||
*/
|
||||
SPLIT_TWO_WAY_BINDING = 8007,
|
||||
|
||||
/**
|
||||
* A two way binding in a template has an incorrect syntax,
|
||||
* parentheses outside brackets. For example:
|
||||
*
|
||||
* ```
|
||||
* <div ([foo])="bar" />
|
||||
* ```
|
||||
*/
|
||||
INVALID_BANANA_IN_BOX = 8101,
|
||||
|
||||
/**
|
||||
* The template type-checking engine would need to generate an inline type check block for a
|
||||
* component, but the current type-checking environment doesn't support it.
|
||||
|
||||
@@ -138,3 +138,12 @@ function bindingNameEquals(node: ts.BindingName, name: string): boolean {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getSourceCodeForDiagnostic(diag: ts.Diagnostic): string {
|
||||
if (diag.file === undefined || diag.start === undefined || diag.length === undefined) {
|
||||
throw new Error(
|
||||
`Unable to get source code for diagnostic. Provided diagnostic instance doesn't contain "file", "start" and/or "length" properties.`);
|
||||
}
|
||||
const text = diag.file.text;
|
||||
return text.substr(diag.start, diag.length);
|
||||
}
|
||||
|
||||
@@ -168,9 +168,9 @@ export interface TemplateTypeChecker {
|
||||
/**
|
||||
* Constructs a `ts.Diagnostic` for a given `ParseSourceSpan` within a template.
|
||||
*/
|
||||
makeTemplateDiagnostic(
|
||||
makeTemplateDiagnostic<T extends ErrorCode>(
|
||||
clazz: ts.ClassDeclaration, sourceSpan: ParseSourceSpan, category: ts.DiagnosticCategory,
|
||||
errorCode: ErrorCode, message: string, relatedInformation?: {
|
||||
errorCode: T, message: string, relatedInformation?: {
|
||||
text: string,
|
||||
start: number,
|
||||
end: number,
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
load("//tools:defaults.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "extended",
|
||||
srcs = glob(
|
||||
["**/*.ts"],
|
||||
),
|
||||
visibility = ["//packages/compiler-cli/src/ngtsc:__subpackages__"],
|
||||
deps = [
|
||||
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/api",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/extended/api",
|
||||
"@npm//typescript",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
load("//tools:defaults.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "api",
|
||||
srcs = glob(
|
||||
["**/*.ts"],
|
||||
),
|
||||
visibility = ["//packages/compiler-cli/src/ngtsc:__subpackages__"],
|
||||
deps = [
|
||||
"//packages/compiler",
|
||||
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/api",
|
||||
"@npm//typescript",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {TmplAstNode} from '@angular/compiler';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {ErrorCode} from '../../../diagnostics';
|
||||
import {TemplateTypeChecker} from '../../api';
|
||||
|
||||
/**
|
||||
* A `ts.Diangostic` with a specific error code.
|
||||
*/
|
||||
export type TemplateDiagnostic<T extends ErrorCode> = ts.Diagnostic&{code: T};
|
||||
|
||||
/**
|
||||
* A Template Check receives information about the template it's checking and returns
|
||||
* information about the diagnostics to be generated.
|
||||
*/
|
||||
export interface TemplateCheck<T extends ErrorCode> {
|
||||
/** Unique template check code, used for configuration and searching the error. */
|
||||
code: T;
|
||||
|
||||
/** Runs check and returns information about the diagnostics to be generated. */
|
||||
run(ctx: TemplateContext, template: TmplAstNode[]): TemplateDiagnostic<T>[];
|
||||
}
|
||||
|
||||
/**
|
||||
* The TemplateContext provided to a Template Check to get diagnostic information.
|
||||
*/
|
||||
export interface TemplateContext {
|
||||
/** Interface that provides information about template nodes. */
|
||||
templateTypeChecker: TemplateTypeChecker;
|
||||
|
||||
/**
|
||||
* TypeScript interface that provides type information about symbols that appear
|
||||
* in the template (it is not to query types outside the Angular component).
|
||||
*/
|
||||
typeChecker: ts.TypeChecker;
|
||||
|
||||
/** The `@Component()` class from which the template was obtained. */
|
||||
component: ts.ClassDeclaration;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import * as ts from 'typescript';
|
||||
import {ErrorCode} from '../../../diagnostics';
|
||||
import {TemplateTypeChecker} from '../../api';
|
||||
import {TemplateCheck, TemplateContext} from '../api/api';
|
||||
|
||||
/**
|
||||
* Run all `TemplateChecks` for a component and return the generated `ts.Diagnostic`s.
|
||||
* @param component the `@Component()` class from which the template is obtained
|
||||
* @param templateTypeChecker interface to get information about template nodes
|
||||
* @param typeChecker program's type checker
|
||||
* @param templateChecks specific checks to be run
|
||||
* @returns generated `ts.Diagnostic[]`
|
||||
*/
|
||||
export function getExtendedTemplateDiagnosticsForComponent(
|
||||
component: ts.ClassDeclaration, templateTypeChecker: TemplateTypeChecker,
|
||||
typeChecker: ts.TypeChecker, templateChecks: TemplateCheck<ErrorCode>[]): ts.Diagnostic[] {
|
||||
const template = templateTypeChecker.getTemplate(component);
|
||||
// Skip checks if component has no template. This can happen if the user writes a
|
||||
// `@Component()` but doesn't add the template, could happen in the language service
|
||||
// when users are in the middle of typing code.
|
||||
if (template === null) {
|
||||
return [];
|
||||
}
|
||||
const diagnostics: ts.Diagnostic[] = [];
|
||||
|
||||
const ctx = {templateTypeChecker, typeChecker, component} as TemplateContext;
|
||||
|
||||
for (const check of templateChecks) {
|
||||
diagnostics.push(...deduplicateDiagnostics(check.run(ctx, template)));
|
||||
}
|
||||
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
// Filter out duplicated diagnostics, this is possible due to the way the compiler
|
||||
// handles desugaring and produces `AST`s. Ex.
|
||||
//
|
||||
// ```
|
||||
// <div *ngIf="true" (foo)="bar">test</div>
|
||||
// ```
|
||||
//
|
||||
// Would result in the following AST:
|
||||
//
|
||||
// ```
|
||||
// Template {
|
||||
// outputs: [
|
||||
// BoundEvent {
|
||||
// name: 'foo',
|
||||
// /.../
|
||||
// }
|
||||
// ],
|
||||
// children: [
|
||||
// Element {
|
||||
// outputs: [
|
||||
// BoundEvent {
|
||||
// name: 'foo',
|
||||
// /.../
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ],
|
||||
// /.../
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// In this case a duplicated diagnostic could be generated for the output `foo`.
|
||||
// TODO(danieltrevino): handle duplicated diagnostics when they are being generated
|
||||
// to avoid extra work (could be directly in the visitor).
|
||||
// https://github.com/angular/angular/pull/42984#discussion_r684823926
|
||||
function deduplicateDiagnostics(diagnostics: ts.Diagnostic[]): ts.Diagnostic[] {
|
||||
const result: ts.Diagnostic[] = [];
|
||||
for (const newDiag of diagnostics) {
|
||||
const isDuplicateDiag = result.some(existingDiag => areDiagnosticsEqual(newDiag, existingDiag));
|
||||
if (!isDuplicateDiag) {
|
||||
result.push(newDiag);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function areDiagnosticsEqual(first: ts.Diagnostic, second: ts.Diagnostic): boolean {
|
||||
return first.file?.fileName === second.file?.fileName && first.start === second.start &&
|
||||
first.length === second.length && first.code === second.code;
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
load("//tools:defaults.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "invalid_banana_in_box",
|
||||
srcs = ["index.ts"],
|
||||
visibility = ["//packages/compiler-cli/src/ngtsc/typecheck/extended:__subpackages__"],
|
||||
deps = [
|
||||
"//packages/compiler",
|
||||
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/extended/api",
|
||||
"@npm//typescript",
|
||||
],
|
||||
)
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {TmplAstBoundEvent, TmplAstNode, TmplAstRecursiveVisitor} from '@angular/compiler';
|
||||
import * as ts from 'typescript';
|
||||
import {ErrorCode} from '../../../../../diagnostics';
|
||||
import {TemplateCheck, TemplateContext, TemplateDiagnostic} from '../../../api/api';
|
||||
|
||||
/**
|
||||
* Ensures the two-way binding syntax is correct.
|
||||
* Parentheses should be inside the brackets "[()]".
|
||||
* Will return diagnostic information when "([])" is found.
|
||||
*/
|
||||
export class InvalidBananaInBoxCheck implements TemplateCheck<ErrorCode.INVALID_BANANA_IN_BOX> {
|
||||
code: ErrorCode.INVALID_BANANA_IN_BOX = 8101;
|
||||
|
||||
run(ctx: TemplateContext,
|
||||
template: TmplAstNode[]): TemplateDiagnostic<ErrorCode.INVALID_BANANA_IN_BOX>[] {
|
||||
const visitor = new BananaVisitor(ctx);
|
||||
|
||||
return visitor.getDiagnostics(template);
|
||||
}
|
||||
}
|
||||
|
||||
class BananaVisitor extends TmplAstRecursiveVisitor {
|
||||
private diagnostics: ts.Diagnostic[] = [];
|
||||
|
||||
constructor(public readonly ctx: TemplateContext) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for outputs with names surrounded in brackets "[]".
|
||||
* The syntax '([foo])="bar"' would be interpreted as an @Output()
|
||||
* with name '[foo]'. Just like '(foo)="bar"' would have the name 'foo'.
|
||||
* Generate diagnostic information for the cases found.
|
||||
*/
|
||||
override visitBoundEvent(boundEvent: TmplAstBoundEvent) {
|
||||
const name = boundEvent.name;
|
||||
if (name.startsWith('[') && name.endsWith(']')) {
|
||||
const boundSyntax = boundEvent.sourceSpan.toString();
|
||||
const expectedBoundSyntax = boundSyntax.replace(`(${name})`, `[(${name.slice(1, -1)})]`);
|
||||
this.diagnostics.push(
|
||||
this.ctx.templateTypeChecker.makeTemplateDiagnostic<ErrorCode.INVALID_BANANA_IN_BOX>(
|
||||
this.ctx.component, boundEvent.sourceSpan, ts.DiagnosticCategory.Warning,
|
||||
ErrorCode.INVALID_BANANA_IN_BOX,
|
||||
`In the two-way binding syntax the parentheses should be inside the brackets, ex. '${
|
||||
expectedBoundSyntax}'.
|
||||
Find more at https://angular.io/guide/two-way-binding`));
|
||||
}
|
||||
}
|
||||
|
||||
getDiagnostics(template: TmplAstNode[]): ts.Diagnostic[] {
|
||||
this.diagnostics = [];
|
||||
for (const node of template) {
|
||||
node.visit(this);
|
||||
}
|
||||
return this.diagnostics;
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
load("//tools:defaults.bzl", "jasmine_node_test", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "test_lib",
|
||||
testonly = True,
|
||||
srcs = ["spec.ts"],
|
||||
deps = [
|
||||
"//packages/compiler",
|
||||
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
||||
"//packages/compiler-cli/src/ngtsc/file_system",
|
||||
"//packages/compiler-cli/src/ngtsc/file_system/testing",
|
||||
"//packages/compiler-cli/src/ngtsc/testing",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/extended",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/extended/src/template_checks/invalid_banana_in_box",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/testing",
|
||||
"@npm//typescript",
|
||||
],
|
||||
)
|
||||
|
||||
jasmine_node_test(
|
||||
name = "test",
|
||||
bootstrap = ["//tools/testing:node_no_angular_es5"],
|
||||
deps = [
|
||||
":test_lib",
|
||||
],
|
||||
)
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import * as ts from 'typescript';
|
||||
import {ErrorCode} from '../../../../../diagnostics';
|
||||
import {absoluteFrom, getSourceFileOrError} from '../../../../../file_system';
|
||||
import {runInEachFileSystem} from '../../../../../file_system/testing';
|
||||
import {getSourceCodeForDiagnostic} from '../../../../../testing';
|
||||
import {getClass, setup} from '../../../../testing';
|
||||
import {getExtendedTemplateDiagnosticsForComponent} from '../../../src/template_checker';
|
||||
import {InvalidBananaInBoxCheck} from '../../../src/template_checks/invalid_banana_in_box/index';
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
describe('TemplateChecks', () => {
|
||||
it('should produce invalid banana in a box warning', () => {
|
||||
const fileName = absoluteFrom('/main.ts');
|
||||
const {program, templateTypeChecker} = setup([{
|
||||
fileName,
|
||||
templates: {
|
||||
'TestCmp': '<div ([input])="var1"> </div>',
|
||||
},
|
||||
source: 'export class TestCmp { var1: string = "text"; }'
|
||||
}]);
|
||||
const sf = getSourceFileOrError(program, fileName);
|
||||
const component = getClass(sf, 'TestCmp');
|
||||
const diags = getExtendedTemplateDiagnosticsForComponent(
|
||||
component, templateTypeChecker, program.getTypeChecker(),
|
||||
[new InvalidBananaInBoxCheck()]);
|
||||
expect(diags.length).toBe(1);
|
||||
expect(diags[0].category).toBe(ts.DiagnosticCategory.Warning);
|
||||
expect(diags[0].code).toBe(ErrorCode.INVALID_BANANA_IN_BOX);
|
||||
expect(getSourceCodeForDiagnostic(diags[0])).toBe('([input])="var1"');
|
||||
});
|
||||
|
||||
it('should not produce invalid banana in a box warning if written correctly', () => {
|
||||
const fileName = absoluteFrom('/main.ts');
|
||||
const {program, templateTypeChecker} = setup([{
|
||||
fileName,
|
||||
templates: {
|
||||
'TestCmp': '<div [(input)]="var1"> </div>',
|
||||
},
|
||||
source: 'export class TestCmp { var1: string = "text"; }'
|
||||
}]);
|
||||
const sf = getSourceFileOrError(program, fileName);
|
||||
const component = getClass(sf, 'TestCmp');
|
||||
const diags = getExtendedTemplateDiagnosticsForComponent(
|
||||
component, templateTypeChecker, program.getTypeChecker(),
|
||||
[new InvalidBananaInBoxCheck()]);
|
||||
expect(diags.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should not produce invalid banana in a box warning with bracket in the middle of the name',
|
||||
() => {
|
||||
const fileName = absoluteFrom('/main.ts');
|
||||
const {program, templateTypeChecker} = setup([{
|
||||
fileName,
|
||||
templates: {
|
||||
'TestCmp': '<div (abc[123]def)="var1"> </div>',
|
||||
},
|
||||
source: 'export class TestCmp { var1: string = "text"; }'
|
||||
}]);
|
||||
const sf = getSourceFileOrError(program, fileName);
|
||||
const component = getClass(sf, 'TestCmp');
|
||||
const diags = getExtendedTemplateDiagnosticsForComponent(
|
||||
component, templateTypeChecker, program.getTypeChecker(),
|
||||
[new InvalidBananaInBoxCheck()]);
|
||||
expect(diags.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should produce invalid banana in a box warnings for *ngIf and ng-template', () => {
|
||||
const fileName = absoluteFrom('/main.ts');
|
||||
const {program, templateTypeChecker} = setup([{
|
||||
fileName,
|
||||
templates: {
|
||||
'TestCmp': `<div>
|
||||
<div *ngIf="false" ([foo])="var1"> </div>
|
||||
<ng-template #elseBlock ([bar])="var1">Content to render when condition is false.</ng-template>
|
||||
</div>`,
|
||||
},
|
||||
source: `export class TestCmp {
|
||||
var1: string = "text";
|
||||
}`
|
||||
}]);
|
||||
const sf = getSourceFileOrError(program, fileName);
|
||||
const component = getClass(sf, 'TestCmp');
|
||||
const diags = getExtendedTemplateDiagnosticsForComponent(
|
||||
component, templateTypeChecker, program.getTypeChecker(),
|
||||
[new InvalidBananaInBoxCheck()]);
|
||||
expect(diags.length).toBe(2);
|
||||
expect(diags[0].category).toBe(ts.DiagnosticCategory.Warning);
|
||||
expect(diags[0].code).toBe(ErrorCode.INVALID_BANANA_IN_BOX);
|
||||
expect(getSourceCodeForDiagnostic(diags[0])).toBe('([foo])="var1"');
|
||||
expect(diags[1].category).toBe(ts.DiagnosticCategory.Warning);
|
||||
expect(diags[1].code).toBe(ErrorCode.INVALID_BANANA_IN_BOX);
|
||||
expect(getSourceCodeForDiagnostic(diags[1])).toBe('([bar])="var1"');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -309,9 +309,9 @@ export class TemplateTypeCheckerImpl implements TemplateTypeChecker {
|
||||
this.isComplete = false;
|
||||
}
|
||||
|
||||
makeTemplateDiagnostic(
|
||||
makeTemplateDiagnostic<T extends ErrorCode>(
|
||||
clazz: ts.ClassDeclaration, sourceSpan: ParseSourceSpan, category: ts.DiagnosticCategory,
|
||||
errorCode: ErrorCode, message: string, relatedInformation?: {
|
||||
errorCode: T, message: string, relatedInformation?: {
|
||||
text: string,
|
||||
start: number,
|
||||
end: number,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {TmplAstReference, TmplAstTemplate} from '@angular/compiler';
|
||||
import {AST, EmptyExpr, LiteralPrimitive, MethodCall, PropertyRead, PropertyWrite, SafeMethodCall, SafePropertyRead, TmplAstNode} from '@angular/compiler/src/compiler';
|
||||
import {AST, EmptyExpr, ImplicitReceiver, LiteralPrimitive, MethodCall, PropertyRead, PropertyWrite, SafeMethodCall, SafePropertyRead, TmplAstNode} from '@angular/compiler/src/compiler';
|
||||
import {TextAttribute} from '@angular/compiler/src/render3/r3_ast';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
@@ -91,6 +91,19 @@ export class CompletionEngine {
|
||||
}
|
||||
}
|
||||
|
||||
if (node instanceof PropertyRead && node.receiver instanceof ImplicitReceiver) {
|
||||
const nodeLocation = findFirstMatchingNode(this.tcb, {
|
||||
filter: ts.isPropertyAccessExpression,
|
||||
withSpan: node.sourceSpan,
|
||||
});
|
||||
if (nodeLocation) {
|
||||
nodeContext = {
|
||||
shimPath: this.shimPath,
|
||||
positionInShimFile: nodeLocation.getStart(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
componentContext: this.componentContext,
|
||||
templateContext,
|
||||
|
||||
@@ -26,6 +26,7 @@ ts_library(
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/api",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/diagnostics",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/testing",
|
||||
"//packages/compiler-cli/src/ngtsc/util",
|
||||
"@npm//typescript",
|
||||
],
|
||||
|
||||
@@ -12,7 +12,7 @@ import {absoluteFrom, getSourceFileOrError} from '../../file_system';
|
||||
import {runInEachFileSystem, TestFile} from '../../file_system/testing';
|
||||
import {OptimizeFor, TypeCheckingConfig} from '../api';
|
||||
|
||||
import {ngForDeclaration, ngForDts, setup, TestDeclaration} from './test_utils';
|
||||
import {ngForDeclaration, ngForDts, setup, TestDeclaration} from '../testing';
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
describe('template diagnostics', () => {
|
||||
|
||||
@@ -15,7 +15,7 @@ import {sfExtensionData, ShimReferenceTagger} from '../../shims';
|
||||
import {expectCompleteReuse, makeProgram} from '../../testing';
|
||||
import {OptimizeFor} from '../api';
|
||||
|
||||
import {setup} from './test_utils';
|
||||
import {setup} from '../testing';
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
describe('template type-checking program', () => {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {initMockFileSystem} from '../../file_system/testing';
|
||||
import {tcb, TestDeclaration} from './test_utils';
|
||||
import {tcb, TestDeclaration} from '../testing';
|
||||
|
||||
describe('type check blocks diagnostics', () => {
|
||||
beforeEach(() => initMockFileSystem('Native'));
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import {initMockFileSystem} from '../../file_system/testing';
|
||||
import {TypeCheckingConfig} from '../api';
|
||||
|
||||
import {ALL_ENABLED_CONFIG, tcb, TestDeclaration, TestDirective} from './test_utils';
|
||||
import {ALL_ENABLED_CONFIG, tcb, TestDeclaration, TestDirective} from '../testing';
|
||||
|
||||
|
||||
describe('type check blocks', () => {
|
||||
|
||||
@@ -14,7 +14,7 @@ import {runInEachFileSystem} from '../../file_system/testing';
|
||||
import {getTokenAtPosition} from '../../util/src/typescript';
|
||||
import {CompletionKind, GlobalCompletion, TemplateTypeChecker, TypeCheckingConfig} from '../api';
|
||||
|
||||
import {getClass, setup, TypeCheckingTarget} from './test_utils';
|
||||
import {getClass, setup, TypeCheckingTarget} from '../testing';
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
describe('TemplateTypeChecker.getGlobalCompletions()', () => {
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ import {runInEachFileSystem} from '../../file_system/testing';
|
||||
import {ClassDeclaration} from '../../reflection';
|
||||
import {DirectiveSymbol, DomBindingSymbol, ElementSymbol, ExpressionSymbol, InputBindingSymbol, OutputBindingSymbol, PipeSymbol, ReferenceSymbol, Symbol, SymbolKind, TemplateSymbol, TemplateTypeChecker, TypeCheckingConfig, VariableSymbol} from '../api';
|
||||
|
||||
import {getClass, ngForDeclaration, ngForTypeCheckTarget, setup as baseTestSetup, TypeCheckingTarget} from './test_utils';
|
||||
import {getClass, ngForDeclaration, ngForTypeCheckTarget, setup as baseTestSetup, TypeCheckingTarget} from '../testing';
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
describe('TemplateTypeChecker.getSymbolOfNode', () => {
|
||||
|
||||
@@ -11,7 +11,7 @@ import {absoluteFrom, absoluteFromSourceFile, getSourceFileOrError} from '../../
|
||||
import {runInEachFileSystem} from '../../file_system/testing';
|
||||
import {OptimizeFor} from '../api';
|
||||
|
||||
import {getClass, setup, TestDeclaration} from './test_utils';
|
||||
import {getClass, setup, TestDeclaration} from '../testing';
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
describe('TemplateTypeChecker', () => {
|
||||
|
||||
@@ -19,7 +19,7 @@ import {InliningMode, PendingFileTypeCheckingData, TypeCheckContextImpl, TypeChe
|
||||
import {TemplateSourceManager} from '../src/source';
|
||||
import {TypeCheckFile} from '../src/type_check_file';
|
||||
|
||||
import {ALL_ENABLED_CONFIG} from './test_utils';
|
||||
import {ALL_ENABLED_CONFIG} from '../testing';
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
describe('ngtsc typechecking', () => {
|
||||
|
||||
@@ -13,7 +13,7 @@ import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflectio
|
||||
import {getDeclaration, makeProgram} from '../../testing';
|
||||
import {TypeParameterEmitter} from '../src/type_parameter_emitter';
|
||||
|
||||
import {angularCoreDts} from './test_utils';
|
||||
import {angularCoreDts} from '../testing';
|
||||
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
load("//tools:defaults.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "testing",
|
||||
testonly = True,
|
||||
srcs = glob([
|
||||
"**/*.ts",
|
||||
]),
|
||||
visibility = ["//packages/compiler-cli/src/ngtsc:__subpackages__"],
|
||||
deps = [
|
||||
"//packages/compiler",
|
||||
"//packages/compiler-cli/src/ngtsc/file_system",
|
||||
"//packages/compiler-cli/src/ngtsc/file_system/testing",
|
||||
"//packages/compiler-cli/src/ngtsc/imports",
|
||||
"//packages/compiler-cli/src/ngtsc/incremental",
|
||||
"//packages/compiler-cli/src/ngtsc/metadata",
|
||||
"//packages/compiler-cli/src/ngtsc/perf",
|
||||
"//packages/compiler-cli/src/ngtsc/program_driver",
|
||||
"//packages/compiler-cli/src/ngtsc/reflection",
|
||||
"//packages/compiler-cli/src/ngtsc/scope",
|
||||
"//packages/compiler-cli/src/ngtsc/testing",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/api",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/diagnostics",
|
||||
"//packages/compiler-cli/src/ngtsc/util",
|
||||
"@npm//typescript",
|
||||
],
|
||||
)
|
||||
+87
-87
@@ -35,58 +35,58 @@ export function typescriptLibDts(): TestFile {
|
||||
return {
|
||||
name: absoluteFrom('/lib.d.ts'),
|
||||
contents: `
|
||||
type Partial<T> = { [P in keyof T]?: T[P]; };
|
||||
type Pick<T, K extends keyof T> = { [P in K]: T[P]; };
|
||||
type NonNullable<T> = T extends null | undefined ? never : T;
|
||||
|
||||
// The following native type declarations are required for proper type inference
|
||||
declare interface Function {
|
||||
call(...args: any[]): any;
|
||||
}
|
||||
declare interface Array<T> {
|
||||
[index: number]: T;
|
||||
length: number;
|
||||
}
|
||||
declare interface String {
|
||||
length: number;
|
||||
}
|
||||
|
||||
declare interface Event {
|
||||
preventDefault(): void;
|
||||
}
|
||||
declare interface MouseEvent extends Event {
|
||||
readonly x: number;
|
||||
readonly y: number;
|
||||
}
|
||||
|
||||
declare interface HTMLElementEventMap {
|
||||
"click": MouseEvent;
|
||||
}
|
||||
declare interface HTMLElement {
|
||||
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any): void;
|
||||
addEventListener(type: string, listener: (evt: Event): void;): void;
|
||||
}
|
||||
declare interface HTMLDivElement extends HTMLElement {}
|
||||
declare interface HTMLImageElement extends HTMLElement {
|
||||
src: string;
|
||||
alt: string;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
declare interface HTMLQuoteElement extends HTMLElement {
|
||||
cite: string;
|
||||
}
|
||||
declare interface HTMLElementTagNameMap {
|
||||
"blockquote": HTMLQuoteElement;
|
||||
"div": HTMLDivElement;
|
||||
"img": HTMLImageElement;
|
||||
}
|
||||
declare interface Document {
|
||||
createElement<K extends keyof HTMLElementTagNameMap>(tagName: K): HTMLElementTagNameMap[K];
|
||||
createElement(tagName: string): HTMLElement;
|
||||
}
|
||||
declare const document: Document;
|
||||
`
|
||||
type Partial<T> = { [P in keyof T]?: T[P]; };
|
||||
type Pick<T, K extends keyof T> = { [P in K]: T[P]; };
|
||||
type NonNullable<T> = T extends null | undefined ? never : T;
|
||||
|
||||
// The following native type declarations are required for proper type inference
|
||||
declare interface Function {
|
||||
call(...args: any[]): any;
|
||||
}
|
||||
declare interface Array<T> {
|
||||
[index: number]: T;
|
||||
length: number;
|
||||
}
|
||||
declare interface String {
|
||||
length: number;
|
||||
}
|
||||
|
||||
declare interface Event {
|
||||
preventDefault(): void;
|
||||
}
|
||||
declare interface MouseEvent extends Event {
|
||||
readonly x: number;
|
||||
readonly y: number;
|
||||
}
|
||||
|
||||
declare interface HTMLElementEventMap {
|
||||
"click": MouseEvent;
|
||||
}
|
||||
declare interface HTMLElement {
|
||||
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any): void;
|
||||
addEventListener(type: string, listener: (evt: Event): void;): void;
|
||||
}
|
||||
declare interface HTMLDivElement extends HTMLElement {}
|
||||
declare interface HTMLImageElement extends HTMLElement {
|
||||
src: string;
|
||||
alt: string;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
declare interface HTMLQuoteElement extends HTMLElement {
|
||||
cite: string;
|
||||
}
|
||||
declare interface HTMLElementTagNameMap {
|
||||
"blockquote": HTMLQuoteElement;
|
||||
"div": HTMLDivElement;
|
||||
"img": HTMLImageElement;
|
||||
}
|
||||
declare interface Document {
|
||||
createElement<K extends keyof HTMLElementTagNameMap>(tagName: K): HTMLElementTagNameMap[K];
|
||||
createElement(tagName: string): HTMLElement;
|
||||
}
|
||||
declare const document: Document;
|
||||
`
|
||||
};
|
||||
}
|
||||
|
||||
@@ -94,18 +94,18 @@ export function angularCoreDts(): TestFile {
|
||||
return {
|
||||
name: absoluteFrom('/node_modules/@angular/core/index.d.ts'),
|
||||
contents: `
|
||||
export declare class TemplateRef<C> {
|
||||
abstract readonly elementRef: unknown;
|
||||
abstract createEmbeddedView(context: C): unknown;
|
||||
}
|
||||
|
||||
export declare class EventEmitter<T> {
|
||||
subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): unknown;
|
||||
subscribe(observerOrNext?: any, error?: any, complete?: any): unknown;
|
||||
}
|
||||
|
||||
export declare type NgIterable<T> = Array<T> | Iterable<T>;
|
||||
`
|
||||
export declare class TemplateRef<C> {
|
||||
abstract readonly elementRef: unknown;
|
||||
abstract createEmbeddedView(context: C): unknown;
|
||||
}
|
||||
|
||||
export declare class EventEmitter<T> {
|
||||
subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): unknown;
|
||||
subscribe(observerOrNext?: any, error?: any, complete?: any): unknown;
|
||||
}
|
||||
|
||||
export declare type NgIterable<T> = Array<T> | Iterable<T>;
|
||||
`
|
||||
};
|
||||
}
|
||||
|
||||
@@ -113,10 +113,10 @@ export function angularAnimationsDts(): TestFile {
|
||||
return {
|
||||
name: absoluteFrom('/node_modules/@angular/animations/index.d.ts'),
|
||||
contents: `
|
||||
export declare class AnimationEvent {
|
||||
element: any;
|
||||
}
|
||||
`
|
||||
export declare class AnimationEvent {
|
||||
element: any;
|
||||
}
|
||||
`
|
||||
};
|
||||
}
|
||||
|
||||
@@ -136,25 +136,25 @@ export function ngForDts(): TestFile {
|
||||
return {
|
||||
name: absoluteFrom('/ngfor.d.ts'),
|
||||
contents: `
|
||||
export declare class NgForOf<T> {
|
||||
ngForOf: T[];
|
||||
ngForTrackBy: TrackByFunction<T>;
|
||||
static ngTemplateContextGuard<T>(dir: NgForOf<T>, ctx: any): ctx is NgForOfContext<T>;
|
||||
}
|
||||
|
||||
export interface TrackByFunction<T> {
|
||||
(index: number, item: T): any;
|
||||
}
|
||||
|
||||
export declare class NgForOfContext<T> {
|
||||
$implicit: T;
|
||||
index: number;
|
||||
count: number;
|
||||
readonly odd: boolean;
|
||||
readonly even: boolean;
|
||||
readonly first: boolean;
|
||||
readonly last: boolean;
|
||||
}`,
|
||||
export declare class NgForOf<T> {
|
||||
ngForOf: T[];
|
||||
ngForTrackBy: TrackByFunction<T>;
|
||||
static ngTemplateContextGuard<T>(dir: NgForOf<T>, ctx: any): ctx is NgForOfContext<T>;
|
||||
}
|
||||
|
||||
export interface TrackByFunction<T> {
|
||||
(index: number, item: T): any;
|
||||
}
|
||||
|
||||
export declare class NgForOfContext<T> {
|
||||
$implicit: T;
|
||||
index: number;
|
||||
count: number;
|
||||
readonly odd: boolean;
|
||||
readonly even: boolean;
|
||||
readonly first: boolean;
|
||||
readonly last: boolean;
|
||||
}`,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import * as ts from 'typescript';
|
||||
import {ErrorCode, ngErrorCode} from '../../src/ngtsc/diagnostics';
|
||||
import {absoluteFrom as _, getFileSystem, getSourceFileOrError} from '../../src/ngtsc/file_system';
|
||||
import {runInEachFileSystem} from '../../src/ngtsc/file_system/testing';
|
||||
import {expectCompleteReuse, loadStandardTestFiles} from '../../src/ngtsc/testing';
|
||||
import {expectCompleteReuse, getSourceCodeForDiagnostic, loadStandardTestFiles} from '../../src/ngtsc/testing';
|
||||
|
||||
import {NgtscTestEnvironment} from './env';
|
||||
|
||||
@@ -2506,8 +2506,3 @@ export declare class AnimationEvent {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function getSourceCodeForDiagnostic(diag: ts.Diagnostic): string {
|
||||
const text = diag.file!.text;
|
||||
return text.substr(diag.start!, diag.length!);
|
||||
}
|
||||
|
||||
@@ -203,11 +203,15 @@ export class NullVisitor implements Visitor<void> {
|
||||
export class RecursiveVisitor implements Visitor<void> {
|
||||
visitElement(element: Element): void {
|
||||
visitAll(this, element.attributes);
|
||||
visitAll(this, element.inputs);
|
||||
visitAll(this, element.outputs);
|
||||
visitAll(this, element.children);
|
||||
visitAll(this, element.references);
|
||||
}
|
||||
visitTemplate(template: Template): void {
|
||||
visitAll(this, template.attributes);
|
||||
visitAll(this, template.inputs);
|
||||
visitAll(this, template.outputs);
|
||||
visitAll(this, template.children);
|
||||
visitAll(this, template.references);
|
||||
visitAll(this, template.variables);
|
||||
|
||||
@@ -624,7 +624,7 @@ const _shadowDOMSelectorsRe = [
|
||||
// Support for `>>>`, `deep`, `::ng-deep` is then also deprecated and will be removed in the future.
|
||||
// see https://github.com/angular/angular/pull/17677
|
||||
const _shadowDeepSelectors = /(?:>>>)|(?:\/deep\/)|(?:::ng-deep)/g;
|
||||
const _selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$';
|
||||
const _selectorReSuffix = '([>\\s~+[.,{:][\\s\\S]*)?$';
|
||||
const _polyfillHostRe = /-shadowcsshost/gim;
|
||||
const _colonHostRe = /:host/gim;
|
||||
const _colonHostContextRe = /:host-context/gim;
|
||||
|
||||
@@ -24,7 +24,7 @@ import {componentFactoryResolverProviderDef, depDef, lifecycleHookToNodeFlag, pr
|
||||
|
||||
const CLASS_ATTR = 'class';
|
||||
const STYLE_ATTR = 'style';
|
||||
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
|
||||
const IMPLICIT_TEMPLATE_VAR = '$implicit';
|
||||
|
||||
export class ViewCompileResult {
|
||||
constructor(public viewClassVar: string, public rendererTypeVar: string) {}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rxjs": "^6.5.3",
|
||||
"rxjs": "^6.5.3 || ^7.0.0",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"repository": {
|
||||
|
||||
@@ -44,16 +44,16 @@ export function _localeFactory(locale?: string): string {
|
||||
/**
|
||||
* Work out the locale from the potential global properties.
|
||||
*
|
||||
* * Closure Compiler: use `goog.LOCALE`.
|
||||
* * Closure Compiler: use `goog.getLocale()`.
|
||||
* * Ivy enabled: use `$localize.locale`
|
||||
*/
|
||||
export function getGlobalLocale(): string {
|
||||
if (typeof ngI18nClosureMode !== 'undefined' && ngI18nClosureMode &&
|
||||
typeof goog !== 'undefined' && goog.LOCALE !== 'en') {
|
||||
// * The default `goog.LOCALE` value is `en`, while Angular used `en-US`.
|
||||
typeof goog !== 'undefined' && goog.getLocale() !== 'en') {
|
||||
// * The default `goog.getLocale()` value is `en`, while Angular used `en-US`.
|
||||
// * In order to preserve backwards compatibility, we use Angular default value over
|
||||
// Closure Compiler's one.
|
||||
return goog.LOCALE;
|
||||
return goog.getLocale();
|
||||
} else {
|
||||
// KEEP `typeof $localize !== 'undefined' && $localize.locale` IN SYNC WITH THE LOCALIZE
|
||||
// COMPILE-TIME INLINER.
|
||||
|
||||
@@ -336,6 +336,7 @@ export function renderView<T>(tView: TView, lView: LView, context: T): void {
|
||||
// an error, mark the view as corrupted so we can try to recover.
|
||||
if (tView.firstCreatePass) {
|
||||
tView.incompleteFirstPass = true;
|
||||
tView.firstCreatePass = false;
|
||||
}
|
||||
|
||||
throw error;
|
||||
|
||||
@@ -187,7 +187,7 @@ describe('property bindings', () => {
|
||||
})
|
||||
class OtherDir {
|
||||
@Input() id: number|undefined;
|
||||
@Output('click') clickStream = new EventEmitter();
|
||||
@Output('click') clickStream = new EventEmitter<void>();
|
||||
}
|
||||
|
||||
@Directive({
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {ChangeDetectorRef, Component, ComponentFactoryResolver, Directive, EmbeddedViewRef, Injector, Input, NgModule, TemplateRef, ViewChild, ViewContainerRef, ViewRef} from '@angular/core';
|
||||
import {ChangeDetectorRef, Component, ComponentFactoryResolver, Directive, EmbeddedViewRef, Injectable, Injector, Input, NgModule, TemplateRef, ViewChild, ViewContainerRef, ViewRef} from '@angular/core';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {By} from '@angular/platform-browser';
|
||||
import {onlyInIvy} from '@angular/private/testing';
|
||||
@@ -886,5 +886,46 @@ describe('view insertion', () => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.textContent).toContain('2');
|
||||
});
|
||||
|
||||
it('should consistently report errors raised by createEmbeddedView', () => {
|
||||
// Intentionally hasn't been added to `providers` so that it throws a DI error.
|
||||
@Injectable()
|
||||
class DoesNotExist {
|
||||
}
|
||||
|
||||
@Directive({selector: 'dir'})
|
||||
class Dir {
|
||||
constructor(willCauseError: DoesNotExist) {}
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<ng-template #broken>
|
||||
<dir></dir>
|
||||
</ng-template>
|
||||
`,
|
||||
})
|
||||
class App {
|
||||
@ViewChild('broken') template !: TemplateRef<unknown>;
|
||||
|
||||
constructor(private _viewContainerRef: ViewContainerRef) {}
|
||||
|
||||
insertTemplate() {
|
||||
this._viewContainerRef.createEmbeddedView(this.template);
|
||||
}
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [App, Dir]});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
const tryRender = () => {
|
||||
fixture.componentInstance.insertTemplate();
|
||||
fixture.detectChanges();
|
||||
};
|
||||
fixture.detectChanges();
|
||||
|
||||
// We try to render the same template twice to ensure that we get consistent error messages.
|
||||
expect(tryRender).toThrowError(/No provider for DoesNotExist/);
|
||||
expect(tryRender).toThrowError(/No provider for DoesNotExist/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"peerDependencies": {
|
||||
"@angular/core": "0.0.0-PLACEHOLDER",
|
||||
"@angular/platform-browser": "0.0.0-PLACEHOLDER",
|
||||
"rxjs": "^6.5.3"
|
||||
"rxjs": "^6.5.3 || ^7.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"@angular/core": "0.0.0-PLACEHOLDER",
|
||||
"@angular/common": "0.0.0-PLACEHOLDER",
|
||||
"@angular/platform-browser": "0.0.0-PLACEHOLDER",
|
||||
"rxjs": "^6.5.3"
|
||||
"rxjs": "^6.5.3 || ^7.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
Vendored
+1
@@ -18,6 +18,7 @@ declare namespace goog {
|
||||
export const DEBUG: boolean;
|
||||
export const LOCALE: string;
|
||||
export const getMsg: (input: string, placeholders?: {[key: string]: string}) => string;
|
||||
export const getLocale: () => string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user