Skip to content

Commit 39ddd88

Browse files
pmvaldthePunderWoman
authored andcommitted
fix(compiler-cli): show specific error for unresolved @HostListener's event name in local compilation mode (#54230)
Currently the error is a generic error "selector must be a string ...". This commit makes the error more specific to local compilation and adds some action items. PR Close #54230
1 parent 5d63324 commit 39ddd88

File tree

2 files changed

+75
-3
lines changed

2 files changed

+75
-3
lines changed

packages/compiler-cli/src/ngtsc/annotations/directive/src/shared.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ export function extractDirectiveMetadata(
142142
}
143143
}
144144

145-
const host = extractHostBindings(decoratedElements, evaluator, coreModule, directive);
145+
const host = extractHostBindings(decoratedElements, evaluator, coreModule, compilationMode, directive);
146146

147147
const providers: Expression|null = directive.has('providers') ?
148148
new WrappedNodeExpr(
@@ -362,8 +362,7 @@ export function extractDecoratorQueryMetadata(
362362

363363

364364
export function extractHostBindings(
365-
members: ClassMember[], evaluator: PartialEvaluator, coreModule: string|undefined,
366-
metadata?: Map<string, ts.Expression>): ParsedHostBindings {
365+
members: ClassMember[], evaluator: PartialEvaluator, coreModule: string|undefined, compilationMode: CompilationMode, metadata?: Map<string, ts.Expression>): ParsedHostBindings {
367366
let bindings: ParsedHostBindings;
368367
if (metadata && metadata.has('host')) {
369368
bindings = evaluateHostExpressionBindings(metadata.get('host')!, evaluator);
@@ -413,6 +412,15 @@ export function extractHostBindings(
413412
}
414413

415414
const resolved = evaluator.evaluate(decorator.args[0]);
415+
416+
// Specific error for local compilation mode if the event name cannot be resolved
417+
assertLocalCompilationUnresolvedConst(compilationMode, resolved, null,
418+
'Unresolved identifier found for @HostListener\'s event name ' +
419+
'argument! Did you import this identifier from a file outside of ' +
420+
'the compilation unit? This is not allowed when Angular compiler ' +
421+
'runs in local mode. Possible solutions: 1) Move the declaration ' +
422+
'into a file within the compilation unit, 2) Inline the argument');
423+
416424
if (typeof resolved !== 'string') {
417425
throw createValueHasWrongTypeError(
418426
decorator.args[0], resolved,

packages/compiler-cli/test/ngtsc/local_compilation_spec.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,70 @@ runInEachFileSystem(
13191319
expect(text).toEqual(
13201320
'Unresolved identifier found for @Component.selector field! Did you import this identifier from a file outside of the compilation unit? This is not allowed when Angular compiler runs in local mode. Possible solutions: 1) Move the declarations into a file within the compilation unit, 2) Inline the selector');
13211321
});
1322+
1323+
it('should show correct error message when using an external symbol for component @HostListener\'s event name argument',
1324+
() => {
1325+
env.write('test.ts', `
1326+
import {Component, HostListener} from '@angular/core';
1327+
import {ExternalString} from './some-where';
1328+
1329+
@Component({
1330+
template: '',
1331+
})
1332+
export class Main {
1333+
@HostListener(ExternalString, ['$event'])
1334+
handle() {}
1335+
}
1336+
`);
1337+
1338+
const errors = env.driveDiagnostics();
1339+
1340+
expect(errors.length).toBe(1);
1341+
1342+
const {code, messageText, relatedInformation, length} = errors[0];
1343+
1344+
expect(code).toBe(
1345+
ngErrorCode(ErrorCode.LOCAL_COMPILATION_UNRESOLVED_CONST));
1346+
expect(length).toBe(14),
1347+
expect(relatedInformation).toBeUndefined();
1348+
1349+
const text = ts.flattenDiagnosticMessageText(messageText, '\n');
1350+
1351+
expect(text).toEqual(
1352+
`Unresolved identifier found for @HostListener's event name argument! Did you import this identifier from a file outside of the compilation unit? This is not allowed when Angular compiler runs in local mode. Possible solutions: 1) Move the declaration into a file within the compilation unit, 2) Inline the argument`
1353+
);
1354+
});
1355+
1356+
it('should show correct error message when using an external symbol for directive @HostListener\'s event name argument',
1357+
() => {
1358+
env.write('test.ts', `
1359+
import {Directive, HostListener} from '@angular/core';
1360+
import {ExternalString} from './some-where';
1361+
1362+
@Directive({selector: '[test]'})
1363+
export class Main {
1364+
@HostListener(ExternalString, ['$event'])
1365+
handle() {}
1366+
}
1367+
`);
1368+
1369+
const errors = env.driveDiagnostics();
1370+
1371+
expect(errors.length).toBe(1);
1372+
1373+
const {code, messageText, relatedInformation, length} = errors[0];
1374+
1375+
expect(code).toBe(
1376+
ngErrorCode(ErrorCode.LOCAL_COMPILATION_UNRESOLVED_CONST));
1377+
expect(length).toBe(14),
1378+
expect(relatedInformation).toBeUndefined();
1379+
1380+
const text = ts.flattenDiagnosticMessageText(messageText, '\n');
1381+
1382+
expect(text).toEqual(
1383+
`Unresolved identifier found for @HostListener's event name argument! Did you import this identifier from a file outside of the compilation unit? This is not allowed when Angular compiler runs in local mode. Possible solutions: 1) Move the declaration into a file within the compilation unit, 2) Inline the argument`
1384+
);
1385+
});
13221386
});
13231387

13241388
describe('ng module bootstrap def', () => {

0 commit comments

Comments
 (0)