Content-Length: 476604 | pFad | http://github.com/angular/angular/commit/f4c4b10ea8dc263c30d1051a83a72486344d81e4

90 fix(compiler-cli): Produce fatal diagnostic on duplicate decorated pr… · angular/angular@f4c4b10 · GitHub
Skip to content

Commit f4c4b10

Browse files
atscottthePunderWoman
authored andcommitted
fix(compiler-cli): Produce fatal diagnostic on duplicate decorated properties (#60376)
This prevents the compilation and language service from crashing. fixes angular/vscode-ng-language-service#2091 PR Close #60376
1 parent 64da69f commit f4c4b10

File tree

4 files changed

+41
-6
lines changed

4 files changed

+41
-6
lines changed

goldens/public-api/compiler-cli/error_code.api.md

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ export enum ErrorCode {
4343
DIRECTIVE_INHERITS_UNDECORATED_CTOR = 2006,
4444
// (undocumented)
4545
DIRECTIVE_MISSING_SELECTOR = 2004,
46+
// (undocumented)
47+
DUPLICATE_DECORATED_PROPERTIES = 1012,
4648
DUPLICATE_VARIABLE_DECLARATION = 8006,
4749
HOST_BINDING_PARSE_ERROR = 5001,
4850
HOST_DIRECTIVE_COMPONENT = 2015,

packages/compiler-cli/src/ngtsc/annotations/common/src/metadata.ts

+9-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9+
import {ErrorCode, FatalDiagnosticError, makeRelatedInformation} from '../../../diagnostics';
910
import {
1011
ArrowFunctionExpr,
1112
Expression,
@@ -88,16 +89,18 @@ export function extractClassMetadata(
8889
.filter(
8990
(member) => !member.isStatic && member.decorators !== null && member.decorators.length > 0,
9091
);
91-
const duplicateDecoratedMemberNames = classMembers
92-
.map((member) => member.name)
93-
.filter((name, i, arr) => arr.indexOf(name) < i);
94-
if (duplicateDecoratedMemberNames.length > 0) {
92+
const duplicateDecoratedMembers = classMembers.filter(
93+
(member, i, arr) => arr.findIndex((arrayMember) => arrayMember.name === member.name) < i,
94+
);
95+
if (duplicateDecoratedMembers.length > 0) {
9596
// This should theoretically never happen, because the only way to have duplicate instance
9697
// member names is getter/setter pairs and decorators cannot appear in both a getter and the
9798
// corresponding setter.
98-
throw new Error(
99+
throw new FatalDiagnosticError(
100+
ErrorCode.DUPLICATE_DECORATED_PROPERTIES,
101+
duplicateDecoratedMembers[0].nameNode ?? clazz,
99102
`Duplicate decorated properties found on class '${clazz.name.text}': ` +
100-
duplicateDecoratedMemberNames.join(', '),
103+
duplicateDecoratedMembers.map((member) => member.name).join(', '),
101104
);
102105
}
103106
const decoratedMembers = classMembers.map((member) =>

packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export enum ErrorCode {
2323
VALUE_HAS_WRONG_TYPE = 1010,
2424
VALUE_NOT_LITERAL = 1011,
2525

26+
DUPLICATE_DECORATED_PROPERTIES = 1012,
27+
2628
/**
2729
* Raised when an initializer API is annotated with an unexpected decorator.
2830
*

packages/language-service/test/diagnostic_spec.ts

+28
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,34 @@ describe('getSemanticDiagnostics', () => {
5959
expect(messageText).toBe(`Property 'nope' does not exist on type 'AppComponent'.`);
6060
});
6161

62+
it('produces diagnostic for duplicate docarated property rather than crashing', () => {
63+
const files = {
64+
'app.ts': `
65+
import {Component, Input} from '@angular/core';
66+
67+
@Component({
68+
template: '',
69+
})
70+
export class AppComponent {
71+
@Input() test1?: string;
72+
@Input() test1?: string;
73+
}
74+
`,
75+
};
76+
const project = createModuleAndProjectWithDeclarations(env, 'test', files);
77+
78+
const diags = project.getDiagnosticsForFile('app.ts');
79+
expect(diags.length).toBe(2);
80+
expect(diags[0].category).toBe(ts.DiagnosticCategory.Error);
81+
expect(diags[0].file?.fileName).toBe('/test/app.ts');
82+
expect(diags[0].messageText).toBe(`Duplicate identifier 'test1'.`);
83+
expect(diags[1].category).toBe(ts.DiagnosticCategory.Error);
84+
expect(diags[1].file?.fileName).toBe('/test/app.ts');
85+
expect(diags[1].messageText).toBe(
86+
`Duplicate decorated properties found on class 'AppComponent': test1`,
87+
);
88+
});
89+
6290
it('should process external template', () => {
6391
const files = {
6492
'app.ts': `

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/angular/angular/commit/f4c4b10ea8dc263c30d1051a83a72486344d81e4

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy