diff --git a/adev/src/app/features/update/update.component.ts b/adev/src/app/features/update/update.component.ts
index 859823f94696..3ece43fd12b4 100644
--- a/adev/src/app/features/update/update.component.ts
+++ b/adev/src/app/features/update/update.component.ts
@@ -128,8 +128,10 @@ export default class UpdateComponent {
}
}
- @HostListener('click', ['$event.target'])
- copyCode({tagName, textContent}: Element) {
+ @HostListener('click', ['$event'])
+ copyCode(event: Event) {
+ const {tagName, textContent} = event.target as Element;
+
if (tagName === 'CODE') {
this.clipboard.copy(textContent!);
this.snackBar.open('Copied to clipboard', '', {duration: 2000});
diff --git a/modules/tsconfig.json b/modules/tsconfig.json
index 06843a9c265c..2a4d54e4ad57 100644
--- a/modules/tsconfig.json
+++ b/modules/tsconfig.json
@@ -29,7 +29,6 @@
],
"angularCompilerOptions": {
"strictTemplates": true,
- "skipTemplateCodegen": true,
- "typeCheckHostBindings": true
+ "skipTemplateCodegen": true
}
}
diff --git a/packages/compiler-cli/src/ngtsc/core/src/compiler.ts b/packages/compiler-cli/src/ngtsc/core/src/compiler.ts
index 6b454d135756..473cfc980766 100644
--- a/packages/compiler-cli/src/ngtsc/core/src/compiler.ts
+++ b/packages/compiler-cli/src/ngtsc/core/src/compiler.ts
@@ -1461,7 +1461,7 @@ export class NgCompiler {
const supportJitMode = this.options['supportJitMode'] ?? true;
const supportTestBed = this.options['supportTestBed'] ?? true;
const externalRuntimeStyles = this.options['externalRuntimeStyles'] ?? false;
- const typeCheckHostBindings = this.options.typeCheckHostBindings ?? false;
+ const typeCheckHostBindings = this.options.typeCheckHostBindings ?? true;
// Libraries compiled in partial mode could potentially be used with TestBed within an
// application. Since this is not known at library compilation time, support is required to
diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/GOLDEN_PARTIAL.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/GOLDEN_PARTIAL.js
index 7be10608361c..30471a3d347f 100644
--- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/GOLDEN_PARTIAL.js
+++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/GOLDEN_PARTIAL.js
@@ -18,7 +18,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDE
export class MyCmp {
}
MyCmp.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyCmp, deps: [], target: i0.ɵɵFactoryTarget.Component });
-MyCmp.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: MyCmp, isStandalone: true, selector: "my-cmp", host: { attributes: { "literal1": "foo" }, listeners: { "event1": "foo()" }, properties: { "attr.attr1": "foo", "prop1": "foo", "class.class1": "false", "style.style1": "true", "class": "foo", "style": "foo" } }, ngImport: i0, template: `
+MyCmp.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: MyCmp, isStandalone: true, selector: "my-cmp", host: { attributes: { "literal1": "foo" }, listeners: { "event1": "foo()" }, properties: { "attr.attr1": "foo", "id": "foo", "class.class1": "false", "style.style1": "true", "class": "foo", "style": "foo" } }, ngImport: i0, template: `
- `
+ `,
}]
}] });
diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/TEST_CASES.json b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/TEST_CASES.json
index 4e6d7d97036b..bc1d30d9ce1a 100644
--- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/TEST_CASES.json
+++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/TEST_CASES.json
@@ -1,20 +1,15 @@
{
- "$schema": "../test_case_schema.json",
- "cases": [
- {
- "description": "should emit bindings in the correct order",
- "inputFiles": [
- "order_bindings.ts"
- ],
- "expectations": [
- {
- "failureMessage": "Invalid binding code",
- "files": [
- "order_bindings.js"
- ]
- }
- ]
- }
- ]
- }
-
\ No newline at end of file
+ "$schema": "../test_case_schema.json",
+ "cases": [
+ {
+ "description": "should emit bindings in the correct order",
+ "inputFiles": ["order_bindings.ts"],
+ "expectations": [
+ {
+ "failureMessage": "Invalid binding code",
+ "files": ["order_bindings.js"]
+ }
+ ]
+ }
+ ]
+}
diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/GOLDEN_PARTIAL.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/GOLDEN_PARTIAL.js
index 86d3d4163abd..f8bc2487c9de 100644
--- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/GOLDEN_PARTIAL.js
+++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/GOLDEN_PARTIAL.js
@@ -51,14 +51,18 @@ export declare class MyModule {
import { Directive, NgModule } from '@angular/core';
import * as i0 from "@angular/core";
export class HostBindingDir {
+ constructor() {
+ this.getData = () => undefined;
+ }
}
HostBindingDir.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: HostBindingDir, deps: [], target: i0.ɵɵFactoryTarget.Directive });
HostBindingDir.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: HostBindingDir, isStandalone: false, selector: "[hostBindingDir]", host: { properties: { "id": "getData()?.id" } }, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: HostBindingDir, decorators: [{
type: Directive,
args: [{
- selector: '[hostBindingDir]', host: { '[id]': 'getData()?.id' },
- standalone: false
+ selector: '[hostBindingDir]',
+ host: { '[id]': 'getData()?.id' },
+ standalone: false,
}]
}] });
export class MyModule {
@@ -76,9 +80,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDE
****************************************************************************************************/
import * as i0 from "@angular/core";
export declare class HostBindingDir {
- getData?: () => {
+ getData: () => {
id: number;
- };
+ } | undefined;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵdir: i0.ɵɵDirectiveDeclaration;
}
@@ -620,8 +624,8 @@ export declare class MyDirective {
import { Component, HostListener } from '@angular/core';
import * as i0 from "@angular/core";
export class MyComponent {
- start() {
- }
+ start() { }
+ done() { }
}
MyComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
MyComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: MyComponent, isStandalone: false, selector: "my-comp", host: { listeners: { "@animation.done": "done()", "@animation.start": "start()" } }, ngImport: i0, template: '', isInline: true });
@@ -633,7 +637,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDE
host: {
'(@animation.done)': 'done()',
},
- standalone: false
+ standalone: false,
}]
}], propDecorators: { start: [{
type: HostListener,
@@ -646,6 +650,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDE
import * as i0 from "@angular/core";
export declare class MyComponent {
start(): void;
+ done(): void;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
@@ -656,10 +661,11 @@ export declare class MyComponent {
import { Component, HostListener } from '@angular/core';
import * as i0 from "@angular/core";
export class MyComponent {
- start() {
- }
- click() {
- }
+ start() { }
+ click() { }
+ mousedown() { }
+ done() { }
+ mouseup() { }
}
MyComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
MyComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: MyComponent, isStandalone: false, selector: "my-comp", host: { listeners: { "mousedown": "mousedown()", "@animation.done": "done()", "mouseup": "mouseup()", "@animation.start": "start()", "click": "click()" } }, ngImport: i0, template: '', isInline: true });
@@ -673,7 +679,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDE
'(@animation.done)': 'done()',
'(mouseup)': 'mouseup()',
},
- standalone: false
+ standalone: false,
}]
}], propDecorators: { start: [{
type: HostListener,
@@ -690,6 +696,9 @@ import * as i0 from "@angular/core";
export declare class MyComponent {
start(): void;
click(): void;
+ mousedown(): void;
+ done(): void;
+ mouseup(): void;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
@@ -837,40 +846,55 @@ export declare class MyModule {
****************************************************************************************************/
import { Directive } from '@angular/core';
import * as i0 from "@angular/core";
-export class HostBindingDir {
+export class HostBindingLinkDir {
constructor() {
this.evil = 'evil';
}
}
-HostBindingDir.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: HostBindingDir, deps: [], target: i0.ɵɵFactoryTarget.Directive });
-HostBindingDir.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: HostBindingDir, isStandalone: true, selector: "[hostBindingDir]", host: { properties: { "innerHtml": "evil", "href": "evil", "attr.style": "evil", "src": "evil", "sandbox": "evil" } }, ngImport: i0 });
-i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: HostBindingDir, decorators: [{
+HostBindingLinkDir.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: HostBindingLinkDir, deps: [], target: i0.ɵɵFactoryTarget.Directive });
+HostBindingLinkDir.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: HostBindingLinkDir, isStandalone: true, selector: "a[hostBindingLinkDir]", host: { properties: { "innerHtml": "evil", "href": "evil", "attr.style": "evil" } }, ngImport: i0 });
+i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: HostBindingLinkDir, decorators: [{
type: Directive,
args: [{
- selector: '[hostBindingDir]',
+ selector: 'a[hostBindingLinkDir]',
host: {
'[innerHtml]': 'evil',
'[href]': 'evil',
'[attr.style]': 'evil',
+ },
+ }]
+ }] });
+export class HostBindingImageDir {
+ constructor() {
+ this.evil = 'evil';
+ }
+}
+HostBindingImageDir.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: HostBindingImageDir, deps: [], target: i0.ɵɵFactoryTarget.Directive });
+HostBindingImageDir.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: HostBindingImageDir, isStandalone: true, selector: "img[hostBindingImgDir]", host: { properties: { "innerHtml": "evil", "attr.style": "evil", "src": "evil" } }, ngImport: i0 });
+i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: HostBindingImageDir, decorators: [{
+ type: Directive,
+ args: [{
+ selector: 'img[hostBindingImgDir]',
+ host: {
+ '[innerHtml]': 'evil',
+ '[attr.style]': 'evil',
'[src]': 'evil',
- '[sandbox]': 'evil',
},
}]
}] });
-export class HostBindingDir2 {
+export class HostBindingIframeDir {
constructor() {
this.evil = 'evil';
}
}
-HostBindingDir2.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: HostBindingDir2, deps: [], target: i0.ɵɵFactoryTarget.Directive });
-HostBindingDir2.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: HostBindingDir2, isStandalone: true, selector: "a", host: { properties: { "innerHtml": "evil", "href": "evil", "attr.style": "evil", "src": "evil", "sandbox": "evil" } }, ngImport: i0 });
-i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: HostBindingDir2, decorators: [{
+HostBindingIframeDir.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: HostBindingIframeDir, deps: [], target: i0.ɵɵFactoryTarget.Directive });
+HostBindingIframeDir.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: HostBindingIframeDir, isStandalone: true, selector: "iframe[hostBindingIframeDir]", host: { properties: { "innerHtml": "evil", "attr.style": "evil", "src": "evil", "sandbox": "evil" } }, ngImport: i0 });
+i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: HostBindingIframeDir, decorators: [{
type: Directive,
args: [{
- selector: 'a',
+ selector: 'iframe[hostBindingIframeDir]',
host: {
'[innerHtml]': 'evil',
- '[href]': 'evil',
'[attr.style]': 'evil',
'[src]': 'evil',
'[sandbox]': 'evil',
@@ -882,15 +906,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDE
* PARTIAL FILE: sanitization.d.ts
****************************************************************************************************/
import * as i0 from "@angular/core";
-export declare class HostBindingDir {
+export declare class HostBindingLinkDir {
evil: string;
- static ɵfac: i0.ɵɵFactoryDeclaration;
- static ɵdir: i0.ɵɵDirectiveDeclaration;
+ static ɵfac: i0.ɵɵFactoryDeclaration;
+ static ɵdir: i0.ɵɵDirectiveDeclaration;
}
-export declare class HostBindingDir2 {
+export declare class HostBindingImageDir {
evil: string;
- static ɵfac: i0.ɵɵFactoryDeclaration;
- static ɵdir: i0.ɵɵDirectiveDeclaration;
+ static ɵfac: i0.ɵɵFactoryDeclaration;
+ static ɵdir: i0.ɵɵDirectiveDeclaration;
+}
+export declare class HostBindingIframeDir {
+ evil: string;
+ static ɵfac: i0.ɵɵFactoryDeclaration;
+ static ɵdir: i0.ɵɵDirectiveDeclaration;
}
/****************************************************************************************************
diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/chain_synthetic_listeners.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/chain_synthetic_listeners.ts
index fc4e87ab3b37..eb48b47bff00 100644
--- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/chain_synthetic_listeners.ts
+++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/chain_synthetic_listeners.ts
@@ -1,15 +1,16 @@
import {Component, HostListener} from '@angular/core';
@Component({
- selector: 'my-comp',
- template: '',
- host: {
- '(@animation.done)': 'done()',
- },
- standalone: false
+ selector: 'my-comp',
+ template: '',
+ host: {
+ '(@animation.done)': 'done()',
+ },
+ standalone: false,
})
export class MyComponent {
@HostListener('@animation.start')
- start() {
- }
+ start() {}
+
+ done() {}
}
diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/chain_synthetic_listeners_mixed.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/chain_synthetic_listeners_mixed.ts
index ee760cfbf78d..9ab3ebb2354f 100644
--- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/chain_synthetic_listeners_mixed.ts
+++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/chain_synthetic_listeners_mixed.ts
@@ -1,21 +1,23 @@
import {Component, HostListener} from '@angular/core';
@Component({
- selector: 'my-comp',
- template: '',
- host: {
- '(mousedown)': 'mousedown()',
- '(@animation.done)': 'done()',
- '(mouseup)': 'mouseup()',
- },
- standalone: false
+ selector: 'my-comp',
+ template: '',
+ host: {
+ '(mousedown)': 'mousedown()',
+ '(@animation.done)': 'done()',
+ '(mouseup)': 'mouseup()',
+ },
+ standalone: false,
})
export class MyComponent {
@HostListener('@animation.start')
- start() {
- }
+ start() {}
@HostListener('click')
- click() {
- }
+ click() {}
+
+ mousedown() {}
+ done() {}
+ mouseup() {}
}
diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/host_bindings_with_temporaries.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/host_bindings_with_temporaries.ts
index 03d899d1bf44..990aa2c5f0e5 100644
--- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/host_bindings_with_temporaries.ts
+++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/host_bindings_with_temporaries.ts
@@ -1,15 +1,17 @@
import {Directive, NgModule} from '@angular/core';
@Directive({
- selector: '[hostBindingDir]', host: { '[id]': 'getData()?.id' },
- standalone: false
+ selector: '[hostBindingDir]',
+ host: {'[id]': 'getData()?.id'},
+ standalone: false,
})
export class HostBindingDir {
- getData?: () => {
- id: number
- };
+ getData: () =>
+ | {
+ id: number;
+ }
+ | undefined = () => undefined;
}
@NgModule({declarations: [HostBindingDir]})
-export class MyModule {
-}
+export class MyModule {}
diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/sanitization.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/sanitization.js
index 8af169be19ab..ca216aacac71 100644
--- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/sanitization.js
+++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/sanitization.js
@@ -1,13 +1,20 @@
-hostBindings: function HostBindingDir_HostBindings(rf, ctx) {
+hostBindings: function HostBindingLinkDir_HostBindings(rf, ctx) {
if (rf & 2) {
- $r3$.ɵɵdomProperty("innerHTML", ctx.evil, $r3$.ɵɵsanitizeHtml)("href", ctx.evil, $r3$.ɵɵsanitizeUrlOrResourceUrl)("src", ctx.evil, $r3$.ɵɵsanitizeUrlOrResourceUrl)("sandbox", ctx.evil, $r3$.ɵɵvalidateIframeAttribute);
+ $r3$.ɵɵdomProperty("innerHTML", ctx.evil, $r3$.ɵɵsanitizeHtml)("href", ctx.evil, $r3$.ɵɵsanitizeUrl);
$r3$.ɵɵattribute("style", ctx.evil, $r3$.ɵɵsanitizeStyle);
- }
+ }
}
…
-hostBindings: function HostBindingDir2_HostBindings(rf, ctx) {
+hostBindings: function HostBindingImageDir_HostBindings(rf, ctx) {
if (rf & 2) {
- $r3$.ɵɵdomProperty("innerHTML", ctx.evil, $r3$.ɵɵsanitizeHtml)("href", ctx.evil, $r3$.ɵɵsanitizeUrl)("src", ctx.evil)("sandbox", ctx.evil, $r3$.ɵɵvalidateIframeAttribute);
+ $r3$.ɵɵdomProperty("innerHTML", ctx.evil, $r3$.ɵɵsanitizeHtml)("src", ctx.evil, $r3$.ɵɵsanitizeUrl);
$r3$.ɵɵattribute("style", ctx.evil, $r3$.ɵɵsanitizeStyle);
- }
+ }
+}
+…
+hostBindings: function HostBindingIframeDir_HostBindings(rf, ctx) {
+ if (rf & 2) {
+ $r3$.ɵɵdomProperty("innerHTML", ctx.evil, $r3$.ɵɵsanitizeHtml)("src", ctx.evil, $r3$.ɵɵsanitizeResourceUrl)("sandbox", ctx.evil, $r3$.ɵɵvalidateIframeAttribute);
+ $r3$.ɵɵattribute("style", ctx.evil, $r3$.ɵɵsanitizeStyle);
+ }
}
diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/sanitization.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/sanitization.ts
index 4e63f7287d8c..7afa74caf8a1 100644
--- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/sanitization.ts
+++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/sanitization.ts
@@ -1,29 +1,38 @@
import {Directive} from '@angular/core';
@Directive({
- selector: '[hostBindingDir]',
+ selector: 'a[hostBindingLinkDir]',
host: {
'[innerHtml]': 'evil',
'[href]': 'evil',
'[attr.style]': 'evil',
+ },
+})
+export class HostBindingLinkDir {
+ evil = 'evil';
+}
+
+@Directive({
+ selector: 'img[hostBindingImgDir]',
+ host: {
+ '[innerHtml]': 'evil',
+ '[attr.style]': 'evil',
'[src]': 'evil',
- '[sandbox]': 'evil',
},
})
-export class HostBindingDir {
+export class HostBindingImageDir {
evil = 'evil';
}
@Directive({
- selector: 'a',
+ selector: 'iframe[hostBindingIframeDir]',
host: {
'[innerHtml]': 'evil',
- '[href]': 'evil',
'[attr.style]': 'evil',
'[src]': 'evil',
'[sandbox]': 'evil',
},
})
-export class HostBindingDir2 {
+export class HostBindingIframeDir {
evil = 'evil';
}
diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/order_bindings.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/order_bindings.js
index e6f46855999e..5f9d09436666 100644
--- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/order_bindings.js
+++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/order_bindings.js
@@ -5,7 +5,7 @@ function MyCmp_HostBindings(rf, ctx) {
$r3$.ɵɵlistener("event1", function MyCmp_event1_HostBindingHandler() { return ctx.foo(); });
}
if (rf & 2) {
- $r3$.ɵɵdomProperty("prop1", ctx.foo);
+ $r3$.ɵɵdomProperty("id", ctx.foo);
$r3$.ɵɵattribute("attr1", ctx.foo);
$r3$.ɵɵstyleMap(ctx.foo);
$r3$.ɵɵclassMap(ctx.foo);
diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/order_bindings.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/order_bindings.ts
index 5129ae86b742..544261691bbb 100644
--- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/order_bindings.ts
+++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/order_bindings.ts
@@ -5,8 +5,7 @@ import {Component} from '@angular/core';
template: ``,
inputs: ['attr1', 'prop1', 'attrInterp1', 'propInterp1'],
})
-export class SomeCmp {
-}
+export class SomeCmp {}
@Component({
selector: 'my-cmp',
@@ -15,7 +14,7 @@ export class SomeCmp {
'literal1': 'foo',
'(event1)': 'foo()',
'[attr.attr1]': 'foo',
- '[prop1]': 'foo',
+ '[id]': 'foo',
'[class.class1]': 'false',
'[style.style1]': 'true',
'[class]': 'foo',
@@ -34,7 +33,7 @@ export class SomeCmp {
attr.attrInterp1="interp {{foo}}"
propInterp1="interp {{foo}}"
/>
- `
+ `,
})
export class MyCmp {
foo: any;
diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/host_bindings/GOLDEN_PARTIAL.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/host_bindings/GOLDEN_PARTIAL.js
index ab139dc5bde4..f60c678473b5 100644
--- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/host_bindings/GOLDEN_PARTIAL.js
+++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/host_bindings/GOLDEN_PARTIAL.js
@@ -153,7 +153,7 @@ export class MyComponent {
}
}
MyComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
-MyComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: MyComponent, isStandalone: false, selector: "my-component", host: { properties: { "style!important": "myStyleExp", "class!important": "myClassExp", "class.foo!important": "this.myFooClassExp", "style.width!important": "this.myWidthExp" } }, ngImport: i0, template: `
+MyComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: MyComponent, isStandalone: false, selector: "my-component", host: { properties: { "style.width!important": "this.myWidthExp", "class.baz!important": "myClassExp", "class.foo!important": "this.myFooClassExp" } }, ngImport: i0, template: `
`, isInline: true });
@@ -165,8 +165,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDE
`,
- host: { '[style!important]': 'myStyleExp', '[class!important]': 'myClassExp' },
- standalone: false
+ host: { '[style.width!important]': 'myStyleExp', '[class.baz!important]': 'myClassExp' },
+ standalone: false,
}]
}], propDecorators: { myFooClassExp: [{
type: HostBinding,
diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/host_bindings/important.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/host_bindings/important.ts
index f1c5f4cf987e..43a8bcdc7c0e 100644
--- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/host_bindings/important.ts
+++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/host_bindings/important.ts
@@ -1,13 +1,13 @@
import {Component, HostBinding, NgModule} from '@angular/core';
@Component({
- selector: 'my-component',
- template: `
+ selector: 'my-component',
+ template: `
`,
- host: { '[style!important]': 'myStyleExp', '[class!important]': 'myClassExp' },
- standalone: false
+ host: {'[style.width!important]': 'myStyleExp', '[class.baz!important]': 'myClassExp'},
+ standalone: false,
})
export class MyComponent {
myStyleExp = '';
@@ -22,5 +22,4 @@ export class MyComponent {
}
@NgModule({declarations: [MyComponent]})
-export class MyModule {
-}
+export class MyModule {}
diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/host_bindings/important_template.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/host_bindings/important_template.js
index 3e6efb395c5b..b6463c99c559 100644
--- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/host_bindings/important_template.js
+++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/host_bindings/important_template.js
@@ -1,10 +1,8 @@
-hostVars: 8,
+hostVars: 6,
hostBindings: function MyComponent_HostBindings(rf, ctx) {
if (rf & 2) {
- $r3$.ɵɵstyleMap(ctx.myStyleExp);
- $r3$.ɵɵclassMap(ctx.myClassExp);
$r3$.ɵɵstyleProp("width", ctx.myWidthExp);
- $r3$.ɵɵclassProp("foo", ctx.myFooClassExp);
+ $r3$.ɵɵclassProp("baz", ctx.myClassExp)("foo", ctx.myFooClassExp);
}
},
diff --git a/packages/compiler-cli/test/ngtsc/host_bindings_type_check_spec.ts b/packages/compiler-cli/test/ngtsc/host_bindings_type_check_spec.ts
index d1e76b91a069..d1aa2a8797af 100644
--- a/packages/compiler-cli/test/ngtsc/host_bindings_type_check_spec.ts
+++ b/packages/compiler-cli/test/ngtsc/host_bindings_type_check_spec.ts
@@ -24,9 +24,6 @@ runInEachFileSystem(() => {
beforeEach(() => {
env = NgtscTestEnvironment.setup(testFiles);
env.tsconfig({
- // Necessary for testing host bindings.
- typeCheckHostBindings: true,
-
// Not required for host bindings, but they allow us to
// exercise more parts of the type checker.
strictTemplates: true,
diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
index 6937bdb921c1..5b079aff995e 100644
--- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
+++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
@@ -5340,13 +5340,13 @@ runInEachFileSystem((os: string) => {
})
class FooCmp {
@HostListener('click')
- onClick(event: any): void {}
+ onClick(): void {}
@HostListener('document:click', ['$event.target'])
- onDocumentClick(eventTarget: HTMLElement): void {}
+ onDocumentClick(eventTarget: EventTarget | null): void {}
@HostListener('window:scroll')
- onWindowScroll(event: any): void {}
+ onWindowScroll(): void {}
}
`,
);
@@ -5375,7 +5375,7 @@ runInEachFileSystem((os: string) => {
})
class FooCmp {
@HostListener('UnknownTarget:click')
- onClick(event: any): void {}
+ onClick(): void {}
}
`,
);
@@ -5466,17 +5466,24 @@ runInEachFileSystem((os: string) => {
'[attr.hello]': 'foo',
'(click)': 'onClick($event)',
'(body:click)': 'onBodyClick($event)',
- '[prop]': 'bar',
+ '[id]': 'bar',
},
})
class FooCmp {
+ arg1: any;
+ arg2: any;
+ arg3: any;
+ foo: any;
+ bar: any;
+
onClick(event: any): void {}
+ onBodyClick(event: any): void {}
@HostBinding('class.someclass')
get someClass(): boolean { return false; }
- @HostListener('change', ['arg1', 'arg2', 'arg3'])
- onChange(event: any, arg: any): void {}
+ @HostListener('change', ['$event', 'arg1', 'arg2', 'arg3'])
+ onChange(event: any, arg1: any, arg2: any, arg3: any): void {}
}
`,
);
@@ -5487,10 +5494,10 @@ runInEachFileSystem((os: string) => {
hostVars: 4,
hostBindings: function FooCmp_HostBindings(rf, ctx) {
if (rf & 1) {
- i0.ɵɵlistener("click", function FooCmp_click_HostBindingHandler($event) { return ctx.onClick($event); })("click", function FooCmp_click_HostBindingHandler($event) { return ctx.onBodyClick($event); }, i0.ɵɵresolveBody)("change", function FooCmp_change_HostBindingHandler() { return ctx.onChange(ctx.arg1, ctx.arg2, ctx.arg3); });
+ i0.ɵɵlistener("click", function FooCmp_click_HostBindingHandler($event) { return ctx.onClick($event); })("click", function FooCmp_click_HostBindingHandler($event) { return ctx.onBodyClick($event); }, i0.ɵɵresolveBody)("change", function FooCmp_change_HostBindingHandler($event) { return ctx.onChange($event, ctx.arg1, ctx.arg2, ctx.arg3); });
}
if (rf & 2) {
- i0.ɵɵdomProperty("prop", ctx.bar);
+ i0.ɵɵdomProperty("id", ctx.bar);
i0.ɵɵattribute("hello", ctx.foo);
i0.ɵɵclassProp("someclass", ctx.someClass);
}
@@ -5608,6 +5615,8 @@ runInEachFileSystem((os: string) => {
selector: '[test]',
})
class Dir {
+ arg: any;
+
@HostListener('change', ['$event', 'arg'])
onChange(event: any, arg: any): void {}
}
@@ -8471,29 +8480,19 @@ runInEachFileSystem((os: string) => {
expect(trim(jsContents)).toContain(trim(hostBindingsFn));
});
- it('should generate sanitizers for unsafe properties in hostBindings fn in Directives', () => {
+ it('should generate sanitizers for unsafe properties in hostBindings function in Directives', () => {
env.write(
`test.ts`,
`
- import {Component, Directive, HostBinding, Input, NgModule} from '@angular/core';
+ import {Component, Directive, HostBinding, Input} from '@angular/core';
@Directive({
- selector: '[unsafeProps]',
- standalone: false,
+ selector: 'a[unsafeProps]',
})
class UnsafePropsDirective {
@HostBinding('href')
propHref: string;
- @HostBinding('src')
- propSrc: string;
-
- @HostBinding('action')
- propAction: string;
-
- @HostBinding('profile')
- propProfile: string;
-
@HostBinding('innerHTML')
propInnerHTML: string;
@@ -8506,24 +8505,21 @@ runInEachFileSystem((os: string) => {
@Component({
selector: 'foo',
template: 'Link Title',
- standalone: false,
+ imports: [UnsafePropsDirective]
})
class FooCmp {
ctxProp = '';
}
-
- @NgModule({declarations: [FooCmp, UnsafePropsDirective]})
- class MyModule {}
`,
);
env.driveMain();
const jsContents = env.getContents('test.js');
const hostBindingsFn = `
- hostVars: 6,
+ hostVars: 3,
hostBindings: function UnsafePropsDirective_HostBindings(rf, ctx) {
if (rf & 2) {
- i0.ɵɵdomProperty("href", ctx.propHref, i0.ɵɵsanitizeUrlOrResourceUrl)("src", ctx.propSrc, i0.ɵɵsanitizeUrlOrResourceUrl)("action", ctx.propAction, i0.ɵɵsanitizeUrl)("profile", ctx.propProfile, i0.ɵɵsanitizeResourceUrl)("innerHTML", ctx.propInnerHTML, i0.ɵɵsanitizeHtml)("title", ctx.propSafeTitle);
+ i0.ɵɵdomProperty("href", ctx.propHref, i0.ɵɵsanitizeUrl)("innerHTML", ctx.propInnerHTML, i0.ɵɵsanitizeHtml)("title", ctx.propSafeTitle);
}
}
`;
@@ -8537,10 +8533,9 @@ runInEachFileSystem((os: string) => {
import {Component} from '@angular/core';
@Component({
- selector: 'foo',
+ selector: 'a[foo]',
template: 'Link Title',
host: {
- '[src]': 'srcProp',
'[href]': 'hrefProp',
'[title]': 'titleProp',
'[attr.src]': 'srcAttr',
@@ -8548,18 +8543,24 @@ runInEachFileSystem((os: string) => {
'[attr.title]': 'titleAttr',
}
})
- class FooCmp {}
+ class FooCmp {
+ hrefProp: any;
+ titleProp: any;
+ srcAttr: any;
+ hrefAttr: any;
+ titleAttr: any;
+ }
`,
);
env.driveMain();
const jsContents = env.getContents('test.js');
const hostBindingsFn = `
- hostVars: 6,
+ hostVars: 5,
hostBindings: function FooCmp_HostBindings(rf, ctx) {
if (rf & 2) {
- i0.ɵɵdomProperty("src", ctx.srcProp)("href", ctx.hrefProp)("title", ctx.titleProp);
- i0.ɵɵattribute("src", ctx.srcAttr)("href", ctx.hrefAttr)("title", ctx.titleAttr);
+ i0.ɵɵdomProperty("href", ctx.hrefProp, i0.ɵɵsanitizeUrl)("title", ctx.titleProp);
+ i0.ɵɵattribute("src", ctx.srcAttr)("href", ctx.hrefAttr, i0.ɵɵsanitizeUrl)("title", ctx.titleAttr);
}
}
`;
@@ -9759,6 +9760,7 @@ runInEachFileSystem((os: string) => {
import {Directive} from '@angular/core';
@Directive({
+ selector: 'iframe[someDir]',
host: {
'[sandbox]': "''",
'[attr.allow]': "''",
diff --git a/packages/language-service/test/completions_spec.ts b/packages/language-service/test/completions_spec.ts
index 9bfccf57690e..7710d31f5f75 100644
--- a/packages/language-service/test/completions_spec.ts
+++ b/packages/language-service/test/completions_spec.ts
@@ -2157,9 +2157,6 @@ describe('completions', () => {
`title!: string; hero!: number;`,
undefined,
`host: {'[title]': 'ti'},`,
- {
- typeCheckHostBindings: true,
- },
);
appFile.moveCursorToText(`'ti¦'`);
const completions = appFile.getCompletionsAtPosition();
@@ -2172,9 +2169,6 @@ describe('completions', () => {
`title!: string; hero!: number;`,
undefined,
`host: {'(click)': 't'},`,
- {
- typeCheckHostBindings: true,
- },
);
appFile.moveCursorToText(`'(click)': 't¦'`);
const completions = appFile.getCompletionsAtPosition();
@@ -2182,11 +2176,8 @@ describe('completions', () => {
});
it('should be able to complete inside `host` of a directive', () => {
- const {appFile} = setupInlineTemplate(
- '',
- '',
- {
- 'Dir': `
+ const {appFile} = setupInlineTemplate('', '', {
+ 'Dir': `
@Directive({
host: {'[title]': 'ti'},
})
@@ -2195,12 +2186,7 @@ describe('completions', () => {
hero!: number;
}
`,
- },
- undefined,
- {
- typeCheckHostBindings: true,
- },
- );
+ });
appFile.moveCursorToText(`'ti¦'`);
const completions = appFile.getCompletionsAtPosition();
expectContain(completions, ts.ScriptElementKind.memberVariableElement, ['title', 'hero']);
diff --git a/packages/language-service/test/definitions_spec.ts b/packages/language-service/test/definitions_spec.ts
index 130c9182add5..81bb653674fa 100644
--- a/packages/language-service/test/definitions_spec.ts
+++ b/packages/language-service/test/definitions_spec.ts
@@ -834,9 +834,7 @@ describe('definitions', () => {
};
const env = LanguageServiceTestEnv.setup();
- const project = createModuleAndProjectWithDeclarations(env, 'test', files, {
- typeCheckHostBindings: true,
- });
+ const project = createModuleAndProjectWithDeclarations(env, 'test', files);
const appFile = project.openFile('app.ts');
project.expectNoSourceDiagnostics();
@@ -868,9 +866,7 @@ describe('definitions', () => {
};
const env = LanguageServiceTestEnv.setup();
- const project = createModuleAndProjectWithDeclarations(env, 'test', files, {
- typeCheckHostBindings: true,
- });
+ const project = createModuleAndProjectWithDeclarations(env, 'test', files);
const appFile = project.openFile('app.ts');
project.expectNoSourceDiagnostics();
@@ -901,9 +897,7 @@ describe('definitions', () => {
};
const env = LanguageServiceTestEnv.setup();
- const project = createModuleAndProjectWithDeclarations(env, 'test', files, {
- typeCheckHostBindings: true,
- });
+ const project = createModuleAndProjectWithDeclarations(env, 'test', files);
const dirFile = project.openFile('dir.ts');
project.expectNoSourceDiagnostics();
diff --git a/packages/language-service/test/gettcb_spec.ts b/packages/language-service/test/gettcb_spec.ts
index 76bdebbb1f59..9411178c0c15 100644
--- a/packages/language-service/test/gettcb_spec.ts
+++ b/packages/language-service/test/gettcb_spec.ts
@@ -93,9 +93,7 @@ describe('get typecheck block', () => {
}`,
};
const env = LanguageServiceTestEnv.setup();
- const project = createModuleAndProjectWithDeclarations(env, 'test', files, {
- typeCheckHostBindings: true,
- });
+ const project = createModuleAndProjectWithDeclarations(env, 'test', files);
project.expectNoSourceDiagnostics();
const appFile = project.openFile('app.ts');
@@ -129,9 +127,7 @@ describe('get typecheck block', () => {
}`,
};
const env = LanguageServiceTestEnv.setup();
- const project = createModuleAndProjectWithDeclarations(env, 'test', files, {
- typeCheckHostBindings: true,
- });
+ const project = createModuleAndProjectWithDeclarations(env, 'test', files);
project.expectNoSourceDiagnostics();
const appFile = project.openFile('app.ts');
@@ -165,9 +161,7 @@ describe('get typecheck block', () => {
}`,
};
const env = LanguageServiceTestEnv.setup();
- const project = createModuleAndProjectWithDeclarations(env, 'test', files, {
- typeCheckHostBindings: true,
- });
+ const project = createModuleAndProjectWithDeclarations(env, 'test', files);
project.expectNoSourceDiagnostics();
const appFile = project.openFile('app.ts');
diff --git a/packages/language-service/test/quick_info_spec.ts b/packages/language-service/test/quick_info_spec.ts
index 7dfd2054efe6..fead6e2af1e0 100644
--- a/packages/language-service/test/quick_info_spec.ts
+++ b/packages/language-service/test/quick_info_spec.ts
@@ -951,13 +951,7 @@ describe('quick info', () => {
expectedDisplayString: string;
expectedSpanText: string;
}) {
- const project = env.addProject(
- 'host-bindings',
- {'host-bindings.ts': source},
- {
- typeCheckHostBindings: true,
- },
- );
+ const project = env.addProject('host-bindings', {'host-bindings.ts': source});
const appFile = project.openFile('host-bindings.ts');
appFile.moveCursorToText(moveTo);
diff --git a/packages/language-service/test/references_and_rename_spec.ts b/packages/language-service/test/references_and_rename_spec.ts
index b5f7eda3a9c2..e54aaa28c11c 100644
--- a/packages/language-service/test/references_and_rename_spec.ts
+++ b/packages/language-service/test/references_and_rename_spec.ts
@@ -1540,9 +1540,7 @@ describe('find references and rename locations', () => {
`,
};
env = LanguageServiceTestEnv.setup();
- const project = createModuleAndProjectWithDeclarations(env, 'test', files, {
- typeCheckHostBindings: true,
- });
+ const project = createModuleAndProjectWithDeclarations(env, 'test', files);
appFile = project.openFile('app.ts');
});
diff --git a/packages/tsconfig.json b/packages/tsconfig.json
index da86abb88502..46955a117ca3 100644
--- a/packages/tsconfig.json
+++ b/packages/tsconfig.json
@@ -37,8 +37,7 @@
"suppressTsconfigOverrideWarnings": true
},
"angularCompilerOptions": {
- "strictTemplates": true,
- "typeCheckHostBindings": true
+ "strictTemplates": true
},
"exclude": [
"common/locales",