refactor(ivy): use ClassDeclaration in more ReflectionHost methods (#29209)

PR Close #29209
This commit is contained in:
George Kalpakas
2019-03-20 12:10:58 +02:00
committed by Miško Hevery
parent bb6a3632f6
commit 2790352d04
22 changed files with 291 additions and 261 deletions

View File

@ -21,7 +21,6 @@ ts_library(
"//packages/compiler-cli/src/ngtsc/scope",
"//packages/compiler-cli/src/ngtsc/testing",
"//packages/compiler-cli/src/ngtsc/translator",
"//packages/compiler-cli/src/ngtsc/util",
"@npm//typescript",
],
)

View File

@ -12,10 +12,9 @@ import {CycleAnalyzer, ImportGraph} from '../../cycles';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
import {ModuleResolver, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
import {PartialEvaluator} from '../../partial_evaluator';
import {TypeScriptReflectionHost} from '../../reflection';
import {TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection';
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
import {isNamedClassDeclaration} from '../../util/src/typescript';
import {ResourceLoader} from '../src/api';
import {ComponentDecoratorHandler} from '../src/component';

View File

@ -10,10 +10,9 @@ import * as ts from 'typescript';
import {NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
import {PartialEvaluator} from '../../partial_evaluator';
import {TypeScriptReflectionHost} from '../../reflection';
import {ClassDeclaration, TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection';
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
import {isNamedClassDeclaration} from '../../util/src/typescript';
import {DirectiveDecoratorHandler} from '../src/directive';
@ -79,5 +78,5 @@ describe('DirectiveDecoratorHandler', () => {
class TestReflectionHost extends TypeScriptReflectionHost {
hasBaseClassReturnValue = false;
hasBaseClass(node: ts.Declaration): boolean { return this.hasBaseClassReturnValue; }
hasBaseClass(clazz: ClassDeclaration): boolean { return this.hasBaseClassReturnValue; }
}

View File

@ -12,10 +12,9 @@ import * as ts from 'typescript';
import {LocalIdentifierStrategy, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
import {PartialEvaluator} from '../../partial_evaluator';
import {TypeScriptReflectionHost} from '../../reflection';
import {TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection';
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
import {isNamedClassDeclaration} from '../../util/src/typescript';
import {NgModuleDecoratorHandler} from '../src/ng_module';
import {NoopReferencesRegistry} from '../src/references_registry';

View File

@ -8,4 +8,5 @@
export * from './src/host';
export {typeNodeToValueExpr} from './src/type_to_value';
export {TypeScriptReflectionHost, filterToMembersWithDecorator, reflectIdentifierOfDeclaration, reflectNameOfDeclaration, reflectObjectLiteral, reflectTypeEntityToDeclaration} from './src/typescript';
export {TypeScriptReflectionHost, filterToMembersWithDecorator, reflectIdentifierOfDeclaration, reflectNameOfDeclaration, reflectObjectLiteral, reflectTypeEntityToDeclaration} from './src/typescript';
export {isNamedClassDeclaration, isNamedFunctionDeclaration, isNamedVariableDeclaration} from './src/util';

View File

@ -362,16 +362,13 @@ export interface ReflectionHost {
* Examine a declaration which should be of a class, and return metadata about the members of the
* class.
*
* @param declaration a TypeScript `ts.Declaration` node representing the class over which to
* reflect. If the source is in ES6 format, this will be a `ts.ClassDeclaration` node. If the
* source is in ES5 format, this might be a `ts.VariableDeclaration` as classes in ES5 are
* represented as the result of an IIFE execution.
* @param clazz a `ClassDeclaration` representing the class over which to reflect.
*
* @returns an array of `ClassMember` metadata representing the members of the class.
*
* @throws if `declaration` does not resolve to a class declaration.
*/
getMembersOfClass(clazz: ts.Declaration): ClassMember[];
getMembersOfClass(clazz: ClassDeclaration): ClassMember[];
/**
* Reflect over the constructor of a class and return metadata about its parameters.
@ -379,16 +376,13 @@ export interface ReflectionHost {
* This method only looks at the constructor of a class directly and not at any inherited
* constructors.
*
* @param declaration a TypeScript `ts.Declaration` node representing the class over which to
* reflect. If the source is in ES6 format, this will be a `ts.ClassDeclaration` node. If the
* source is in ES5 format, this might be a `ts.VariableDeclaration` as classes in ES5 are
* represented as the result of an IIFE execution.
* @param clazz a `ClassDeclaration` representing the class over which to reflect.
*
* @returns an array of `Parameter` metadata representing the parameters of the constructor, if
* a constructor exists. If the constructor exists and has 0 parameters, this array will be empty.
* If the class has no constructor, this method returns `null`.
*/
getConstructorParameters(declaration: ts.Declaration): CtorParameter[]|null;
getConstructorParameters(clazz: ClassDeclaration): CtorParameter[]|null;
/**
* Reflect over a function and return metadata about its parameters and body.
@ -478,17 +472,21 @@ export interface ReflectionHost {
isClass(node: ts.Node): node is ClassDeclaration;
/**
* Determines whether the given declaration has a base class.
* Determines whether the given declaration, which should be a class, has a base class.
*
* @param clazz a `ClassDeclaration` representing the class over which to reflect.
*/
hasBaseClass(node: ts.Declaration): boolean;
hasBaseClass(clazz: ClassDeclaration): boolean;
/**
* Get the number of generic type parameters of a given class.
*
* @param clazz a `ClassDeclaration` representing the class over which to reflect.
*
* @returns the number of type parameters of the class, if known, or `null` if the declaration
* is not a class or has an unknown number of type parameters.
*/
getGenericArityOfClass(clazz: ts.Declaration): number|null;
getGenericArityOfClass(clazz: ClassDeclaration): number|null;
/**
* Find the assigned value of a variable declaration.

View File

@ -26,17 +26,17 @@ export class TypeScriptReflectionHost implements ReflectionHost {
.filter((dec): dec is Decorator => dec !== null);
}
getMembersOfClass(declaration: ts.Declaration): ClassMember[] {
const clazz = castDeclarationToClassOrDie(declaration);
return clazz.members.map(member => this._reflectMember(member))
getMembersOfClass(clazz: ClassDeclaration): ClassMember[] {
const tsClazz = castDeclarationToClassOrDie(clazz);
return tsClazz.members.map(member => this._reflectMember(member))
.filter((member): member is ClassMember => member !== null);
}
getConstructorParameters(declaration: ts.Declaration): CtorParameter[]|null {
const clazz = castDeclarationToClassOrDie(declaration);
getConstructorParameters(clazz: ClassDeclaration): CtorParameter[]|null {
const tsClazz = castDeclarationToClassOrDie(clazz);
// First, find the constructor.
const ctor = clazz.members.find(ts.isConstructorDeclaration);
const ctor = tsClazz.members.find(ts.isConstructorDeclaration);
if (ctor === undefined) {
return null;
}
@ -139,9 +139,9 @@ export class TypeScriptReflectionHost implements ReflectionHost {
return ts.isClassDeclaration(node) && (node.name !== undefined) && ts.isIdentifier(node.name);
}
hasBaseClass(node: ts.Declaration): boolean {
return ts.isClassDeclaration(node) && node.heritageClauses !== undefined &&
node.heritageClauses.some(clause => clause.token === ts.SyntaxKind.ExtendsKeyword);
hasBaseClass(clazz: ClassDeclaration): boolean {
return ts.isClassDeclaration(clazz) && clazz.heritageClauses !== undefined &&
clazz.heritageClauses.some(clause => clause.token === ts.SyntaxKind.ExtendsKeyword);
}
getDeclarationOfIdentifier(id: ts.Identifier): Declaration|null {
@ -166,7 +166,7 @@ export class TypeScriptReflectionHost implements ReflectionHost {
};
}
getGenericArityOfClass(clazz: ts.Declaration): number|null {
getGenericArityOfClass(clazz: ClassDeclaration): number|null {
if (!ts.isClassDeclaration(clazz)) {
return null;
}
@ -419,7 +419,8 @@ export function reflectObjectLiteral(node: ts.ObjectLiteralExpression): Map<stri
return map;
}
function castDeclarationToClassOrDie(declaration: ts.Declaration): ts.ClassDeclaration {
function castDeclarationToClassOrDie(declaration: ClassDeclaration):
ClassDeclaration<ts.ClassDeclaration> {
if (!ts.isClassDeclaration(declaration)) {
throw new Error(
`Reflecting on a ${ts.SyntaxKind[declaration.kind]} instead of a ClassDeclaration.`);

View File

@ -0,0 +1,27 @@
/**
* @license
* Copyright Google Inc. 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 * as ts from 'typescript';
import {ClassDeclaration} from './host';
export function isNamedClassDeclaration(node: ts.Node):
node is ClassDeclaration<ts.ClassDeclaration>&{name: ts.Identifier} {
return ts.isClassDeclaration(node) && (node.name !== undefined);
}
export function isNamedFunctionDeclaration(node: ts.Node):
node is ClassDeclaration<ts.FunctionDeclaration>&{name: ts.Identifier} {
return ts.isFunctionDeclaration(node) && (node.name !== undefined);
}
export function isNamedVariableDeclaration(node: ts.Node):
node is ClassDeclaration<ts.VariableDeclaration>&{name: ts.Identifier} {
return ts.isVariableDeclaration(node) && (node.name !== undefined);
}

View File

@ -11,6 +11,7 @@ import * as ts from 'typescript';
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
import {CtorParameter} from '../src/host';
import {TypeScriptReflectionHost} from '../src/typescript';
import {isNamedClassDeclaration} from '../src/util';
describe('reflector', () => {
describe('ctor params', () => {
@ -25,7 +26,7 @@ describe('reflector', () => {
}
`
}]);
const clazz = getDeclaration(program, 'entry.ts', 'Foo', ts.isClassDeclaration);
const clazz = getDeclaration(program, 'entry.ts', 'Foo', isNamedClassDeclaration);
const checker = program.getTypeChecker();
const host = new TypeScriptReflectionHost(checker);
const args = host.getConstructorParameters(clazz) !;
@ -54,7 +55,7 @@ describe('reflector', () => {
`
}
]);
const clazz = getDeclaration(program, 'entry.ts', 'Foo', ts.isClassDeclaration);
const clazz = getDeclaration(program, 'entry.ts', 'Foo', isNamedClassDeclaration);
const checker = program.getTypeChecker();
const host = new TypeScriptReflectionHost(checker);
const args = host.getConstructorParameters(clazz) !;
@ -83,7 +84,7 @@ describe('reflector', () => {
`
}
]);
const clazz = getDeclaration(program, 'entry.ts', 'Foo', ts.isClassDeclaration);
const clazz = getDeclaration(program, 'entry.ts', 'Foo', isNamedClassDeclaration);
const checker = program.getTypeChecker();
const host = new TypeScriptReflectionHost(checker);
const args = host.getConstructorParameters(clazz) !;
@ -111,7 +112,7 @@ describe('reflector', () => {
`
}
]);
const clazz = getDeclaration(program, 'entry.ts', 'Foo', ts.isClassDeclaration);
const clazz = getDeclaration(program, 'entry.ts', 'Foo', isNamedClassDeclaration);
const checker = program.getTypeChecker();
const host = new TypeScriptReflectionHost(checker);
const args = host.getConstructorParameters(clazz) !;
@ -139,7 +140,7 @@ describe('reflector', () => {
`
}
]);
const clazz = getDeclaration(program, 'entry.ts', 'Foo', ts.isClassDeclaration);
const clazz = getDeclaration(program, 'entry.ts', 'Foo', isNamedClassDeclaration);
const checker = program.getTypeChecker();
const host = new TypeScriptReflectionHost(checker);
const args = host.getConstructorParameters(clazz) !;
@ -166,7 +167,7 @@ describe('reflector', () => {
`
}
]);
const clazz = getDeclaration(program, 'entry.ts', 'Foo', ts.isClassDeclaration);
const clazz = getDeclaration(program, 'entry.ts', 'Foo', isNamedClassDeclaration);
const checker = program.getTypeChecker();
const host = new TypeScriptReflectionHost(checker);
const args = host.getConstructorParameters(clazz) !;
@ -198,7 +199,7 @@ describe('reflector', () => {
`
}
]);
const clazz = getDeclaration(program, 'entry.ts', 'Foo', ts.isClassDeclaration);
const clazz = getDeclaration(program, 'entry.ts', 'Foo', isNamedClassDeclaration);
const checker = program.getTypeChecker();
const host = new TypeScriptReflectionHost(checker);
const args = host.getConstructorParameters(clazz) !;
@ -292,4 +293,4 @@ function argExpressionToString(name: ts.Node | null): string {
} else {
throw new Error(`Unexpected node in arg expression: ${ts.SyntaxKind[name.kind]}.`);
}
}
}

View File

@ -139,7 +139,8 @@ export class MetadataDtsModuleScopeResolver implements DtsModuleScopeResolver {
*
* @param ref `Reference` to the class of interest, with the context of how it was obtained.
*/
private readModuleMetadataFromClass(ref: Reference<ts.Declaration>): RawDependencyMetadata|null {
private readModuleMetadataFromClass(ref: Reference<ClassDeclaration>): RawDependencyMetadata
|null {
const clazz = ref.node;
const resolutionContext = clazz.getSourceFile().fileName;
// This operation is explicitly not memoized, as it depends on `ref.ownedByModuleGuess`.

View File

@ -9,8 +9,8 @@
import * as ts from 'typescript';
import {Reference} from '../../imports';
import {ClassDeclaration, ClassMemberKind, ReflectionHost, reflectTypeEntityToDeclaration} from '../../reflection';
import {isNamedClassDeclaration, nodeDebugInfo} from '../../util/src/typescript';
import {ClassDeclaration, ClassMemberKind, ReflectionHost, isNamedClassDeclaration, reflectTypeEntityToDeclaration} from '../../reflection';
import {nodeDebugInfo} from '../../util/src/typescript';
export function extractReferencesFromType(
checker: ts.TypeChecker, def: ts.TypeNode, ngModuleImportedFrom: string | null,
@ -77,7 +77,7 @@ export function readStringArrayType(type: ts.TypeNode): string[] {
}
export function extractDirectiveGuards(node: ts.Declaration, reflector: ReflectionHost): {
export function extractDirectiveGuards(node: ClassDeclaration, reflector: ReflectionHost): {
ngTemplateGuards: string[],
hasNgTemplateContextGuard: boolean,
} {
@ -88,7 +88,7 @@ export function extractDirectiveGuards(node: ts.Declaration, reflector: Reflecti
return {hasNgTemplateContextGuard, ngTemplateGuards};
}
function nodeStaticMethodNames(node: ts.Declaration, reflector: ReflectionHost): string[] {
function nodeStaticMethodNames(node: ClassDeclaration, reflector: ReflectionHost): string[] {
return reflector.getMembersOfClass(node)
.filter(member => member.kind === ClassMemberKind.Method && member.isStatic)
.map(member => member.name);

View File

@ -11,9 +11,9 @@ import * as ts from 'typescript';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
import {ImportRewriter} from '../../imports';
import {ClassDeclaration, ReflectionHost, reflectNameOfDeclaration} from '../../reflection';
import {ClassDeclaration, ReflectionHost, isNamedClassDeclaration, reflectNameOfDeclaration} from '../../reflection';
import {TypeCheckContext} from '../../typecheck';
import {getSourceFile, isNamedClassDeclaration} from '../../util/src/typescript';
import {getSourceFile} from '../../util/src/typescript';
import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from './api';
import {DtsFileTransformer} from './declaration';

View File

@ -67,12 +67,11 @@ export class NgTscPlugin implements TscPlugin {
const afterDeclarations: Array<ts.TransformerFactory<ts.SourceFile|ts.Bundle>> =
[(context: ts.TransformationContext) => (sf: ts.SourceFile | ts.Bundle) => {
const visitor = (node: ts.Node): ts.Node => {
if (node.kind === ts.SyntaxKind.ClassDeclaration) {
const clz = node as ts.ClassDeclaration;
if (ts.isClassDeclaration(node)) {
// For demo purposes, transform the class name in the .d.ts output
return ts.updateClassDeclaration(
clz, clz.decorators, node.modifiers, ts.createIdentifier('NEWNAME'),
clz.typeParameters, clz.heritageClauses, clz.members);
node, node.decorators, node.modifiers, ts.createIdentifier('NEWNAME'),
node.typeParameters, node.heritageClauses, node.members);
}
return ts.visitEachChild(node, visitor, context);
};

View File

@ -12,6 +12,7 @@ ts_library(
"//packages:types",
"//packages/compiler-cli/src/ngtsc/imports",
"//packages/compiler-cli/src/ngtsc/path",
"//packages/compiler-cli/src/ngtsc/reflection",
"//packages/compiler-cli/src/ngtsc/testing",
"//packages/compiler-cli/src/ngtsc/typecheck",
"//packages/compiler-cli/src/ngtsc/util",

View File

@ -10,8 +10,9 @@ import * as ts from 'typescript';
import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, ReferenceEmitter} from '../../imports';
import {LogicalFileSystem} from '../../path';
import {isNamedClassDeclaration} from '../../reflection';
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
import {getRootDirs, isNamedClassDeclaration} from '../../util/src/typescript';
import {getRootDirs} from '../../util/src/typescript';
import {TypeCheckContext} from '../src/context';
import {TypeCheckProgramHost} from '../src/host';

View File

@ -60,11 +60,6 @@ export function isDeclaration(node: ts.Node): node is ts.Declaration {
ts.isFunctionDeclaration(node) || ts.isVariableDeclaration(node);
}
export function isNamedClassDeclaration(node: ts.Node): node is ts.ClassDeclaration&
{name: ts.Identifier} {
return ts.isClassDeclaration(node) && (node.name !== undefined);
}
export function isExported(node: ts.Declaration): boolean {
let topLevel: ts.Node = node;
if (ts.isVariableDeclaration(node) && ts.isVariableDeclarationList(node.parent)) {