Skip to content

Commit a2e4ee0

Browse files
crisbetoAndrewKushnir
authored andcommitted
feat(compiler): add diagnostic for unused standalone imports (#57605)
Adds a new diagnostic that will report cases where a declaration is in the `imports` array, but isn't being used anywhere. The diagnostic is reported as a warning by default and can be controlled using the following option in the tsconfig: ``` { "angularCompilerOptions": { "extendedDiagnostics": { "checks": { "unusedStandaloneImports": "suppress" } } } } ``` **Note:** I'll look into a codefix for the language service in a follow-up. Fixes #46766. PR Close #57605
1 parent a777bee commit a2e4ee0

File tree

24 files changed

+576
-6
lines changed

24 files changed

+576
-6
lines changed

adev/src/app/sub-navigation-data.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,6 +1368,11 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [
13681368
path: 'extended-diagnostics/NG8111',
13691369
contentPath: 'reference/extended-diagnostics/NG8111',
13701370
},
1371+
{
1372+
label: 'NG8113: Unused Standalone Imports',
1373+
path: 'extended-diagnostics/NG8113',
1374+
contentPath: 'reference/extended-diagnostics/NG8113',
1375+
},
13711376
],
13721377
},
13731378
{
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Unused Standalone Imports
2+
3+
This diagnostic detects cases where the `imports` array of a `@Component` contains symbols that
4+
aren't used within the template.
5+
6+
<docs-code language="typescript">
7+
8+
@Component({
9+
imports: [UsedDirective, UnusedPipe]
10+
})
11+
class AwesomeCheckbox {}
12+
13+
</docs-code>
14+
15+
## What's wrong with that?
16+
17+
The unused imports add unnecessary noise to your code and can increase your compilation time.
18+
19+
## What should I do instead?
20+
21+
Delete the unused import.
22+
23+
<docs-code language="typescript">
24+
25+
@Component({
26+
imports: [UsedDirective]
27+
})
28+
class AwesomeCheckbox {}
29+
30+
</docs-code>
31+
32+
## What if I can't avoid this?
33+
34+
This diagnostic can be disabled by editing the project's `tsconfig.json` file:
35+
36+
<docs-code language="json">
37+
{
38+
"angularCompilerOptions": {
39+
"extendedDiagnostics": {
40+
"checks": {
41+
"unusedStandaloneImports": "suppress"
42+
}
43+
}
44+
}
45+
}
46+
</docs-code>
47+
48+
See [extended diagnostic configuration](extended-diagnostics#configuration) for more info.

adev/src/content/reference/extended-diagnostics/overview.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Currently, Angular supports the following extended diagnostics:
2020
| `NG8108` | [`skipHydrationNotStatic`](extended-diagnostics/NG8108) |
2121
| `NG8109` | [`interpolatedSignalNotInvoked`](extended-diagnostics/NG8109) |
2222
| `NG8111` | [`uninvokedFunctionInEventBinding`](extended-diagnostics/NG8111) |
23+
| `NG8113` | [`unusedStandaloneImports`](extended-diagnostics/NG8113) |
2324

2425
## Configuration
2526

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ export enum ErrorCode {
106106
UNINVOKED_FUNCTION_IN_EVENT_BINDING = 8111,
107107
UNSUPPORTED_INITIALIZER_API_USAGE = 8110,
108108
UNUSED_LET_DECLARATION = 8112,
109+
UNUSED_STANDALONE_IMPORTS = 8113,
109110
// (undocumented)
110111
VALUE_HAS_WRONG_TYPE = 1010,
111112
// (undocumented)

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ export enum ExtendedTemplateDiagnosticName {
2929
// (undocumented)
3030
UNINVOKED_FUNCTION_IN_EVENT_BINDING = "uninvokedFunctionInEventBinding",
3131
// (undocumented)
32-
UNUSED_LET_DECLARATION = "unusedLetDeclaration"
32+
UNUSED_LET_DECLARATION = "unusedLetDeclaration",
33+
// (undocumented)
34+
UNUSED_STANDALONE_IMPORTS = "unusedStandaloneImports"
3335
}
3436

3537
// (No @packageDocumentation comment for this package)

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,7 @@ export class ComponentDecoratorHandler
902902
isStandalone: analysis.meta.isStandalone,
903903
isSignal: analysis.meta.isSignal,
904904
imports: analysis.resolvedImports,
905+
rawImports: analysis.rawImports,
905906
deferredImports: analysis.resolvedDeferredImports,
906907
animationTriggerNames: analysis.animationTriggerNames,
907908
schemas: analysis.schemas,

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ export class DirectiveDecoratorHandler
270270
isStandalone: analysis.meta.isStandalone,
271271
isSignal: analysis.meta.isSignal,
272272
imports: null,
273+
rawImports: null,
273274
deferredImports: null,
274275
schemas: null,
275276
ngContentSelectors: null,

packages/compiler-cli/src/ngtsc/core/src/compiler.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,8 @@ export class NgCompiler {
10371037
suggestionsForSuboptimalTypeInference: this.enableTemplateTypeChecker && !strictTemplates,
10381038
controlFlowPreventingContentProjection:
10391039
this.options.extendedDiagnostics?.defaultCategory || DiagnosticCategoryLabel.Warning,
1040+
unusedStandaloneImports:
1041+
this.options.extendedDiagnostics?.defaultCategory || DiagnosticCategoryLabel.Warning,
10401042
allowSignalsInTwoWayBindings,
10411043
};
10421044
} else {
@@ -1069,6 +1071,8 @@ export class NgCompiler {
10691071
suggestionsForSuboptimalTypeInference: false,
10701072
controlFlowPreventingContentProjection:
10711073
this.options.extendedDiagnostics?.defaultCategory || DiagnosticCategoryLabel.Warning,
1074+
unusedStandaloneImports:
1075+
this.options.extendedDiagnostics?.defaultCategory || DiagnosticCategoryLabel.Warning,
10721076
allowSignalsInTwoWayBindings,
10731077
};
10741078
}
@@ -1114,6 +1118,10 @@ export class NgCompiler {
11141118
typeCheckingConfig.controlFlowPreventingContentProjection =
11151119
this.options.extendedDiagnostics.checks.controlFlowPreventingContentProjection;
11161120
}
1121+
if (this.options.extendedDiagnostics?.checks?.unusedStandaloneImports !== undefined) {
1122+
typeCheckingConfig.unusedStandaloneImports =
1123+
this.options.extendedDiagnostics.checks.unusedStandaloneImports;
1124+
}
11171125

11181126
return typeCheckingConfig;
11191127
}
@@ -1541,11 +1549,12 @@ export class NgCompiler {
15411549
},
15421550
);
15431551

