Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 22cd686

Browse files
crisbetothePunderWoman
authored andcommitted
fix(compiler-cli): make the unused imports diagnostic easier to read (#58468)
The unused imports diagnostic reports once on the entire initializer and then again once per unused imports. This ends up being a bit hard to follow, because in a lot of cases the code snippet looks identical. These changes switch to highlighting the `imports:` part of the property declaration and only highlighting the unused imports without a message. PR Close #58468
1 parent abd0da7 commit 22cd686

File tree

2 files changed

+45
-34
lines changed

2 files changed

+45
-34
lines changed

‎packages/compiler-cli/src/ngtsc/validation/src/rules/unused_standalone_imports_rule.ts

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@
99
import ts from 'typescript';
1010

1111
import {ErrorCode, makeDiagnostic, makeRelatedInformation} from '../../../diagnostics';
12-
import {ImportedSymbolsTracker, Reference} from '../../../imports';
13-
import {
12+
import type {ImportedSymbolsTracker, Reference} from '../../../imports';
13+
import type {ClassDeclaration} from '../../../reflection';
14+
import type {
1415
TemplateTypeChecker,
1516
TypeCheckableDirectiveMeta,
1617
TypeCheckingConfig,
1718
} from '../../../typecheck/api';
1819

19-
import {SourceFileValidatorRule} from './api';
20+
import type {SourceFileValidatorRule} from './api';
2021

2122
/**
2223
* Rule that flags unused symbols inside of the `imports` array of a component.
@@ -79,7 +80,7 @@ export class UnusedStandaloneImportsRule implements SourceFileValidatorRule {
7980
if (unused.length === metadata.imports.length) {
8081
return makeDiagnostic(
8182
ErrorCode.UNUSED_STANDALONE_IMPORTS,
82-
metadata.rawImports,
83+
this.getDiagnosticNode(metadata.rawImports),
8384
'All imports are unused',
8485
undefined,
8586
category,
@@ -88,14 +89,19 @@ export class UnusedStandaloneImportsRule implements SourceFileValidatorRule {
8889

8990
return makeDiagnostic(
9091
ErrorCode.UNUSED_STANDALONE_IMPORTS,
91-
metadata.rawImports,
92+
this.getDiagnosticNode(metadata.rawImports),
9293
'Imports array contains unused imports',
93-
unused.map(([ref, type, name]) =>
94-
makeRelatedInformation(
95-
ref.getOriginForDiagnostics(metadata.rawImports!),
96-
`${type} "${name}" is not used within the template`,
97-
),
98-
),
94+
unused.map((ref) => {
95+
return makeRelatedInformation(
96+
// Intentionally don't pass a message to `makeRelatedInformation` to make the diagnostic
97+
// less noisy. The node will already be highlighted so the user can see which node is
98+
// unused. Note that in the case where an origin can't be resolved, we fall back to
99+
// the original node's identifier so the user can still see the name. This can happen
100+
// when the unused is coming from an imports array within the same file.
101+
ref.getOriginForDiagnostics(metadata.rawImports!, ref.node.name),
102+
'',
103+
);
104+
}),
99105
category,
100106
);
101107
}
@@ -111,7 +117,7 @@ export class UnusedStandaloneImportsRule implements SourceFileValidatorRule {
111117
return null;
112118
}
113119

114-
let unused: [ref: Reference, type: string, name: string][] | null = null;
120+
let unused: Reference<ClassDeclaration>[] | null = null;
115121

116122
for (const current of imports) {
117123
const currentNode = current.node as ts.ClassDeclaration;
@@ -124,7 +130,7 @@ export class UnusedStandaloneImportsRule implements SourceFileValidatorRule {
124130
!this.isPotentialSharedReference(current, rawImports)
125131
) {
126132
unused ??= [];
127-
unused.push([current, dirMeta.isComponent ? 'Component' : 'Directive', dirMeta.name]);
133+
unused.push(current);
128134
}
129135
continue;
130136
}
@@ -138,7 +144,7 @@ export class UnusedStandaloneImportsRule implements SourceFileValidatorRule {
138144
!this.isPotentialSharedReference(current, rawImports)
139145
) {
140146
unused ??= [];
141-
unused.push([current, 'Pipe', pipeMeta.ref.node.name.text]);
147+
unused.push(current);
142148
}
143149
}
144150

@@ -175,4 +181,21 @@ export class UnusedStandaloneImportsRule implements SourceFileValidatorRule {
175181
// symbol like an array of shared common components.
176182
return true;
177183
}
184+
185+
/** Gets the node on which to report the diagnostic. */
186+
private getDiagnosticNode(importsExpression: ts.Expression): ts.Node {
187+
let current = importsExpression.parent;
188+
189+
while (current) {
190+
// Highlight the `imports:` part of the node instead of the entire node, because
191+
// imports arrays can be long which makes the diagnostic harder to scan visually.
192+
if (ts.isPropertyAssignment(current)) {
193+
return current.name;
194+
} else {
195+
current = current.parent;
196+
}
197+
}
198+
199+
return importsExpression;
200+
}
178201
}

‎packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ runInEachFileSystem(() => {
397397
export class TestCmp {}
398398
399399
@Component({
400-
template: '',
400+
template: '',
401401
selector: 'target-cmp',
402402
standalone: false,
403403
})
@@ -432,7 +432,7 @@ runInEachFileSystem(() => {
432432
export class TestCmp {}
433433
434434
@Component({
435-
template: '',
435+
template: '',
436436
selector: 'target-cmp',
437437
standalone: false,
438438
})
@@ -7711,9 +7711,7 @@ suppress
77117711
expect(diags.length).toBe(1);
77127712
expect(diags[0].messageText).toBe('Imports array contains unused imports');
77137713
expect(diags[0].relatedInformation?.length).toBe(1);
7714-
expect(diags[0].relatedInformation![0].messageText).toBe(
7715-
'Directive "UnusedDir" is not used within the template',
7716-
);
7714+
expect(getSourceCodeForDiagnostic(diags[0].relatedInformation![0])).toBe('UnusedDir');
77177715
});
77187716

77197717
it('should report when a pipe is not used within a template', () => {
@@ -7770,9 +7768,7 @@ suppress
77707768
expect(diags.length).toBe(1);
77717769
expect(diags[0].messageText).toBe('Imports array contains unused imports');
77727770
expect(diags[0].relatedInformation?.length).toBe(1);
7773-
expect(diags[0].relatedInformation?.[0].messageText).toBe(
7774-
'Pipe "UnusedPipe" is not used within the template',
7775-
);
7771+
expect(getSourceCodeForDiagnostic(diags[0].relatedInformation![0])).toBe('UnusedPipe');
77767772
});
77777773

77787774
it('should not report imports only used inside @defer blocks', () => {
@@ -7960,12 +7956,8 @@ suppress
79607956
expect(diags.length).toBe(1);
79617957
expect(diags[0].messageText).toBe('Imports array contains unused imports');
79627958
expect(diags[0].relatedInformation?.length).toBe(2);
7963-
expect(diags[0].relatedInformation![0].messageText).toBe(
7964-
'Directive "NgFor" is not used within the template',
7965-
);
7966-
expect(diags[0].relatedInformation![1].messageText).toBe(
7967-
'Pipe "PercentPipe" is not used within the template',
7968-
);
7959+
expect(getSourceCodeForDiagnostic(diags[0].relatedInformation![0])).toBe('NgFor');
7960+
expect(getSourceCodeForDiagnostic(diags[0].relatedInformation![1])).toBe('PercentPipe');
79697961
});
79707962

79717963
it('should report unused imports coming from a nested array from the same file', () => {
@@ -8027,9 +8019,7 @@ suppress
80278019
expect(diags.length).toBe(1);
80288020
expect(diags[0].messageText).toBe('Imports array contains unused imports');
80298021
expect(diags[0].relatedInformation?.length).toBe(1);
8030-
expect(diags[0].relatedInformation![0].messageText).toBe(
8031-
'Directive "UnusedDir" is not used within the template',
8032-
);
8022+
expect(getSourceCodeForDiagnostic(diags[0].relatedInformation![0])).toBe('UnusedDir');
80338023
});
80348024

80358025
it('should report unused imports coming from an array used as the `imports` initializer', () => {
@@ -8080,9 +8070,7 @@ suppress
80808070
expect(diags.length).toBe(1);
80818071
expect(diags[0].messageText).toBe('Imports array contains unused imports');
80828072
expect(diags[0].relatedInformation?.length).toBe(1);
8083-
expect(diags[0].relatedInformation![0].messageText).toBe(
8084-
'Directive "UnusedDir" is not used within the template',
8085-
);
8073+
expect(getSourceCodeForDiagnostic(diags[0].relatedInformation![0])).toBe('UnusedDir');
80868074
});
80878075

80888076
it('should not report unused imports coming from an array through a spread expression from a different file', () => {

0 commit comments

Comments
 (0)