Content-Length: 484632 | pFad | https://github.com/angular/angular/commit/29eded6457b72e7c8a2d53c847ec43996b73c054

9B fix(compiler-cli): report more accurate diagnostic for invalid import… · angular/angular@29eded6 · GitHub
Skip to content

Commit 29eded6

Browse files
crisbetopkozlowski-opensource
authored andcommitted
fix(compiler-cli): report more accurate diagnostic for invalid import (#60455)
Currently when an incorrect value is in the `imports` array, we highlight the entire array which can be very noisy for large arrays. This comes up semi-regularly (at least for me) when an import is missing. These changes add some logic that reports a more accurate diagnostic location for the most common case where the `imports` array is static. Non-static arrays will fall back to the current behavior. PR Close #60455
1 parent 2d51a20 commit 29eded6

File tree

2 files changed

+72
-3
lines changed

2 files changed

+72
-3
lines changed

packages/compiler-cli/src/ngtsc/annotations/component/src/util.ts

+35-3
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@ import {
1111
isResolvedModuleWithProviders,
1212
ResolvedModuleWithProviders,
1313
} from '@angular/compiler-cli/src/ngtsc/annotations/ng_module';
14-
import {ErrorCode, makeDiagnostic} from '@angular/compiler-cli/src/ngtsc/diagnostics';
14+
import {
15+
ErrorCode,
16+
FatalDiagnosticError,
17+
makeDiagnostic,
18+
} from '@angular/compiler-cli/src/ngtsc/diagnostics';
1519
import ts from 'typescript';
1620

1721
import {Reference} from '../../../imports';
1822
import {
23+
DynamicValue,
1924
ForeignFunctionResolver,
2025
ResolvedValue,
2126
ResolvedValueMap,
@@ -96,7 +101,9 @@ export function validateAndFlattenComponentImports(
96101
}
97102
const diagnostics: ts.Diagnostic[] = [];
98103

99-
for (const ref of imports) {
104+
for (let i = 0; i < imports.length; i++) {
105+
const ref = imports[i];
106+
100107
if (Array.isArray(ref)) {
101108
const {imports: childImports, diagnostics: childDiagnostics} =
102109
validateAndFlattenComponentImports(ref, expr, isDeferred);
@@ -132,7 +139,32 @@ export function validateAndFlattenComponentImports(
132139
),
133140
);
134141
} else {
135-
diagnostics.push(createValueHasWrongTypeError(expr, imports, errorMessage).toDiagnostic());
142+
let diagnosticNode: ts.Node;
143+
let diagnosticValue: ResolvedValue;
144+
145+
if (ref instanceof DynamicValue) {
146+
diagnosticNode = ref.node;
147+
diagnosticValue = ref;
148+
} else if (
149+
ts.isArrayLiteralExpression(expr) &&
150+
expr.elements.length === imports.length &&
151+
!expr.elements.some(ts.isSpreadAssignment) &&
152+
!imports.some(Array.isArray)
153+
) {
154+
// Reporting a diagnostic on the entire array can be noisy, especially if the user has a
155+
// large array. The most common case is that the array will be static so we can reliably
156+
// trace back a `ResolvedValue` back to its node using its index. This allows us to report
157+
// the exact node that caused the issue.
158+
diagnosticNode = expr.elements[i];
159+
diagnosticValue = ref;
160+
} else {
161+
diagnosticNode = expr;
162+
diagnosticValue = imports;
163+
}
164+
165+
diagnostics.push(
166+
createValueHasWrongTypeError(diagnosticNode, diagnosticValue, errorMessage).toDiagnostic(),
167+
);
136168
}
137169
}
138170

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

+37
Original file line numberDiff line numberDiff line change
@@ -2282,6 +2282,43 @@ runInEachFileSystem((os: string) => {
22822282
);
22832283
});
22842284

2285+
it('should report diagnostic on the exact element in the `imports` array', () => {
2286+
// Note: the scenario here is slightly contrived, but we want to hit the code
2287+
// path where TS doesn't report a type error before Angular which appears to be
2288+
// common with the language service.
2289+
env.write(
2290+
'test.ts',
2291+
`
2292+
import {Component, Directive} from '@angular/core';
2293+
2294+
@Directive({selector: '[hello]'})
2295+
export class HelloDir {}
2296+
2297+
const someVar = {} as any;
2298+
2299+
@Component({
2300+
template: '<div hello></div>',
2301+
imports: [
2302+
someVar,
2303+
HelloDir,
2304+
]
2305+
})
2306+
export class TestCmp {}
2307+
`,
2308+
);
2309+
2310+
const diags = env.driveDiagnostics();
2311+
const message = diags.length
2312+
? ts.flattenDiagnosticMessageText(diags[0].messageText, '\n')
2313+
: '';
2314+
expect(diags.length).toBe(1);
2315+
expect(getDiagnosticSourceCode(diags[0])).toBe('someVar');
2316+
expect(message).toContain(
2317+
`'imports' must be an array of components, directives, pipes, or NgModules.`,
2318+
);
2319+
expect(message).toContain(`Value is of type '{}'`);
2320+
});
2321+
22852322
describe('empty and missing selectors', () => {
22862323
it('should use default selector for Components when no selector present', () => {
22872324
env.write(

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: https://github.com/angular/angular/commit/29eded6457b72e7c8a2d53c847ec43996b73c054

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy