From 8ba4ddcb692b768983a9b8269c759c856c48c769 Mon Sep 17 00:00:00 2001 From: Alex Rickabaugh Date: Tue, 3 May 2022 09:11:58 -0700 Subject: [PATCH] refactor(compiler-cli): improve error for `imports` in non-standalone cmp (#45851) This commit improves the error message for using `imports` on a component that isn't set to `standalone: true`. Two concrete improvements are made: * A related information message is added to the diagnostic which suggests the fix of adding `standalone: true`. * The component is marked as poisoned, preventing other errors which might be caused by an incorrectly configured template scope from being generated and thus masking the original problem. Fixes #45850 PR Close #45851 --- .../annotations/component/src/handler.ts | 9 +++++-- .../test/ngtsc/standalone_spec.ts | 26 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts b/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts index da81f81919a..3c5072882f4 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts @@ -10,7 +10,7 @@ import {AnimationTriggerNames, compileClassMetadata, compileComponentFromMetadat import ts from 'typescript'; import {Cycle, CycleAnalyzer, CycleHandlingStrategy} from '../../../cycles'; -import {ErrorCode, FatalDiagnosticError, makeDiagnostic} from '../../../diagnostics'; +import {ErrorCode, FatalDiagnosticError, makeDiagnostic, makeRelatedInformation} from '../../../diagnostics'; import {absoluteFrom, relative} from '../../../file_system'; import {assertSuccessfulReferenceEmit, ImportedFile, ModuleResolver, Reference, ReferenceEmitter} from '../../../imports'; import {DependencyTracker} from '../../../incremental/api'; @@ -260,7 +260,12 @@ export class ComponentDecoratorHandler implements } diagnostics.push(makeDiagnostic( ErrorCode.COMPONENT_NOT_STANDALONE, component.get('imports')!, - `'imports' is only valid on a component that is standalone.`)); + `'imports' is only valid on a component that is standalone.`, + [makeRelatedInformation( + node.name, `Did you forget to add 'standalone: true' to this @Component?`)])); + // Poison the component so that we don't spam further template type-checking errors that + // result from misconfigured imports. + isPoisoned = true; } else if (component.has('imports')) { const expr = component.get('imports')!; const imported = this.evaluator.evaluate(expr); diff --git a/packages/compiler-cli/test/ngtsc/standalone_spec.ts b/packages/compiler-cli/test/ngtsc/standalone_spec.ts index d8c03cd618a..9a50ff8cc83 100644 --- a/packages/compiler-cli/test/ngtsc/standalone_spec.ts +++ b/packages/compiler-cli/test/ngtsc/standalone_spec.ts @@ -353,6 +353,32 @@ runInEachFileSystem(() => { expect(diags).toContain(`Type 'number' is not assignable to type 'string'.`); expect(diags).toContain(`Type 'boolean' is not assignable to type 'string'.`); }); + + it('should not spam errors if imports is misconfigured', () => { + env.write('test.ts', ` + import {Component, Input} from '@angular/core'; + + @Component({ + standalone: true, + selector: 'dep-cmp', + template: '', + }) + export class DepCmp {} + + @Component({ + // missing standalone: true, would ordinarily cause template type-checking errors + // as well as an error about imports on a non-standalone component. + imports: [DepCmp], + selector: 'test-cmp', + template: '', + }) + export class TestCmp {} + `); + + const diags = env.driveDiagnostics(); + expect(diags.length).toBe(1); + expect(diags[0].messageText).toContain('imports'); + }); }); describe('NgModule-side', () => {