From 9e77bd30875c8bb40e7b7cf11332c5843b845502 Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Mon, 17 Aug 2020 15:42:30 -0700 Subject: [PATCH] feat(compiler-cli): define interfaces to be used for TemplateTypeChecker (#38618) This commit defines the interfaces which outline the information the `TemplateTypeChecker` can return when requesting a Symbol for an item in the `TemplateAst`. Rather than providing the `ts.Symbol`, `ts.Type`, etc. information in several separate functions, the `TemplateTypeChecker` can instead provide all the useful information it knows about a particular node in the `TemplateAst` and allow the callers to determine what to do with it. PR Close #38618 --- .../src/ngtsc/typecheck/api/index.ts | 1 + .../src/ngtsc/typecheck/api/symbols.ts | 230 ++++++++++++++++++ 2 files changed, 231 insertions(+) create mode 100644 packages/compiler-cli/src/ngtsc/typecheck/api/symbols.ts diff --git a/packages/compiler-cli/src/ngtsc/typecheck/api/index.ts b/packages/compiler-cli/src/ngtsc/typecheck/api/index.ts index 5a59d80402113..c6994c26d926f 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/api/index.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/api/index.ts @@ -9,3 +9,4 @@ export * from './api'; export * from './checker'; export * from './context'; +export * from './symbols'; diff --git a/packages/compiler-cli/src/ngtsc/typecheck/api/symbols.ts b/packages/compiler-cli/src/ngtsc/typecheck/api/symbols.ts new file mode 100644 index 0000000000000..062d67b04d6cb --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/typecheck/api/symbols.ts @@ -0,0 +1,230 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {TmplAstElement, TmplAstReference, TmplAstTemplate, TmplAstVariable} from '@angular/compiler'; +import * as ts from 'typescript'; + +import {AbsoluteFsPath} from '../../file_system'; + +export enum SymbolKind { + Input, + Output, + Binding, + Reference, + Variable, + Directive, + Element, + Template, + Expression, +} + +/** + * A representation of an entity in the `TemplateAst`. + */ +export type Symbol = InputBindingSymbol|OutputBindingSymbol|ElementSymbol|ReferenceSymbol| + VariableSymbol|ExpressionSymbol|DirectiveSymbol|TemplateSymbol; + +/** Information about where a `ts.Node` can be found in the type check block shim file. */ +export interface ShimLocation { + /** + * The fully qualified path of the file which contains the generated TypeScript type check + * code for the component's template. + */ + shimPath: AbsoluteFsPath; + + /** The location in the shim file where node appears. */ + positionInShimFile: number; +} + +/** + * A generic representation of some node in a template. + */ +export interface TsNodeSymbolInfo { + /** The `ts.Type` of the template node. */ + tsType: ts.Type; + + /** The `ts.Symbol` for the template node */ + tsSymbol: ts.Symbol|null; + + /** The position of the most relevant part of the template node. */ + shimLocation: ShimLocation; +} + +/** + * A representation of an expression in a component template. + */ +export interface ExpressionSymbol { + kind: SymbolKind.Expression; + + /** The `ts.Type` of the expression AST. */ + tsType: ts.Type; + + /** + * The `ts.Symbol` of the entity. This could be `null`, for example `AST` expression + * `{{foo.bar + foo.baz}}` does not have a `ts.Symbol` but `foo.bar` and `foo.baz` both do. + */ + tsSymbol: ts.Symbol|null; + + /** The position of the most relevant part of the expression. */ + shimLocation: ShimLocation; +} + +/** Represents either an input or output binding in a template. */ +export interface BindingSymbol { + kind: SymbolKind.Binding; + + /** The `ts.Type` of the class member on the directive that is the target of the binding. */ + tsType: ts.Type; + + /** The `ts.Symbol` of the class member on the directive that is the target of the binding. */ + tsSymbol: ts.Symbol; + + /** + * The `DirectiveSymbol` or `ElementSymbol` for the Directive, Component, or `HTMLElement` with + * the binding. + */ + target: DirectiveSymbol|ElementSymbol|TemplateSymbol; + + /** The location in the shim file where the field access for the binding appears. */ + shimLocation: ShimLocation; +} + +/** + * A representation of an input binding in a component template. + */ +export interface InputBindingSymbol { + kind: SymbolKind.Input; + + /** A single input may be bound to multiple components or directives. */ + bindings: BindingSymbol[]; +} + +/** + * A representation of an output binding in a component template. + */ +export interface OutputBindingSymbol { + kind: SymbolKind.Output; + + /** A single output may be bound to multiple components or directives. */ + bindings: BindingSymbol[]; +} + +/** + * A representation of a local reference in a component template. + */ +export interface ReferenceSymbol { + kind: SymbolKind.Reference; + + /** + * The `ts.Type` of the Reference value. + * + * `TmplAstTemplate` - The type of the `TemplateRef` + * `TmplAstElement` - The `ts.Type` for the `HTMLElement`. + * Directive - The `ts.Type` for the class declaration. + */ + tsType: ts.Type; + + /** + * The `ts.Symbol` for the Reference value. + * + * `TmplAstTemplate` - A `TemplateRef` symbol. + * `TmplAstElement` - The symbol for the `HTMLElement`. + * Directive - The symbol for the class declaration of the directive. + */ + tsSymbol: ts.Symbol; + + /** + * Depending on the type of the reference, this is one of the following: + * - `TmplAstElement` when the local ref refers to the HTML element + * - `TmplAstTemplate` when the ref refers to an `ng-template` + * - `ts.ClassDeclaration` when the local ref refers to a Directive instance (#ref="myExportAs") + */ + target: TmplAstElement|TmplAstTemplate|ts.ClassDeclaration; + + /** + * The node in the `TemplateAst` where the symbol is declared. That is, node for the `#ref` or + * `#ref="exportAs"`. + */ + declaration: TmplAstReference; + + /** The location in the shim file of a variable that holds the type of the local ref. */ + shimLocation: ShimLocation; +} + +/** + * A representation of a context variable in a component template. + */ +export interface VariableSymbol { + kind: SymbolKind.Variable; + + /** + * The `ts.Type` of the entity. + * + * This will be `any` if there is no `ngTemplateContextGuard`. + */ + tsType: ts.Type; + + /** + * The `ts.Symbol` for the context variable. + * + * This will be `null` if there is no `ngTemplateContextGuard`. + */ + tsSymbol: ts.Symbol|null; + + /** + * The node in the `TemplateAst` where the variable is declared. That is, the node for the `let-` + * node in the template. + */ + declaration: TmplAstVariable; + + /** The location in the shim file of a variable that holds the type of the template variable. */ + shimLocation: ShimLocation; +} + +/** + * A representation of an element in a component template. + */ +export interface ElementSymbol { + kind: SymbolKind.Element; + + /** The `ts.Type` for the `HTMLElement`. */ + tsType: ts.Type; + + /** The `ts.Symbol` for the `HTMLElement`. */ + tsSymbol: ts.Symbol|null; + + /** A list of directives applied to the element. */ + directives: DirectiveSymbol[]; + + /** The location in the shim file for the variable that holds the type of the element. */ + shimLocation: ShimLocation; +} + +export interface TemplateSymbol { + kind: SymbolKind.Template; + + /** A list of directives applied to the element. */ + directives: DirectiveSymbol[]; +} + +/** + * A representation of a directive/component whose selector matches a node in a component + * template. + */ +export interface DirectiveSymbol { + kind: SymbolKind.Directive; + + /** The `ts.Type` for the class declaration. */ + tsType: ts.Type; + + /** The `ts.Symbol` for the class declaration. */ + tsSymbol: ts.Symbol; + + /** The location in the shim file for the variable that holds the type of the directive. */ + shimLocation: ShimLocation; +}