66 * found in the LICENSE file at https://angular.io/license
77 */
88
9+ import { ASTWithName } from '@angular/compiler' ;
910import { ErrorCode as NgCompilerErrorCode , ngErrorCode } from '@angular/compiler-cli/src/ngtsc/diagnostics/index' ;
10- import { PotentialDirective , PotentialImport , TemplateTypeChecker } from '@angular/compiler-cli/src/ngtsc/typecheck/api' ;
11+ import { PotentialDirective , PotentialPipe } from '@angular/compiler-cli/src/ngtsc/typecheck/api' ;
1112import * as t from '@angular/compiler/src/render3/r3_ast' ; // t for template AST
1213import ts from 'typescript' ;
1314
@@ -19,6 +20,7 @@ import {CodeActionContext, CodeActionMeta, FixIdForCodeFixesAll} from './utils';
1920
2021const errorCodes : number [ ] = [
2122 ngErrorCode ( NgCompilerErrorCode . SCHEMA_INVALID_ELEMENT ) ,
23+ ngErrorCode ( NgCompilerErrorCode . MISSING_PIPE ) ,
2224] ;
2325
2426/**
@@ -40,43 +42,44 @@ function getCodeActions(
4042 { templateInfo, start, compiler, formatOptions, preferences, errorCode, tsLs} :
4143 CodeActionContext ) {
4244 let codeActions : ts . CodeFixAction [ ] = [ ] ;
43-
4445 const checker = compiler . getTemplateTypeChecker ( ) ;
4546 const tsChecker = compiler . programDriver . getProgram ( ) . getTypeChecker ( ) ;
4647
47- // The error must be an invalid element in tag, which is interpreted as an intended selector.
4848 const target = getTargetAtPosition ( templateInfo . template , start ) ;
49- if ( target === null || target . context . kind !== TargetNodeKind . ElementInTagContext ||
50- target . context . node instanceof t . Template ) {
49+ if ( target === null ) {
5150 return [ ] ;
5251 }
53- const missingElement = target . context . node ;
5452
55- const importOn = standaloneTraitOrNgModule ( checker , templateInfo . component ) ;
56- if ( importOn === null ) {
53+ let matches : Set < PotentialDirective > | Set < PotentialPipe > ;
54+ if ( target . context . kind === TargetNodeKind . ElementInTagContext &&
55+ target . context . node instanceof t . Element ) {
56+ const allPossibleDirectives = checker . getPotentialTemplateDirectives ( templateInfo . component ) ;
57+ matches = getDirectiveMatchesForElementTag ( target . context . node , allPossibleDirectives ) ;
58+ } else if (
59+ target . context . kind === TargetNodeKind . RawExpression &&
60+ target . context . node instanceof ASTWithName ) {
61+ const name = ( target . context . node as any ) . name ;
62+ const allPossiblePipes = checker . getPotentialPipes ( templateInfo . component ) ;
63+ matches = new Set ( allPossiblePipes . filter ( p => p . name === name ) ) ;
64+ } else {
5765 return [ ] ;
5866 }
5967
6068 // Find all possible importable directives with a matching selector.
61- const allPossibleDirectives = checker . getPotentialTemplateDirectives ( templateInfo . component ) ;
62- const matchingDirectives =
63- getDirectiveMatchesForElementTag ( missingElement , allPossibleDirectives ) ;
64- const matches = matchingDirectives . values ( ) ;
65-
66- for ( let currMatch of matches ) {
67- const currMatchSymbol = currMatch . tsSymbol . valueDeclaration ;
69+ const importOn = standaloneTraitOrNgModule ( checker , templateInfo . component ) ;
70+ if ( importOn === null ) {
71+ return [ ] ;
72+ }
73+ for ( const currMatch of matches . values ( ) ) {
74+ const currMatchSymbol = currMatch . tsSymbol . valueDeclaration ! ;
6875 const potentialImports = checker . getPotentialImportsFor ( currMatch , importOn ) ;
6976 for ( let potentialImport of potentialImports ) {
7077 let [ fileImportChanges , importName ] = updateImportsForTypescriptFile (
7178 tsChecker , importOn . getSourceFile ( ) , potentialImport , currMatchSymbol . getSourceFile ( ) ) ;
79+ // Always update the trait import, although the TS import might already be present.
7280 let traitImportChanges = updateImportsForAngularTrait ( checker , importOn , importName ) ;
73- // All quick fixes should always update the trait import; however, the TypeScript import might
74- // already be present.
75- if ( traitImportChanges . length === 0 ) {
76- continue ;
77- }
81+ if ( traitImportChanges . length === 0 ) continue ;
7882
79- // Create a code action for this import.
8083 let description = `Import ${ importName } ` ;
8184 if ( potentialImport . moduleSpecifier !== undefined ) {
8285 description += ` from '${ potentialImport . moduleSpecifier } ' on ${ importOn . name ! . text } ` ;
0 commit comments