@@ -357,8 +357,8 @@ runInEachFileSystem(() => {
357357 import {ɵɵDirectiveDeclaration} from '@angular/core';
358358
359359 export declare class ExternalDir {
360- static ɵdir: ɵɵDirectiveDeclaration<ExternalDir, '[test]', never, never,
361- {input: "input"}, {output: "output"}, never, true, never>;
360+ static ɵdir: ɵɵDirectiveDeclaration<ExternalDir, '[test]', never,
361+ {input: "input"}, {output: "output"}, never, never, true, never>;
362362 }
363363 ` ) ;
364364
@@ -434,7 +434,7 @@ runInEachFileSystem(() => {
434434 diag . messageText . messageText ;
435435 }
436436
437- it ( 'should throw if a host directive is not standalone' , ( ) => {
437+ it ( 'should produce a diagnostic if a host directive is not standalone' , ( ) => {
438438 env . write ( 'test.ts' , `
439439 import {Directive, Component, NgModule} from '@angular/core';
440440
@@ -451,7 +451,7 @@ runInEachFileSystem(() => {
451451 expect ( messages ) . toEqual ( [ 'Host directive HostDir must be standalone' ] ) ;
452452 } ) ;
453453
454- it ( 'should throw if a host directive is a component' , ( ) => {
454+ it ( 'should produce a diagnostic if a host directive is a component' , ( ) => {
455455 env . write ( 'test.ts' , `
456456 import {Directive, Component, NgModule} from '@angular/core';
457457
@@ -471,7 +471,7 @@ runInEachFileSystem(() => {
471471 expect ( messages ) . toEqual ( [ 'Host directive HostComp cannot be a component' ] ) ;
472472 } ) ;
473473
474- it ( 'should throw if hostDirectives is not an array' , ( ) => {
474+ it ( 'should produce a diagnostic if hostDirectives is not an array' , ( ) => {
475475 env . write ( 'test.ts' , `
476476 import {Component} from '@angular/core';
477477
@@ -486,7 +486,7 @@ runInEachFileSystem(() => {
486486 expect ( messages ) . toContain ( 'hostDirectives must be an array' ) ;
487487 } ) ;
488488
489- it ( 'should throw if a host directive is not a reference' , ( ) => {
489+ it ( 'should produce a diagnostic if a host directive is not a reference' , ( ) => {
490490 env . write ( 'test.ts' , `
491491 import {Component} from '@angular/core';
492492
@@ -503,7 +503,7 @@ runInEachFileSystem(() => {
503503 expect ( messages ) . toEqual ( [ 'Host directive must be a reference' ] ) ;
504504 } ) ;
505505
506- it ( 'should throw if a host directive is not a reference to a class' , ( ) => {
506+ it ( 'should produce a diagnostic if a host directive is not a reference to a class' , ( ) => {
507507 env . write ( 'test.ts' , `
508508 import {Component} from '@angular/core';
509509
@@ -520,7 +520,7 @@ runInEachFileSystem(() => {
520520 expect ( messages ) . toEqual ( [ 'Host directive reference must be a class' ] ) ;
521521 } ) ;
522522
523- it ( 'should only throw host directive error once in a chain of directives' , ( ) => {
523+ it ( 'should only produce a diagnostic once in a chain of directives' , ( ) => {
524524 env . write ( 'test.ts' , `
525525 import {Directive, Component, NgModule} from '@angular/core';
526526
@@ -544,12 +544,221 @@ runInEachFileSystem(() => {
544544 export class Host {}
545545 ` ) ;
546546
547- // What we're checking here is that the errors aren't produced recursively. If that were
548- // the case, the same error would show up more than once in the diagnostics since `HostDirB`
549- // is in the chain of both `Host` and `HostDirA`.
547+ // What we're checking here is that the diagnostics aren't produced recursively. If that
548+ // were the case, the same diagnostic would show up more than once in the diagnostics since
549+ // `HostDirB` is in the chain of both `Host` and `HostDirA`.
550550 const messages = env . driveDiagnostics ( ) . map ( extractMessage ) ;
551551 expect ( messages ) . toEqual ( [ 'Host directive HostDirB must be standalone' ] ) ;
552552 } ) ;
553+
554+ it ( 'should produce a diagnostic if a host directive output does not exist' , ( ) => {
555+ env . write ( 'test.ts' , `
556+ import {Directive, Output, EventEmitter} from '@angular/core';
557+
558+ @Directive({standalone: true})
559+ class HostDir {
560+ @Output() foo = new EventEmitter();
561+ }
562+
563+ @Directive({
564+ selector: '[dir]',
565+ hostDirectives: [{
566+ directive: HostDir,
567+ outputs: ['doesNotExist'],
568+ }]
569+ })
570+ class Dir {}
571+ ` ) ;
572+
573+ const messages = env . driveDiagnostics ( ) . map ( extractMessage ) ;
574+ expect ( messages ) . toEqual (
575+ [ 'Directive HostDir does not have an output with a public name of doesNotExist.' ] ) ;
576+ } ) ;
577+
578+ it ( 'should produce a diagnostic if a host directive output alias does not exist' , ( ) => {
579+ env . write ( 'test.ts' , `
580+ import {Directive, Output, EventEmitter} from '@angular/core';
581+
582+ @Directive({standalone: true})
583+ class HostDir {
584+ @Output('alias') foo = new EventEmitter();
585+ }
586+
587+ @Directive({
588+ selector: '[dir]',
589+ hostDirectives: [{
590+ directive: HostDir,
591+ outputs: ['foo'],
592+ }]
593+ })
594+ class Dir {}
595+ ` ) ;
596+
597+ const messages = env . driveDiagnostics ( ) . map ( extractMessage ) ;
598+ expect ( messages ) . toEqual (
599+ [ 'Directive HostDir does not have an output with a public name of foo.' ] ) ;
600+ } ) ;
601+
602+ it ( 'should produce a diagnostic if a host directive input does not exist' , ( ) => {
603+ env . write ( 'test.ts' , `
604+ import {Directive, Input} from '@angular/core';
605+
606+ @Directive({standalone: true})
607+ class HostDir {
608+ @Input() foo: any;
609+ }
610+
611+ @Directive({
612+ selector: '[dir]',
613+ hostDirectives: [{
614+ directive: HostDir,
615+ inputs: ['doesNotExist'],
616+ }]
617+ })
618+ class Dir {}
619+ ` ) ;
620+
621+ const messages = env . driveDiagnostics ( ) . map ( extractMessage ) ;
622+ expect ( messages ) . toEqual (
623+ [ 'Directive HostDir does not have an input with a public name of doesNotExist.' ] ) ;
624+ } ) ;
625+
626+ it ( 'should produce a diagnostic if a host directive input alias does not exist' , ( ) => {
627+ env . write ( 'test.ts' , `
628+ import {Directive, Input} from '@angular/core';
629+
630+ @Directive({standalone: true})
631+ class HostDir {
632+ @Input('alias') foo: any;
633+ }
634+
635+ @Directive({
636+ selector: '[dir]',
637+ hostDirectives: [{directive: HostDir, inputs: ['foo']}],
638+ })
639+ class Dir {}
640+ ` ) ;
641+
642+ const messages = env . driveDiagnostics ( ) . map ( extractMessage ) ;
643+ expect ( messages ) . toEqual (
644+ [ 'Directive HostDir does not have an input with a public name of foo.' ] ) ;
645+ } ) ;
646+
647+ it ( 'should produce a diagnostic if a host directive tries to alias to an existing input' ,
648+ ( ) => {
649+ env . write ( 'test.ts' , `
650+ import {Directive, Input} from '@angular/core';
651+
652+ @Directive({selector: '[host-dir]', standalone: true})
653+ class HostDir {
654+ @Input('colorAlias') color?: string;
655+ @Input() buttonColor?: string;
656+ }
657+
658+ @Directive({
659+ selector: '[dir]',
660+ hostDirectives: [{directive: HostDir, inputs: ['colorAlias: buttonColor']}]
661+ })
662+ class Dir {}
663+ ` ) ;
664+
665+ const messages = env . driveDiagnostics ( ) . map ( extractMessage ) ;
666+ expect ( messages ) . toEqual ( [
667+ 'Cannot alias input colorAlias of host directive HostDir to buttonColor, because it ' +
668+ 'already has a different input with the same public name.'
669+ ] ) ;
670+ } ) ;
671+
672+ it ( 'should produce a diagnostic if a host directive tries to alias to an existing input alias' ,
673+ ( ) => {
674+ env . write ( 'test.ts' , `
675+ import {Directive, Input} from '@angular/core';
676+
677+ @Directive({selector: '[host-dir]', standalone: true})
678+ class HostDir {
679+ @Input('colorAlias') color?: string;
680+ @Input('buttonColorAlias') buttonColor?: string;
681+ }
682+
683+ @Directive({
684+ selector: '[dir]',
685+ hostDirectives: [{directive: HostDir, inputs: ['colorAlias: buttonColorAlias']}]
686+ })
687+ class Dir {}
688+ ` ) ;
689+
690+ const messages = env . driveDiagnostics ( ) . map ( extractMessage ) ;
691+ expect ( messages ) . toEqual (
692+ [ 'Cannot alias input colorAlias of host directive HostDir to buttonColorAlias, ' +
693+ 'because it already has a different input with the same public name.' ] ) ;
694+ } ) ;
695+
696+ it ( 'should not produce a diagnostic if a host directive input aliases to the same name' ,
697+ ( ) => {
698+ env . write ( 'test.ts' , `
699+ import {Directive, Input} from '@angular/core';
700+
701+ @Directive({selector: '[host-dir]', standalone: true})
702+ class HostDir {
703+ @Input('color') color?: string;
704+ }
705+
706+ @Directive({
707+ selector: '[dir]',
708+ hostDirectives: [{directive: HostDir, inputs: ['color: buttonColor']}]
709+ })
710+ class Dir {}
711+ ` ) ;
712+
713+ const messages = env . driveDiagnostics ( ) . map ( extractMessage ) ;
714+ expect ( messages ) . toEqual ( [ ] ) ;
715+ } ) ;
716+
717+ it ( 'should produce a diagnostic if a host directive tries to alias to an existing output alias' ,
718+ ( ) => {
719+ env . write ( 'test.ts' , `
720+ import {Directive, Output, EventEmitter} from '@angular/core';
721+
722+ @Directive({selector: '[host-dir]', standalone: true})
723+ class HostDir {
724+ @Output('clickedAlias') clicked = new EventEmitter();
725+ @Output('tappedAlias') tapped = new EventEmitter();
726+ }
727+
728+ @Directive({
729+ selector: '[dir]',
730+ hostDirectives: [{directive: HostDir, outputs: ['clickedAlias: tappedAlias']}]
731+ })
732+ class Dir {}
733+ ` ) ;
734+
735+ const messages = env . driveDiagnostics ( ) . map ( extractMessage ) ;
736+ expect ( messages ) . toEqual ( [
737+ 'Cannot alias output clickedAlias of host directive HostDir ' +
738+ 'to tappedAlias, because it already has a different output with the same public name.'
739+ ] ) ;
740+ } ) ;
741+
742+ it ( 'should not produce a diagnostic if a host directive output aliases to the same name' ,
743+ ( ) => {
744+ env . write ( 'test.ts' , `
745+ import {Directive, Output, EventEmitter} from '@angular/core';
746+
747+ @Directive({selector: '[host-dir]', standalone: true})
748+ class HostDir {
749+ @Output('clicked') clicked = new EventEmitter();
750+ }
751+
752+ @Directive({
753+ selector: '[dir]',
754+ hostDirectives: [{directive: HostDir, outputs: ['clicked: wasClicked']}]
755+ })
756+ class Dir {}
757+ ` ) ;
758+
759+ const messages = env . driveDiagnostics ( ) . map ( extractMessage ) ;
760+ expect ( messages ) . toEqual ( [ ] ) ;
761+ } ) ;
553762 } ) ;
554763 } ) ;
555764} ) ;
0 commit comments