Skip to content

Commit

Permalink
feat(compiler-cli): define interfaces to be used for TemplateTypeChec…
Browse files Browse the repository at this point in the history
…ker (#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
  • Loading branch information
atscott authored and AndrewKushnir committed Sep 10, 2020
1 parent 26f2820 commit 9e77bd3
Show file tree
Hide file tree
Showing 2 changed files with 231 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/compiler-cli/src/ngtsc/typecheck/api/index.ts
Expand Up @@ -9,3 +9,4 @@
export * from './api';
export * from './checker';
export * from './context';
export * from './symbols';
230 changes: 230 additions & 0 deletions 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;
}

0 comments on commit 9e77bd3

Please sign in to comment.