1552+
const typeCheckingConfig = this.getTypeCheckingConfig();
15441553
const templateTypeChecker = new TemplateTypeCheckerImpl(
15451554
this.inputProgram,
15461555
notifyingDriver,
15471556
traitCompiler,
1548-
this.getTypeCheckingConfig(),
1557+
typeCheckingConfig,
15491558
refEmitter,
15501559
reflector,
15511560
this.adapter,
@@ -1576,7 +1585,7 @@ export class NgCompiler {
15761585

15771586
const sourceFileValidator =
15781587
this.constructionDiagnostics.length === 0
1579-
? new SourceFileValidator(reflector, importTracker)
1588+
? new SourceFileValidator(reflector, importTracker, templateTypeChecker, typeCheckingConfig)
15801589
: null;
15811590

15821591
return {

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,11 @@ export function makeDiagnostic(
5050
node: ts.Node,
5151
messageText: string | ts.DiagnosticMessageChain,
5252
relatedInformation?: ts.DiagnosticRelatedInformation[],
53+
category: ts.DiagnosticCategory = ts.DiagnosticCategory.Error,
5354
): ts.DiagnosticWithLocation {
5455
node = ts.getOriginalNode(node);
5556
return {
56-
category: ts.DiagnosticCategory.Error,
57+
category,
5758
code: ngErrorCode(code),
5859
file: ts.getOriginalNode(node).getSourceFile(),
5960
start: node.getStart(undefined, false),

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,11 @@ export enum ErrorCode {
508508
*/
509509
UNUSED_LET_DECLARATION = 8112,
510510

511+
/**
512+
* A symbol referenced in `@Component.imports` isn't being used within the template.
513+
*/
514+
UNUSED_STANDALONE_IMPORTS = 8113,
515+
511516
/**
512517
* The template type-checking engine would need to generate an inline type check block for a
513518
* component, but the current type-checking environment doesn't support it.

0 commit comments

Comments
 (0)