refactor(ivy): split apart the 'metadata' package in the ngtsc compiler (#27743)

This refactoring moves code around between a few of the ngtsc subpackages,
with the goal of having a more logical package structure. Additional
interfaces are also introduced where they make sense.

The 'metadata' package formerly contained both the partial evaluator,
the TypeScriptReflectionHost as well as some other reflection functions,
and the Reference interface and various implementations. This package
was split into 3 parts.

The partial evaluator now has its own package 'partial_evaluator', and
exists behind an interface PartialEvaluator instead of a top-level
function. In the future this will be useful for reducing churn as the
partial evaluator becomes more complicated.

The TypeScriptReflectionHost and other miscellaneous functions have moved
into a new 'reflection' package. The former 'host' package which contained
the ReflectionHost interface and associated types was also merged into this
new 'reflection' package.

Finally, the Reference APIs were moved to the 'imports' package, which will
consolidate all import-related logic in ngtsc.

PR Close #27743
This commit is contained in:
Alex Rickabaugh 2018-12-18 09:48:15 -08:00 committed by Kara Erickson
parent 37b716b298
commit 2a6108af97
64 changed files with 534 additions and 433 deletions

View File

@ -27,7 +27,8 @@ ts_library(
"//packages/compiler-cli/src/ngtsc/annotations",
"//packages/compiler-cli/src/ngtsc/diagnostics",
"//packages/compiler-cli/src/ngtsc/entry_point",
"//packages/compiler-cli/src/ngtsc/metadata",
"//packages/compiler-cli/src/ngtsc/partial_evaluator",
"//packages/compiler-cli/src/ngtsc/reflection",
"//packages/compiler-cli/src/ngtsc/shims",
"//packages/compiler-cli/src/ngtsc/switch",
"//packages/compiler-cli/src/ngtsc/transform",

View File

@ -13,8 +13,9 @@ ts_library(
"//packages:types",
"//packages/compiler",
"//packages/compiler-cli/src/ngtsc/annotations",
"//packages/compiler-cli/src/ngtsc/host",
"//packages/compiler-cli/src/ngtsc/metadata",
"//packages/compiler-cli/src/ngtsc/imports",
"//packages/compiler-cli/src/ngtsc/partial_evaluator",
"//packages/compiler-cli/src/ngtsc/reflection",
"//packages/compiler-cli/src/ngtsc/transform",
"//packages/compiler-cli/src/ngtsc/translator",
"@ngdeps//@types/convert-source-map",

View File

@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ConstantPool} from '@angular/compiler';
import {PartialEvaluator} from '@angular/compiler-cli/src/ngtsc/partial_evaluator';
import * as path from 'canonical-path';
import * as fs from 'fs';
import * as ts from 'typescript';
@ -59,16 +60,17 @@ export class FileResourceLoader implements ResourceLoader {
export class DecorationAnalyzer {
resourceLoader = new FileResourceLoader();
scopeRegistry = new SelectorScopeRegistry(this.typeChecker, this.host);
evaluator = new PartialEvaluator(this.host, this.typeChecker);
handlers: DecoratorHandler<any, any>[] = [
new BaseDefDecoratorHandler(this.typeChecker, this.host),
new BaseDefDecoratorHandler(this.host, this.evaluator),
new ComponentDecoratorHandler(
this.typeChecker, this.host, this.scopeRegistry, this.isCore, this.resourceLoader,
this.host, this.evaluator, this.scopeRegistry, this.isCore, this.resourceLoader,
this.rootDirs, /* defaultPreserveWhitespaces */ false, /* i18nUseExternalIds */ true),
new DirectiveDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore),
new DirectiveDecoratorHandler(this.host, this.evaluator, this.scopeRegistry, this.isCore),
new InjectableDecoratorHandler(this.host, this.isCore),
new NgModuleDecoratorHandler(
this.typeChecker, this.host, this.scopeRegistry, this.referencesRegistry, this.isCore),
new PipeDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore),
this.host, this.evaluator, this.scopeRegistry, this.referencesRegistry, this.isCore),
new PipeDecoratorHandler(this.host, this.evaluator, this.scopeRegistry, this.isCore),
];
constructor(

View File

@ -8,8 +8,8 @@
import * as ts from 'typescript';
import {ReferencesRegistry} from '../../../ngtsc/annotations';
import {Declaration} from '../../../ngtsc/host';
import {ResolvedReference} from '../../../ngtsc/metadata';
import {ResolvedReference} from '../../../ngtsc/imports';
import {Declaration} from '../../../ngtsc/reflection';
import {NgccReflectionHost} from '../host/ngcc_host';
import {isDefined} from '../utils';

View File

@ -8,8 +8,8 @@
import * as ts from 'typescript';
import {ReferencesRegistry} from '../../../ngtsc/annotations';
import {Declaration, ReflectionHost} from '../../../ngtsc/host';
import {Reference, ResolvedReference} from '../../../ngtsc/metadata';
import {Reference, ResolvedReference} from '../../../ngtsc/imports';
import {Declaration, ReflectionHost} from '../../../ngtsc/reflection';
import {hasNameIdentifier} from '../utils';
/**

View File

@ -8,7 +8,7 @@
import * as ts from 'typescript';
import {ReferencesRegistry} from '../../../ngtsc/annotations';
import {Declaration} from '../../../ngtsc/host';
import {Declaration} from '../../../ngtsc/reflection';
import {NgccReflectionHost} from '../host/ngcc_host';
import {hasNameIdentifier, isDefined} from '../utils';

View File

@ -7,7 +7,7 @@
*/
import * as ts from 'typescript';
import {Decorator} from '../../../ngtsc/host';
import {Decorator} from '../../../ngtsc/reflection';
/**
* A simple container that holds the details of a decorated class that has been

View File

@ -8,8 +8,7 @@
import * as ts from 'typescript';
import {ClassMember, ClassMemberKind, CtorParameter, Decorator, Import} from '../../../ngtsc/host';
import {TypeScriptReflectionHost, reflectObjectLiteral} from '../../../ngtsc/metadata';
import {ClassMember, ClassMemberKind, CtorParameter, Decorator, Import, TypeScriptReflectionHost, reflectObjectLiteral} from '../../../ngtsc/reflection';
import {BundleProgram} from '../packages/bundle_program';
import {findAll, getNameText, isDefined} from '../utils';

View File

@ -8,8 +8,7 @@
import * as ts from 'typescript';
import {ClassMember, ClassMemberKind, Decorator, FunctionDefinition, Parameter} from '../../../ngtsc/host';
import {reflectObjectLiteral} from '../../../ngtsc/metadata';
import {ClassMember, ClassMemberKind, Decorator, FunctionDefinition, Parameter, reflectObjectLiteral} from '../../../ngtsc/reflection';
import {getNameText} from '../utils';
import {Esm2015ReflectionHost, ParamInfo, getPropertyValueFromSymbol, isAssignmentStatement} from './esm2015_host';

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import * as ts from 'typescript';
import {ReflectionHost} from '../../../ngtsc/host';
import {ReflectionHost} from '../../../ngtsc/reflection';
import {DecoratedClass} from './decorated_class';
export const PRE_R3_MARKER = '__PRE_R3__';

View File

@ -13,7 +13,6 @@ import {basename, dirname, relative, resolve} from 'canonical-path';
import {SourceMapConsumer, SourceMapGenerator, RawSourceMap} from 'source-map';
import * as ts from 'typescript';
import {Decorator} from '../../../ngtsc/host';
import {CompileResult} from '@angular/compiler-cli/src/ngtsc/transform';
import {translateStatement, translateType, ImportManager} from '../../../ngtsc/translator';
import {NgccImportManager} from './ngcc_import_manager';

View File

@ -10,8 +10,9 @@ ts_library(
]),
deps = [
"//packages/compiler-cli/src/ngcc",
"//packages/compiler-cli/src/ngtsc/host",
"//packages/compiler-cli/src/ngtsc/metadata",
"//packages/compiler-cli/src/ngtsc/imports",
"//packages/compiler-cli/src/ngtsc/partial_evaluator",
"//packages/compiler-cli/src/ngtsc/reflection",
"//packages/compiler-cli/src/ngtsc/testing",
"//packages/compiler-cli/src/ngtsc/transform",
"@ngdeps//@types/convert-source-map",

View File

@ -7,7 +7,7 @@
*/
import * as ts from 'typescript';
import {Decorator} from '../../../ngtsc/host';
import {Decorator} from '../../../ngtsc/reflection';
import {DecoratorHandler} from '../../../ngtsc/transform';
import {DecorationAnalyses, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';

View File

@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ResolvedReference} from '@angular/compiler-cli/src/ngtsc/metadata';
import * as ts from 'typescript';
import {ResolvedReference} from '../../../ngtsc/imports';
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
import {PrivateDeclarationsAnalyzer} from '../../src/analysis/private_declarations_analyzer';
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';

View File

@ -8,7 +8,9 @@
import * as ts from 'typescript';
import {Reference, TypeScriptReflectionHost, staticallyResolve} from '../../../ngtsc/metadata';
import {Reference} from '../../../ngtsc/imports';
import {PartialEvaluator} from '../../../ngtsc/partial_evaluator';
import {TypeScriptReflectionHost} from '../../../ngtsc/reflection';
import {getDeclaration, makeProgram} from '../../../ngtsc/testing/in_memory_typescript';
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
@ -37,10 +39,10 @@ describe('NgccReferencesRegistry', () => {
const testArrayExpression = testArrayDeclaration.initializer !;
const host = new TypeScriptReflectionHost(checker);
const evaluator = new PartialEvaluator(host, checker);
const registry = new NgccReferencesRegistry(host);
const references =
staticallyResolve(testArrayExpression, host, checker) as Reference<ts.Declaration>[];
const references = evaluator.evaluate(testArrayExpression) as Reference<ts.Declaration>[];
registry.add(...references);
const map = registry.getDeclarationMap();

View File

@ -8,7 +8,7 @@
import * as ts from 'typescript';
import {ClassMemberKind, Import} from '../../../ngtsc/host';
import {ClassMemberKind, Import} from '../../../ngtsc/reflection';
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
import {convertToDirectTsLibImport, getDeclaration, makeTestProgram} from '../helpers/utils';

View File

@ -8,7 +8,7 @@
import * as ts from 'typescript';
import {ClassMemberKind, Import} from '../../../ngtsc/host';
import {ClassMemberKind, Import} from '../../../ngtsc/reflection';
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
import {getDeclaration, makeTestBundleProgram, makeTestProgram} from '../helpers/utils';

View File

@ -8,7 +8,7 @@
import * as ts from 'typescript';
import {ClassMemberKind, Import} from '../../../ngtsc/host';
import {ClassMemberKind, Import} from '../../../ngtsc/reflection';
import {Esm5ReflectionHost} from '../../src/host/esm5_host';
import {convertToDirectTsLibImport, getDeclaration, makeTestProgram} from '../helpers/utils';

View File

@ -8,7 +8,7 @@
import * as ts from 'typescript';
import {ClassMemberKind, Import} from '../../../ngtsc/host';
import {ClassMemberKind, Import} from '../../../ngtsc/reflection';
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
import {Esm5ReflectionHost} from '../../src/host/esm5_host';
import {getDeclaration, makeTestProgram} from '../helpers/utils';

View File

@ -12,8 +12,9 @@ ts_library(
deps = [
"//packages/compiler",
"//packages/compiler-cli/src/ngtsc/diagnostics",
"//packages/compiler-cli/src/ngtsc/host",
"//packages/compiler-cli/src/ngtsc/metadata",
"//packages/compiler-cli/src/ngtsc/imports",
"//packages/compiler-cli/src/ngtsc/partial_evaluator",
"//packages/compiler-cli/src/ngtsc/reflection",
"//packages/compiler-cli/src/ngtsc/transform",
"//packages/compiler-cli/src/ngtsc/typecheck",
"@ngdeps//@types/node",

View File

@ -9,8 +9,8 @@
import {R3BaseRefMetaData, compileBaseDefFromMetadata} from '@angular/compiler';
import * as ts from 'typescript';
import {ClassMember, Decorator, ReflectionHost} from '../../host';
import {staticallyResolve} from '../../metadata';
import {PartialEvaluator} from '../../partial_evaluator';
import {ClassMember, Decorator, ReflectionHost} from '../../reflection';
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
import {isAngularCore} from './util';
@ -26,7 +26,7 @@ function containsNgTopLevelDecorator(decorators: Decorator[] | null): boolean {
export class BaseDefDecoratorHandler implements
DecoratorHandler<R3BaseRefMetaData, R3BaseRefDecoratorDetection> {
constructor(private checker: ts.TypeChecker, private reflector: ReflectionHost, ) {}
constructor(private reflector: ReflectionHost, private evaluator: PartialEvaluator) {}
detect(node: ts.ClassDeclaration, decorators: Decorator[]|null): R3BaseRefDecoratorDetection
|undefined {
@ -69,7 +69,7 @@ export class BaseDefDecoratorHandler implements
const args = decorator.args;
let value: string|[string, string];
if (args && args.length > 0) {
const resolvedValue = staticallyResolve(args[0], this.reflector, this.checker);
const resolvedValue = this.evaluator.evaluate(args[0]);
if (typeof resolvedValue !== 'string') {
throw new TypeError('Input alias does not resolve to a string value');
}
@ -88,7 +88,7 @@ export class BaseDefDecoratorHandler implements
const args = decorator.args;
let value: string;
if (args && args.length > 0) {
const resolvedValue = staticallyResolve(args[0], this.reflector, this.checker);
const resolvedValue = this.evaluator.evaluate(args[0]);
if (typeof resolvedValue !== 'string') {
throw new TypeError('Output alias does not resolve to a string value');
}

View File

@ -11,8 +11,9 @@ import * as path from 'path';
import * as ts from 'typescript';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
import {Decorator, ReflectionHost} from '../../host';
import {AbsoluteReference, Reference, ResolvedReference, filterToMembersWithDecorator, reflectObjectLiteral, staticallyResolve} from '../../metadata';
import {ResolvedReference} from '../../imports';
import {PartialEvaluator} from '../../partial_evaluator';
import {Decorator, ReflectionHost, filterToMembersWithDecorator, reflectObjectLiteral} from '../../reflection';
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
import {TypeCheckContext, TypeCheckableDirectiveMeta} from '../../typecheck';
@ -37,7 +38,7 @@ export interface ComponentHandlerData {
export class ComponentDecoratorHandler implements
DecoratorHandler<ComponentHandlerData, Decorator> {
constructor(
private checker: ts.TypeChecker, private reflector: ReflectionHost,
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
private scopeRegistry: SelectorScopeRegistry, private isCore: boolean,
private resourceLoader: ResourceLoader, private rootDirs: string[],
private defaultPreserveWhitespaces: boolean, private i18nUseExternalIds: boolean) {}
@ -62,7 +63,7 @@ export class ComponentDecoratorHandler implements
if (this.resourceLoader.preload !== undefined && component.has('templateUrl')) {
const templateUrlExpr = component.get('templateUrl') !;
const templateUrl = staticallyResolve(templateUrlExpr, this.reflector, this.checker);
const templateUrl = this.evaluator.evaluate(templateUrlExpr);
if (typeof templateUrl !== 'string') {
throw new FatalDiagnosticError(
ErrorCode.VALUE_HAS_WRONG_TYPE, templateUrlExpr, 'templateUrl must be a string');
@ -97,7 +98,7 @@ export class ComponentDecoratorHandler implements
// @Component inherits @Directive, so begin by extracting the @Directive metadata and building
// on it.
const directiveResult = extractDirectiveMetadata(
node, decorator, this.checker, this.reflector, this.isCore,
node, decorator, this.reflector, this.evaluator, this.isCore,
this.elementSchemaRegistry.getDefaultComponentElementName());
if (directiveResult === undefined) {
// `extractDirectiveMetadata` returns undefined when the @Directive has `jit: true`. In this
@ -112,7 +113,7 @@ export class ComponentDecoratorHandler implements
let templateStr: string|null = null;
if (component.has('templateUrl')) {
const templateUrlExpr = component.get('templateUrl') !;
const templateUrl = staticallyResolve(templateUrlExpr, this.reflector, this.checker);
const templateUrl = this.evaluator.evaluate(templateUrlExpr);
if (typeof templateUrl !== 'string') {
throw new FatalDiagnosticError(
ErrorCode.VALUE_HAS_WRONG_TYPE, templateUrlExpr, 'templateUrl must be a string');
@ -120,7 +121,7 @@ export class ComponentDecoratorHandler implements
templateStr = this.resourceLoader.load(templateUrl, containingFile);
} else if (component.has('template')) {
const templateExpr = component.get('template') !;
const resolvedTemplate = staticallyResolve(templateExpr, this.reflector, this.checker);
const resolvedTemplate = this.evaluator.evaluate(templateExpr);
if (typeof resolvedTemplate !== 'string') {
throw new FatalDiagnosticError(
ErrorCode.VALUE_HAS_WRONG_TYPE, templateExpr, 'template must be a string');
@ -134,7 +135,7 @@ export class ComponentDecoratorHandler implements
let preserveWhitespaces: boolean = this.defaultPreserveWhitespaces;
if (component.has('preserveWhitespaces')) {
const expr = component.get('preserveWhitespaces') !;
const value = staticallyResolve(expr, this.reflector, this.checker);
const value = this.evaluator.evaluate(expr);
if (typeof value !== 'boolean') {
throw new FatalDiagnosticError(
ErrorCode.VALUE_HAS_WRONG_TYPE, expr, 'preserveWhitespaces must be a boolean');
@ -161,7 +162,7 @@ export class ComponentDecoratorHandler implements
let interpolation: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG;
if (component.has('interpolation')) {
const expr = component.get('interpolation') !;
const value = staticallyResolve(expr, this.reflector, this.checker);
const value = this.evaluator.evaluate(expr);
if (!Array.isArray(value) || value.length !== 2 ||
!value.every(element => typeof element === 'string')) {
throw new FatalDiagnosticError(
@ -200,21 +201,21 @@ export class ComponentDecoratorHandler implements
const coreModule = this.isCore ? undefined : '@angular/core';
const viewChildFromFields = queriesFromFields(
filterToMembersWithDecorator(decoratedElements, 'ViewChild', coreModule), this.reflector,
this.checker);
this.evaluator);
const viewChildrenFromFields = queriesFromFields(
filterToMembersWithDecorator(decoratedElements, 'ViewChildren', coreModule), this.reflector,
this.checker);
this.evaluator);
const viewQueries = [...viewChildFromFields, ...viewChildrenFromFields];
if (component.has('queries')) {
const queriesFromDecorator = extractQueriesFromDecorator(
component.get('queries') !, this.reflector, this.checker, this.isCore);
component.get('queries') !, this.reflector, this.evaluator, this.isCore);
viewQueries.push(...queriesFromDecorator.view);
}
let styles: string[]|null = null;
if (component.has('styles')) {
styles = parseFieldArrayValue(component, 'styles', this.reflector, this.checker);
styles = parseFieldArrayValue(component, 'styles', this.evaluator);
}
let styleUrls = this._extractStyleUrls(component);
@ -227,8 +228,7 @@ export class ComponentDecoratorHandler implements
let encapsulation: number = 0;
if (component.has('encapsulation')) {
encapsulation = parseInt(staticallyResolve(
component.get('encapsulation') !, this.reflector, this.checker) as string);
encapsulation = parseInt(this.evaluator.evaluate(component.get('encapsulation') !) as string);
}
let animations: Expression|null = null;
@ -333,7 +333,7 @@ export class ComponentDecoratorHandler implements
}
const styleUrlsExpr = component.get('styleUrls') !;
const styleUrls = staticallyResolve(styleUrlsExpr, this.reflector, this.checker);
const styleUrls = this.evaluator.evaluate(styleUrlsExpr);
if (!Array.isArray(styleUrls) || !styleUrls.every(url => typeof url === 'string')) {
throw new FatalDiagnosticError(
ErrorCode.VALUE_HAS_WRONG_TYPE, styleUrlsExpr, 'styleUrls must be an array of strings');

View File

@ -10,8 +10,9 @@ import {ConstantPool, Expression, R3DirectiveMetadata, R3QueryMetadata, Statemen
import * as ts from 'typescript';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
import {ClassMember, ClassMemberKind, Decorator, Import, ReflectionHost} from '../../host';
import {Reference, ResolvedReference, filterToMembersWithDecorator, reflectObjectLiteral, staticallyResolve} from '../../metadata';
import {Reference, ResolvedReference} from '../../imports';
import {PartialEvaluator} from '../../partial_evaluator';
import {ClassMember, ClassMemberKind, Decorator, ReflectionHost, filterToMembersWithDecorator, reflectObjectLiteral} from '../../reflection';
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
import {generateSetClassMetadataCall} from './metadata';
@ -27,7 +28,7 @@ export interface DirectiveHandlerData {
export class DirectiveDecoratorHandler implements
DecoratorHandler<DirectiveHandlerData, Decorator> {
constructor(
private checker: ts.TypeChecker, private reflector: ReflectionHost,
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
private scopeRegistry: SelectorScopeRegistry, private isCore: boolean) {}
detect(node: ts.Declaration, decorators: Decorator[]|null): Decorator|undefined {
@ -40,7 +41,7 @@ export class DirectiveDecoratorHandler implements
analyze(node: ts.ClassDeclaration, decorator: Decorator): AnalysisOutput<DirectiveHandlerData> {
const directiveResult =
extractDirectiveMetadata(node, decorator, this.checker, this.reflector, this.isCore);
extractDirectiveMetadata(node, decorator, this.reflector, this.evaluator, this.isCore);
const analysis = directiveResult && directiveResult.metadata;
// If the directive has a selector, it should be registered with the `SelectorScopeRegistry` so
@ -92,8 +93,8 @@ export class DirectiveDecoratorHandler implements
* Helper function to extract metadata from a `Directive` or `Component`.
*/
export function extractDirectiveMetadata(
clazz: ts.ClassDeclaration, decorator: Decorator, checker: ts.TypeChecker,
reflector: ReflectionHost, isCore: boolean, defaultSelector: string | null = null): {
clazz: ts.ClassDeclaration, decorator: Decorator, reflector: ReflectionHost,
evaluator: PartialEvaluator, isCore: boolean, defaultSelector: string | null = null): {
decorator: Map<string, ts.Expression>,
metadata: R3DirectiveMetadata,
decoratedElements: ClassMember[],
@ -127,29 +128,29 @@ export function extractDirectiveMetadata(
// Construct the map of inputs both from the @Directive/@Component
// decorator, and the decorated
// fields.
const inputsFromMeta = parseFieldToPropertyMapping(directive, 'inputs', reflector, checker);
const inputsFromMeta = parseFieldToPropertyMapping(directive, 'inputs', evaluator);
const inputsFromFields = parseDecoratedFields(
filterToMembersWithDecorator(decoratedElements, 'Input', coreModule), reflector, checker,
filterToMembersWithDecorator(decoratedElements, 'Input', coreModule), evaluator,
resolveInput);
// And outputs.
const outputsFromMeta = parseFieldToPropertyMapping(directive, 'outputs', reflector, checker);
const outputsFromMeta = parseFieldToPropertyMapping(directive, 'outputs', evaluator);
const outputsFromFields = parseDecoratedFields(
filterToMembersWithDecorator(decoratedElements, 'Output', coreModule), reflector, checker,
filterToMembersWithDecorator(decoratedElements, 'Output', coreModule), evaluator,
resolveOutput) as{[field: string]: string};
// Construct the list of queries.
const contentChildFromFields = queriesFromFields(
filterToMembersWithDecorator(decoratedElements, 'ContentChild', coreModule), reflector,
checker);
evaluator);
const contentChildrenFromFields = queriesFromFields(
filterToMembersWithDecorator(decoratedElements, 'ContentChildren', coreModule), reflector,
checker);
evaluator);
const queries = [...contentChildFromFields, ...contentChildrenFromFields];
if (directive.has('queries')) {
const queriesFromDecorator =
extractQueriesFromDecorator(directive.get('queries') !, reflector, checker, isCore);
extractQueriesFromDecorator(directive.get('queries') !, reflector, evaluator, isCore);
queries.push(...queriesFromDecorator.content);
}
@ -157,7 +158,7 @@ export function extractDirectiveMetadata(
let selector = defaultSelector;
if (directive.has('selector')) {
const expr = directive.get('selector') !;
const resolved = staticallyResolve(expr, reflector, checker);
const resolved = evaluator.evaluate(expr);
if (typeof resolved !== 'string') {
throw new FatalDiagnosticError(
ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `selector must be a string`);
@ -165,7 +166,7 @@ export function extractDirectiveMetadata(
selector = resolved;
}
const host = extractHostBindings(directive, decoratedElements, reflector, checker, coreModule);
const host = extractHostBindings(directive, decoratedElements, evaluator, coreModule);
const providers: Expression|null =
directive.has('providers') ? new WrappedNodeExpr(directive.get('providers') !) : null;
@ -179,7 +180,7 @@ export function extractDirectiveMetadata(
let exportAs: string|null = null;
if (directive.has('exportAs')) {
const expr = directive.get('exportAs') !;
const resolved = staticallyResolve(expr, reflector, checker);
const resolved = evaluator.evaluate(expr);
if (typeof resolved !== 'string') {
throw new FatalDiagnosticError(
ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `exportAs must be a string`);
@ -207,14 +208,14 @@ export function extractDirectiveMetadata(
export function extractQueryMetadata(
exprNode: ts.Node, name: string, args: ReadonlyArray<ts.Expression>, propertyName: string,
reflector: ReflectionHost, checker: ts.TypeChecker): R3QueryMetadata {
reflector: ReflectionHost, evaluator: PartialEvaluator): R3QueryMetadata {
if (args.length === 0) {
throw new FatalDiagnosticError(
ErrorCode.DECORATOR_ARITY_WRONG, exprNode, `@${name} must have arguments`);
}
const first = name === 'ViewChild' || name === 'ContentChild';
const node = unwrapForwardRef(args[0], reflector);
const arg = staticallyResolve(node, reflector, checker);
const arg = evaluator.evaluate(node);
// Extract the predicate
let predicate: Expression|string[]|null = null;
@ -244,7 +245,7 @@ export function extractQueryMetadata(
}
if (options.has('descendants')) {
const descendantsValue = staticallyResolve(options.get('descendants') !, reflector, checker);
const descendantsValue = evaluator.evaluate(options.get('descendants') !);
if (typeof descendantsValue !== 'boolean') {
throw new Error(`@${name} options.descendants must be a boolean`);
}
@ -261,7 +262,7 @@ export function extractQueryMetadata(
}
export function extractQueriesFromDecorator(
queryData: ts.Expression, reflector: ReflectionHost, checker: ts.TypeChecker,
queryData: ts.Expression, reflector: ReflectionHost, evaluator: PartialEvaluator,
isCore: boolean): {
content: R3QueryMetadata[],
view: R3QueryMetadata[],
@ -283,7 +284,7 @@ export function extractQueriesFromDecorator(
}
const query = extractQueryMetadata(
queryExpr, type.name, queryExpr.arguments || [], propertyName, reflector, checker);
queryExpr, type.name, queryExpr.arguments || [], propertyName, reflector, evaluator);
if (type.name.startsWith('Content')) {
content.push(query);
} else {
@ -307,14 +308,14 @@ function isStringArrayOrDie(value: any, name: string): value is string[] {
}
export function parseFieldArrayValue(
directive: Map<string, ts.Expression>, field: string, reflector: ReflectionHost,
checker: ts.TypeChecker): null|string[] {
directive: Map<string, ts.Expression>, field: string, evaluator: PartialEvaluator): null|
string[] {
if (!directive.has(field)) {
return null;
}
// Resolve the field of interest from the directive metadata to a string[].
const value = staticallyResolve(directive.get(field) !, reflector, checker);
const value = evaluator.evaluate(directive.get(field) !);
if (!isStringArrayOrDie(value, field)) {
throw new Error(`Failed to resolve @Directive.${field}`);
}
@ -327,9 +328,9 @@ export function parseFieldArrayValue(
* correctly shaped metadata object.
*/
function parseFieldToPropertyMapping(
directive: Map<string, ts.Expression>, field: string, reflector: ReflectionHost,
checker: ts.TypeChecker): {[field: string]: string} {
const metaValues = parseFieldArrayValue(directive, field, reflector, checker);
directive: Map<string, ts.Expression>, field: string,
evaluator: PartialEvaluator): {[field: string]: string} {
const metaValues = parseFieldArrayValue(directive, field, evaluator);
if (!metaValues) {
return EMPTY_OBJECT;
}
@ -350,8 +351,7 @@ function parseFieldToPropertyMapping(
* object.
*/
function parseDecoratedFields(
fields: {member: ClassMember, decorators: Decorator[]}[], reflector: ReflectionHost,
checker: ts.TypeChecker,
fields: {member: ClassMember, decorators: Decorator[]}[], evaluator: PartialEvaluator,
mapValueResolver: (publicName: string, internalName: string) =>
string | [string, string]): {[field: string]: string | [string, string]} {
return fields.reduce(
@ -363,7 +363,7 @@ function parseDecoratedFields(
if (decorator.args == null || decorator.args.length === 0) {
results[fieldName] = fieldName;
} else if (decorator.args.length === 1) {
const property = staticallyResolve(decorator.args[0], reflector, checker);
const property = evaluator.evaluate(decorator.args[0]);
if (typeof property !== 'string') {
throw new Error(`Decorator argument must resolve to a string`);
}
@ -389,7 +389,7 @@ function resolveOutput(publicName: string, internalName: string) {
export function queriesFromFields(
fields: {member: ClassMember, decorators: Decorator[]}[], reflector: ReflectionHost,
checker: ts.TypeChecker): R3QueryMetadata[] {
evaluator: PartialEvaluator): R3QueryMetadata[] {
return fields.map(({member, decorators}) => {
if (decorators.length !== 1) {
throw new Error(`Cannot have multiple query decorators on the same class member`);
@ -398,7 +398,7 @@ export function queriesFromFields(
}
const decorator = decorators[0];
return extractQueryMetadata(
decorator.node, decorator.name, decorator.args || [], member.name, reflector, checker);
decorator.node, decorator.name, decorator.args || [], member.name, reflector, evaluator);
});
}
@ -412,8 +412,8 @@ type StringMap = {
};
function extractHostBindings(
metadata: Map<string, ts.Expression>, members: ClassMember[], reflector: ReflectionHost,
checker: ts.TypeChecker, coreModule: string | undefined): {
metadata: Map<string, ts.Expression>, members: ClassMember[], evaluator: PartialEvaluator,
coreModule: string | undefined): {
attributes: StringMap,
listeners: StringMap,
properties: StringMap,
@ -421,7 +421,7 @@ function extractHostBindings(
let hostMetadata: StringMap = {};
if (metadata.has('host')) {
const expr = metadata.get('host') !;
const hostMetaMap = staticallyResolve(expr, reflector, checker);
const hostMetaMap = evaluator.evaluate(expr);
if (!(hostMetaMap instanceof Map)) {
throw new FatalDiagnosticError(
ErrorCode.DECORATOR_ARG_NOT_LITERAL, expr, `Decorator host metadata must be an object`);
@ -445,7 +445,7 @@ function extractHostBindings(
throw new Error(`@HostBinding() can have at most one argument`);
}
const resolved = staticallyResolve(decorator.args[0], reflector, checker);
const resolved = evaluator.evaluate(decorator.args[0]);
if (typeof resolved !== 'string') {
throw new Error(`@HostBinding()'s argument must be a string`);
}
@ -469,7 +469,7 @@ function extractHostBindings(
`@HostListener() can have at most two arguments`);
}
const resolved = staticallyResolve(decorator.args[0], reflector, checker);
const resolved = evaluator.evaluate(decorator.args[0]);
if (typeof resolved !== 'string') {
throw new FatalDiagnosticError(
ErrorCode.VALUE_HAS_WRONG_TYPE, decorator.args[0],
@ -479,7 +479,7 @@ function extractHostBindings(
eventName = resolved;
if (decorator.args.length === 2) {
const resolvedArgs = staticallyResolve(decorator.args[1], reflector, checker);
const resolvedArgs = evaluator.evaluate(decorator.args[1]);
if (!isStringArrayOrDie(resolvedArgs, '@HostListener.args')) {
throw new FatalDiagnosticError(
ErrorCode.VALUE_HAS_WRONG_TYPE, decorator.args[1],

View File

@ -10,8 +10,7 @@ import {Expression, LiteralExpr, R3DependencyMetadata, R3InjectableMetadata, R3R
import * as ts from 'typescript';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
import {Decorator, ReflectionHost} from '../../host';
import {reflectObjectLiteral} from '../../metadata';
import {Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection';
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
import {generateSetClassMetadataCall} from './metadata';

View File

@ -9,7 +9,7 @@
import {ExternalExpr, Identifiers, InvokeFunctionExpr, Statement, WrappedNodeExpr} from '@angular/compiler';
import * as ts from 'typescript';
import {CtorParameter, Decorator, ReflectionHost} from '../../host';
import {CtorParameter, Decorator, ReflectionHost} from '../../reflection';
/**
* Given a class declaration, generate a call to `setClassMetadata` with the Angular metadata

View File

@ -10,8 +10,9 @@ import {Expression, LiteralArrayExpr, R3InjectorMetadata, R3NgModuleMetadata, R3
import * as ts from 'typescript';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
import {Decorator, ReflectionHost} from '../../host';
import {Reference, ResolvedReference, ResolvedValue, reflectObjectLiteral, staticallyResolve, typeNodeToValueExpr} from '../../metadata';
import {Reference, ResolvedReference} from '../../imports';
import {PartialEvaluator, ResolvedValue} from '../../partial_evaluator';
import {Decorator, ReflectionHost, reflectObjectLiteral, typeNodeToValueExpr} from '../../reflection';
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
import {generateSetClassMetadataCall} from './metadata';
@ -32,7 +33,7 @@ export interface NgModuleAnalysis {
*/
export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalysis, Decorator> {
constructor(
private checker: ts.TypeChecker, private reflector: ReflectionHost,
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
private scopeRegistry: SelectorScopeRegistry, private referencesRegistry: ReferencesRegistry,
private isCore: boolean) {}
@ -72,32 +73,30 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
let declarations: Reference<ts.Declaration>[] = [];
if (ngModule.has('declarations')) {
const expr = ngModule.get('declarations') !;
const declarationMeta = staticallyResolve(expr, this.reflector, this.checker);
const declarationMeta = this.evaluator.evaluate(expr);
declarations = this.resolveTypeList(expr, declarationMeta, 'declarations');
this.referencesRegistry.add(...declarations);
}
let imports: Reference<ts.Declaration>[] = [];
if (ngModule.has('imports')) {
const expr = ngModule.get('imports') !;
const importsMeta = staticallyResolve(
expr, this.reflector, this.checker,
ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
const importsMeta = this.evaluator.evaluate(
expr, ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
imports = this.resolveTypeList(expr, importsMeta, 'imports');
this.referencesRegistry.add(...imports);
}
let exports: Reference<ts.Declaration>[] = [];
if (ngModule.has('exports')) {
const expr = ngModule.get('exports') !;
const exportsMeta = staticallyResolve(
expr, this.reflector, this.checker,
ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
const exportsMeta = this.evaluator.evaluate(
expr, ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
exports = this.resolveTypeList(expr, exportsMeta, 'exports');
this.referencesRegistry.add(...exports);
}
let bootstrap: Reference<ts.Declaration>[] = [];
if (ngModule.has('bootstrap')) {
const expr = ngModule.get('bootstrap') !;
const bootstrapMeta = staticallyResolve(expr, this.reflector, this.checker);
const bootstrapMeta = this.evaluator.evaluate(expr);
bootstrap = this.resolveTypeList(expr, bootstrapMeta, 'bootstrap');
this.referencesRegistry.add(...bootstrap);
}

View File

@ -10,8 +10,8 @@ import {LiteralExpr, R3PipeMetadata, Statement, WrappedNodeExpr, compilePipeFrom
import * as ts from 'typescript';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
import {Decorator, ReflectionHost} from '../../host';
import {reflectObjectLiteral, staticallyResolve} from '../../metadata';
import {PartialEvaluator} from '../../partial_evaluator';
import {Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection';
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
import {generateSetClassMetadataCall} from './metadata';
@ -25,7 +25,7 @@ export interface PipeHandlerData {
export class PipeDecoratorHandler implements DecoratorHandler<PipeHandlerData, Decorator> {
constructor(
private checker: ts.TypeChecker, private reflector: ReflectionHost,
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
private scopeRegistry: SelectorScopeRegistry, private isCore: boolean) {}
detect(node: ts.Declaration, decorators: Decorator[]|null): Decorator|undefined {
@ -63,7 +63,7 @@ export class PipeDecoratorHandler implements DecoratorHandler<PipeHandlerData, D
ErrorCode.PIPE_MISSING_NAME, meta, `@Pipe decorator is missing name field`);
}
const pipeNameExpr = pipe.get('name') !;
const pipeName = staticallyResolve(pipeNameExpr, this.reflector, this.checker);
const pipeName = this.evaluator.evaluate(pipeNameExpr);
if (typeof pipeName !== 'string') {
throw new FatalDiagnosticError(
ErrorCode.VALUE_HAS_WRONG_TYPE, pipeNameExpr, `@Pipe.name must be a string`);
@ -73,7 +73,7 @@ export class PipeDecoratorHandler implements DecoratorHandler<PipeHandlerData, D
let pure = true;
if (pipe.has('pure')) {
const expr = pipe.get('pure') !;
const pureValue = staticallyResolve(expr, this.reflector, this.checker);
const pureValue = this.evaluator.evaluate(expr);
if (typeof pureValue !== 'boolean') {
throw new FatalDiagnosticError(
ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `@Pipe.pure must be a boolean`);

View File

@ -7,8 +7,8 @@
*/
import * as ts from 'typescript';
import {Declaration} from '../../host';
import {Reference} from '../../metadata';
import {Reference} from '../../imports';
import {Declaration} from '../../reflection';
/**
* Implement this interface if you want DecoratorHandlers to register

View File

@ -6,12 +6,11 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Expression, ExternalExpr, ExternalReference, WrappedNodeExpr} from '@angular/compiler';
import {Expression, WrappedNodeExpr} from '@angular/compiler';
import * as ts from 'typescript';
import {ReflectionHost} from '../../host';
import {AbsoluteReference, Reference, ResolvedReference, reflectTypeEntityToDeclaration} from '../../metadata';
import {reflectIdentifierOfDeclaration, reflectNameOfDeclaration} from '../../metadata/src/reflector';
import {AbsoluteReference, Reference, ResolvedReference} from '../../imports';
import {ReflectionHost, reflectIdentifierOfDeclaration, reflectNameOfDeclaration, reflectTypeEntityToDeclaration} from '../../reflection';
import {TypeCheckableDirectiveMeta} from '../../typecheck';
import {extractDirectiveGuards} from './util';

View File

@ -6,12 +6,12 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Expression, R3DependencyMetadata, R3Reference, R3ResolvedDependencyType, WrappedNodeExpr} from '@angular/compiler';
import {R3DependencyMetadata, R3Reference, R3ResolvedDependencyType, WrappedNodeExpr} from '@angular/compiler';
import * as ts from 'typescript';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
import {ClassMemberKind, Decorator, ReflectionHost} from '../../host';
import {AbsoluteReference, ImportMode, Reference} from '../../metadata';
import {AbsoluteReference, ImportMode, Reference} from '../../imports';
import {ClassMemberKind, Decorator, ReflectionHost} from '../../reflection';
export function getConstructorDependencies(
clazz: ts.ClassDeclaration, reflector: ReflectionHost, isCore: boolean): R3DependencyMetadata[]|

View File

@ -13,7 +13,9 @@ ts_library(
"//packages/compiler",
"//packages/compiler-cli/src/ngtsc/annotations",
"//packages/compiler-cli/src/ngtsc/diagnostics",
"//packages/compiler-cli/src/ngtsc/metadata",
"//packages/compiler-cli/src/ngtsc/imports",
"//packages/compiler-cli/src/ngtsc/partial_evaluator",
"//packages/compiler-cli/src/ngtsc/reflection",
"//packages/compiler-cli/src/ngtsc/testing",
"//packages/compiler-cli/src/ngtsc/translator",
"@ngdeps//typescript",

View File

@ -9,7 +9,9 @@
import * as ts from 'typescript';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
import {TypeScriptReflectionHost} from '../../metadata';
import {PartialEvaluator} from '../../partial_evaluator';
import {TypeScriptReflectionHost} from '../../reflection';
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
import {ResourceLoader} from '../src/api';
import {ComponentDecoratorHandler} from '../src/component';
@ -38,8 +40,9 @@ describe('ComponentDecoratorHandler', () => {
]);
const checker = program.getTypeChecker();
const host = new TypeScriptReflectionHost(checker);
const evaluator = new PartialEvaluator(host, checker);
const handler = new ComponentDecoratorHandler(
checker, host, new SelectorScopeRegistry(checker, host), false, new NoopResourceLoader(),
host, evaluator, new SelectorScopeRegistry(checker, host), false, new NoopResourceLoader(),
[''], false, true);
const TestCmp = getDeclaration(program, 'entry.ts', 'TestCmp', ts.isClassDeclaration);
const detected = handler.detect(TestCmp, host.getDecoratorsOfDeclaration(TestCmp));

View File

@ -6,12 +6,12 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Statement} from '@angular/compiler';
import * as ts from 'typescript';
import {TypeScriptReflectionHost} from '../../metadata';
import {TypeScriptReflectionHost} from '../../reflection';
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
import {ImportManager, translateStatement} from '../../translator';
import {generateSetClassMetadataCall} from '../src/metadata';
const CORE = {

View File

@ -8,10 +8,10 @@
import * as ts from 'typescript';
import {TypeScriptReflectionHost} from '../../metadata';
import {AbsoluteReference, ResolvedReference} from '../../metadata/src/resolver';
import {AbsoluteReference, ResolvedReference} from '../../imports';
import {TypeScriptReflectionHost} from '../../reflection';
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
import {NgModuleDecoratorHandler} from '../src/ng_module';
import {SelectorScopeRegistry} from '../src/selector_scope';
describe('SelectorScopeRegistry', () => {

View File

@ -0,0 +1,18 @@
package(default_visibility = ["//visibility:public"])
load("//tools:defaults.bzl", "ts_library")
ts_library(
name = "imports",
srcs = glob([
"index.ts",
"src/*.ts",
]),
module_name = "@angular/compiler-cli/src/ngtsc/imports",
deps = [
"//packages:types",
"//packages/compiler",
"@ngdeps//@types/node",
"@ngdeps//typescript",
],
)

View File

@ -6,4 +6,4 @@
* found in the LICENSE file at https://angular.io/license
*/
export * from './src/reflection';
export {AbsoluteReference, ImportMode, NodeReference, Reference, ResolvedReference} from './src/references';

View File

@ -0,0 +1,150 @@
/**
* @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
*/
/// <reference types="node" />
import {Expression, ExternalExpr, ExternalReference, WrappedNodeExpr} from '@angular/compiler';
import * as path from 'path';
import * as ts from 'typescript';
const TS_DTS_JS_EXTENSION = /(?:\.d)?\.ts$|\.js$/;
export enum ImportMode {
UseExistingImport,
ForceNewImport,
}
/**
* A reference to a `ts.Node`.
*
* For example, if an expression evaluates to a function or class definition, it will be returned
* as a `Reference` (assuming references are allowed in evaluation).
*/
export abstract class Reference<T extends ts.Node = ts.Node> {
constructor(readonly node: T) {}
/**
* Whether an `Expression` can be generated which references the node.
*/
// TODO(issue/24571): remove '!'.
readonly expressable !: boolean;
/**
* Generate an `Expression` representing this type, in the context of the given SourceFile.
*
* This could be a local variable reference, if the symbol is imported, or it could be a new
* import if needed.
*/
abstract toExpression(context: ts.SourceFile, importMode?: ImportMode): Expression|null;
abstract addIdentifier(identifier: ts.Identifier): void;
}
/**
* A reference to a node only, without any ability to get an `Expression` representing that node.
*
* This is used for returning references to things like method declarations, which are not directly
* referenceable.
*/
export class NodeReference<T extends ts.Node = ts.Node> extends Reference<T> {
constructor(node: T, readonly moduleName: string|null) { super(node); }
toExpression(context: ts.SourceFile): null { return null; }
addIdentifier(identifier: ts.Identifier): void {}
}
/**
* A reference to a node which has a `ts.Identifier` and can be resolved to an `Expression`.
*
* Imports generated by `ResolvedReference`s are always relative.
*/
export class ResolvedReference<T extends ts.Node = ts.Node> extends Reference<T> {
protected identifiers: ts.Identifier[] = [];
constructor(node: T, protected primaryIdentifier: ts.Identifier) { super(node); }
readonly expressable = true;
toExpression(context: ts.SourceFile, importMode: ImportMode = ImportMode.UseExistingImport):
Expression {
const localIdentifier =
pickIdentifier(context, this.primaryIdentifier, this.identifiers, importMode);
if (localIdentifier !== null) {
return new WrappedNodeExpr(localIdentifier);
} else {
// Relative import from context -> this.node.getSourceFile().
// TODO(alxhub): investigate the impact of multiple source roots here.
// TODO(alxhub): investigate the need to map such paths via the Host for proper g3 support.
let relative =
path.posix.relative(path.dirname(context.fileName), this.node.getSourceFile().fileName)
.replace(TS_DTS_JS_EXTENSION, '');
// path.relative() does not include the leading './'.
if (!relative.startsWith('.')) {
relative = `./${relative}`;
}
// path.relative() returns the empty string (converted to './' above) if the two paths are the
// same.
if (relative === './') {
// Same file after all.
return new WrappedNodeExpr(this.primaryIdentifier);
} else {
return new ExternalExpr(new ExternalReference(relative, this.primaryIdentifier.text));
}
}
}
addIdentifier(identifier: ts.Identifier): void { this.identifiers.push(identifier); }
}
/**
* A reference to a node which has a `ts.Identifer` and an expected absolute module name.
*
* An `AbsoluteReference` can be resolved to an `Expression`, and if that expression is an import
* the module specifier will be an absolute module name, not a relative path.
*/
export class AbsoluteReference<T extends ts.Node> extends Reference<T> {
private identifiers: ts.Identifier[] = [];
constructor(
node: T, private primaryIdentifier: ts.Identifier, readonly moduleName: string,
readonly symbolName: string) {
super(node);
}
readonly expressable = true;
toExpression(context: ts.SourceFile, importMode: ImportMode = ImportMode.UseExistingImport):
Expression {
const localIdentifier =
pickIdentifier(context, this.primaryIdentifier, this.identifiers, importMode);
if (localIdentifier !== null) {
return new WrappedNodeExpr(localIdentifier);
} else {
return new ExternalExpr(new ExternalReference(this.moduleName, this.symbolName));
}
}
addIdentifier(identifier: ts.Identifier): void { this.identifiers.push(identifier); }
}
function pickIdentifier(
context: ts.SourceFile, primary: ts.Identifier, secondaries: ts.Identifier[],
mode: ImportMode): ts.Identifier|null {
context = ts.getOriginalNode(context) as ts.SourceFile;
if (ts.getOriginalNode(primary).getSourceFile() === context) {
return primary;
} else if (mode === ImportMode.UseExistingImport) {
return secondaries.find(id => ts.getOriginalNode(id).getSourceFile() === context) || null;
} else {
return null;
}
}

View File

@ -1,12 +0,0 @@
/**
* @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
*/
/// <reference types="node" />
export {TypeScriptReflectionHost, filterToMembersWithDecorator, findMember, reflectObjectLiteral, reflectTypeEntityToDeclaration, typeNodeToValueExpr} from './src/reflector';
export {AbsoluteReference, EnumValue, ImportMode, Reference, ResolvedReference, ResolvedValue, isDynamicValue, staticallyResolve} from './src/resolver';

View File

@ -3,16 +3,17 @@ package(default_visibility = ["//visibility:public"])
load("//tools:defaults.bzl", "ts_library")
ts_library(
name = "metadata",
name = "partial_evaluator",
srcs = glob([
"index.ts",
"src/*.ts",
]),
module_name = "@angular/compiler-cli/src/ngtsc/metadata",
module_name = "@angular/compiler-cli/src/ngtsc/partial_evaluator",
deps = [
"//packages:types",
"//packages/compiler",
"//packages/compiler-cli/src/ngtsc/host",
"//packages/compiler-cli/src/ngtsc/imports",
"//packages/compiler-cli/src/ngtsc/reflection",
"//packages/compiler-cli/src/ngtsc/util",
"@ngdeps//@types/node",
"@ngdeps//typescript",

View File

@ -0,0 +1,10 @@
/**
* @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
*/
export {ForeignFunctionResolver, PartialEvaluator} from './src/interface';
export {BuiltinFn, DynamicValue, EnumValue, ResolvedValue, ResolvedValueArray, ResolvedValueMap, isDynamicValue} from './src/result';

View File

@ -0,0 +1,21 @@
/**
* @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 {BuiltinFn, DYNAMIC_VALUE, ResolvedValue, ResolvedValueArray} from './result';
export class ArraySliceBuiltinFn extends BuiltinFn {
constructor(private lhs: ResolvedValueArray) { super(); }
evaluate(args: ResolvedValueArray): ResolvedValue {
if (args.length === 0) {
return this.lhs;
} else {
return DYNAMIC_VALUE;
}
}
}

View File

@ -0,0 +1,31 @@
/**
* @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 {Reference} from '../../imports';
import {ReflectionHost} from '../../reflection';
import {StaticInterpreter} from './interpreter';
import {ResolvedValue} from './result';
export type ForeignFunctionResolver =
(node: Reference<ts.FunctionDeclaration|ts.MethodDeclaration>, args: ts.Expression[]) =>
ts.Expression | null;
export class PartialEvaluator {
constructor(private host: ReflectionHost, private checker: ts.TypeChecker) {}
evaluate(expr: ts.Expression, foreignFunctionResolver?: ForeignFunctionResolver): ResolvedValue {
const interpreter = new StaticInterpreter(this.host, this.checker);
return interpreter.visit(expr, {
absoluteModuleName: null,
scope: new Map<ts.ParameterDeclaration, ResolvedValue>(), foreignFunctionResolver,
});
}
}

View File

@ -6,97 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/
/**
* resolver.ts implements partial computation of expressions, resolving expressions to static
* values where possible and returning a `DynamicValue` signal when not.
*/
import {Expression, ExternalExpr, ExternalReference, WrappedNodeExpr} from '@angular/compiler';
import * as path from 'path';
import * as ts from 'typescript';
import {ClassMemberKind, ReflectionHost} from '../../host';
import {AbsoluteReference, NodeReference, Reference, ResolvedReference} from '../../imports';
import {ReflectionHost} from '../../reflection';
const TS_DTS_JS_EXTENSION = /(?:\.d)?\.ts$|\.js$/;
import {ArraySliceBuiltinFn} from './builtin';
import {BuiltinFn, DYNAMIC_VALUE, EnumValue, ResolvedValue, ResolvedValueArray, ResolvedValueMap, isDynamicValue} from './result';
/**
* Represents a value which cannot be determined statically.
*
* Use `isDynamicValue` to determine whether a `ResolvedValue` is a `DynamicValue`.
*/
export class DynamicValue {
/**
* This is needed so the "is DynamicValue" assertion of `isDynamicValue` actually has meaning.
*
* Otherwise, "is DynamicValue" is akin to "is {}" which doesn't trigger narrowing.
*/
private _isDynamic = true;
}
/**
* An internal flyweight for `DynamicValue`. Eventually the dynamic value will carry information
* on the location of the node that could not be statically computed.
*/
const DYNAMIC_VALUE: DynamicValue = new DynamicValue();
/**
* Used to test whether a `ResolvedValue` is a `DynamicValue`.
*/
export function isDynamicValue(value: any): value is DynamicValue {
return value === DYNAMIC_VALUE;
}
/**
* A value resulting from static resolution.
*
* This could be a primitive, collection type, reference to a `ts.Node` that declares a
* non-primitive value, or a special `DynamicValue` type which indicates the value was not
* available statically.
*/
export type ResolvedValue = number | boolean | string | null | undefined | Reference | EnumValue |
ResolvedValueArray | ResolvedValueMap | BuiltinFn | DynamicValue;
/**
* An array of `ResolvedValue`s.
*
* This is a reified type to allow the circular reference of `ResolvedValue` -> `ResolvedValueArray`
* ->
* `ResolvedValue`.
*/
export interface ResolvedValueArray extends Array<ResolvedValue> {}
/**
* A map of strings to `ResolvedValue`s.
*
* This is a reified type to allow the circular reference of `ResolvedValue` -> `ResolvedValueMap` ->
* `ResolvedValue`.
*/ export interface ResolvedValueMap extends Map<string, ResolvedValue> {}
/**
* A value member of an enumeration.
*
* Contains a `Reference` to the enumeration itself, and the name of the referenced member.
*/
export class EnumValue {
constructor(readonly enumRef: Reference<ts.EnumDeclaration>, readonly name: string) {}
}
/**
* An implementation of a builtin function, such as `Array.prototype.slice`.
*/
export abstract class BuiltinFn { abstract evaluate(args: ResolvedValueArray): ResolvedValue; }
class ArraySliceBuiltinFn extends BuiltinFn {
constructor(private lhs: ResolvedValueArray) { super(); }
evaluate(args: ResolvedValueArray): ResolvedValue {
if (args.length === 0) {
return this.lhs;
} else {
return DYNAMIC_VALUE;
}
}
}
/**
* Tracks the scope of a function body, which includes `ResolvedValue`s for the parameters of that
@ -104,164 +21,6 @@ class ArraySliceBuiltinFn extends BuiltinFn {
*/
type Scope = Map<ts.ParameterDeclaration, ResolvedValue>;
export enum ImportMode {
UseExistingImport,
ForceNewImport,
}
/**
* A reference to a `ts.Node`.
*
* For example, if an expression evaluates to a function or class definition, it will be returned
* as a `Reference` (assuming references are allowed in evaluation).
*/
export abstract class Reference<T extends ts.Node = ts.Node> {
constructor(readonly node: T) {}
/**
* Whether an `Expression` can be generated which references the node.
*/
// TODO(issue/24571): remove '!'.
readonly expressable !: boolean;
/**
* Generate an `Expression` representing this type, in the context of the given SourceFile.
*
* This could be a local variable reference, if the symbol is imported, or it could be a new
* import if needed.
*/
abstract toExpression(context: ts.SourceFile, importMode?: ImportMode): Expression|null;
abstract addIdentifier(identifier: ts.Identifier): void;
}
/**
* A reference to a node only, without any ability to get an `Expression` representing that node.
*
* This is used for returning references to things like method declarations, which are not directly
* referenceable.
*/
export class NodeReference<T extends ts.Node = ts.Node> extends Reference<T> {
constructor(node: T, readonly moduleName: string|null) { super(node); }
toExpression(context: ts.SourceFile): null { return null; }
addIdentifier(identifier: ts.Identifier): void {}
}
/**
* A reference to a node which has a `ts.Identifier` and can be resolved to an `Expression`.
*
* Imports generated by `ResolvedReference`s are always relative.
*/
export class ResolvedReference<T extends ts.Node = ts.Node> extends Reference<T> {
protected identifiers: ts.Identifier[] = [];
constructor(node: T, protected primaryIdentifier: ts.Identifier) { super(node); }
readonly expressable = true;
toExpression(context: ts.SourceFile, importMode: ImportMode = ImportMode.UseExistingImport):
Expression {
const localIdentifier =
pickIdentifier(context, this.primaryIdentifier, this.identifiers, importMode);
if (localIdentifier !== null) {
return new WrappedNodeExpr(localIdentifier);
} else {
// Relative import from context -> this.node.getSourceFile().
// TODO(alxhub): investigate the impact of multiple source roots here.
// TODO(alxhub): investigate the need to map such paths via the Host for proper g3 support.
let relative =
path.posix.relative(path.dirname(context.fileName), this.node.getSourceFile().fileName)
.replace(TS_DTS_JS_EXTENSION, '');
// path.relative() does not include the leading './'.
if (!relative.startsWith('.')) {
relative = `./${relative}`;
}
// path.relative() returns the empty string (converted to './' above) if the two paths are the
// same.
if (relative === './') {
// Same file after all.
return new WrappedNodeExpr(this.primaryIdentifier);
} else {
return new ExternalExpr(new ExternalReference(relative, this.primaryIdentifier.text));
}
}
}
addIdentifier(identifier: ts.Identifier): void { this.identifiers.push(identifier); }
}
/**
* A reference to a node which has a `ts.Identifer` and an expected absolute module name.
*
* An `AbsoluteReference` can be resolved to an `Expression`, and if that expression is an import
* the module specifier will be an absolute module name, not a relative path.
*/
export class AbsoluteReference<T extends ts.Node> extends Reference<T> {
private identifiers: ts.Identifier[] = [];
constructor(
node: T, private primaryIdentifier: ts.Identifier, readonly moduleName: string,
readonly symbolName: string) {
super(node);
}
readonly expressable = true;
toExpression(context: ts.SourceFile, importMode: ImportMode = ImportMode.UseExistingImport):
Expression {
const localIdentifier =
pickIdentifier(context, this.primaryIdentifier, this.identifiers, importMode);
if (localIdentifier !== null) {
return new WrappedNodeExpr(localIdentifier);
} else {
return new ExternalExpr(new ExternalReference(this.moduleName, this.symbolName));
}
}
addIdentifier(identifier: ts.Identifier): void { this.identifiers.push(identifier); }
}
function pickIdentifier(
context: ts.SourceFile, primary: ts.Identifier, secondaries: ts.Identifier[],
mode: ImportMode): ts.Identifier|null {
context = ts.getOriginalNode(context) as ts.SourceFile;
if (ts.getOriginalNode(primary).getSourceFile() === context) {
return primary;
} else if (mode === ImportMode.UseExistingImport) {
return secondaries.find(id => ts.getOriginalNode(id).getSourceFile() === context) || null;
} else {
return null;
}
}
/**
* Statically resolve the given `ts.Expression` into a `ResolvedValue`.
*
* @param node the expression to statically resolve if possible
* @param checker a `ts.TypeChecker` used to understand the expression
* @param foreignFunctionResolver a function which will be used whenever a "foreign function" is
* encountered. A foreign function is a function which has no body - usually the result of calling
* a function declared in another library's .d.ts file. In these cases, the foreignFunctionResolver
* will be called with the function's declaration, and can optionally return a `ts.Expression`
* (possibly extracted from the foreign function's type signature) which will be used as the result
* of the call.
* @returns a `ResolvedValue` representing the resolved value
*/
export function staticallyResolve(
node: ts.Expression, host: ReflectionHost, checker: ts.TypeChecker,
foreignFunctionResolver?:
(node: Reference<ts.FunctionDeclaration|ts.MethodDeclaration>, args: ts.Expression[]) =>
ts.Expression | null): ResolvedValue {
return new StaticInterpreter(host, checker).visit(node, {
absoluteModuleName: null,
scope: new Map<ts.ParameterDeclaration, ResolvedValue>(), foreignFunctionResolver,
});
}
interface BinaryOperatorDef {
literal: boolean;
op: (a: any, b: any) => ResolvedValue;
@ -309,7 +68,7 @@ interface Context {
args: ReadonlyArray<ts.Expression>): ts.Expression|null;
}
class StaticInterpreter {
export class StaticInterpreter {
constructor(private host: ReflectionHost, private checker: ts.TypeChecker) {}
visit(node: ts.Expression, context: Context): ResolvedValue {

View File

@ -0,0 +1,79 @@
/**
* @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 {Reference} from '../../imports';
/**
* A value resulting from static resolution.
*
* This could be a primitive, collection type, reference to a `ts.Node` that declares a
* non-primitive value, or a special `DynamicValue` type which indicates the value was not
* available statically.
*/
export type ResolvedValue = number | boolean | string | null | undefined | Reference | EnumValue |
ResolvedValueArray | ResolvedValueMap | BuiltinFn | DynamicValue;
/**
* Represents a value which cannot be determined statically.
*
* Use `isDynamicValue` to determine whether a `ResolvedValue` is a `DynamicValue`.
*/
export class DynamicValue {
/**
* This is needed so the "is DynamicValue" assertion of `isDynamicValue` actually has meaning.
*
* Otherwise, "is DynamicValue" is akin to "is {}" which doesn't trigger narrowing.
*/
private _isDynamic = true;
}
/**
* An internal flyweight for `DynamicValue`. Eventually the dynamic value will carry information
* on the location of the node that could not be statically computed.
*/
export const DYNAMIC_VALUE: DynamicValue = new DynamicValue();
/**
* Used to test whether a `ResolvedValue` is a `DynamicValue`.
*/
export function isDynamicValue(value: any): value is DynamicValue {
return value === DYNAMIC_VALUE;
}
/**
* An array of `ResolvedValue`s.
*
* This is a reified type to allow the circular reference of `ResolvedValue` -> `ResolvedValueArray`
* ->
* `ResolvedValue`.
*/
export interface ResolvedValueArray extends Array<ResolvedValue> {}
/**
* A map of strings to `ResolvedValue`s.
*
* This is a reified type to allow the circular reference of `ResolvedValue` -> `ResolvedValueMap` ->
* `ResolvedValue`.
*/ export interface ResolvedValueMap extends Map<string, ResolvedValue> {}
/**
* A value member of an enumeration.
*
* Contains a `Reference` to the enumeration itself, and the name of the referenced member.
*/
export class EnumValue {
constructor(readonly enumRef: Reference<ts.EnumDeclaration>, readonly name: string) {}
}
/**
* An implementation of a builtin function, such as `Array.prototype.slice`.
*/
export abstract class BuiltinFn { abstract evaluate(args: ResolvedValueArray): ResolvedValue; }

View File

@ -0,0 +1,29 @@
package(default_visibility = ["//visibility:public"])
load("//tools:defaults.bzl", "jasmine_node_test", "ts_library")
ts_library(
name = "test_lib",
testonly = True,
srcs = glob([
"**/*.ts",
]),
deps = [
"//packages:types",
"//packages/compiler",
"//packages/compiler-cli/src/ngtsc/imports",
"//packages/compiler-cli/src/ngtsc/partial_evaluator",
"//packages/compiler-cli/src/ngtsc/reflection",
"//packages/compiler-cli/src/ngtsc/testing",
"@ngdeps//typescript",
],
)
jasmine_node_test(
name = "test",
bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"],
deps = [
":test_lib",
"//tools/testing:node_no_angular",
],
)

View File

@ -9,9 +9,11 @@
import {WrappedNodeExpr} from '@angular/compiler';
import * as ts from 'typescript';
import {TypeScriptReflectionHost} from '..';
import {AbsoluteReference, Reference} from '../../imports';
import {TypeScriptReflectionHost} from '../../reflection';
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
import {AbsoluteReference, EnumValue, Reference, ResolvedValue, staticallyResolve} from '../src/resolver';
import {PartialEvaluator} from '../src/interface';
import {EnumValue, ResolvedValue} from '../src/result';
function makeSimpleProgram(contents: string): ts.Program {
return makeProgram([{name: 'entry.ts', contents}]).program;
@ -32,7 +34,8 @@ function makeExpression(
function evaluate<T extends ResolvedValue>(code: string, expr: string): T {
const {expression, checker} = makeExpression(code, expr);
const host = new TypeScriptReflectionHost(checker);
return staticallyResolve(expression, host, checker) as T;
const evaluator = new PartialEvaluator(host, checker);
return evaluator.evaluate(expression) as T;
}
describe('ngtsc metadata', () => {
@ -55,8 +58,9 @@ describe('ngtsc metadata', () => {
]);
const decl = getDeclaration(program, 'entry.ts', 'X', ts.isVariableDeclaration);
const host = new TypeScriptReflectionHost(program.getTypeChecker());
const evaluator = new PartialEvaluator(host, program.getTypeChecker());
const value = staticallyResolve(decl.initializer !, host, program.getTypeChecker());
const value = evaluator.evaluate(decl.initializer !);
expect(value).toEqual('test');
});
@ -142,7 +146,8 @@ describe('ngtsc metadata', () => {
const host = new TypeScriptReflectionHost(checker);
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
const expr = result.initializer !;
const resolved = staticallyResolve(expr, host, checker);
const evaluator = new PartialEvaluator(host, checker);
const resolved = evaluator.evaluate(expr);
if (!(resolved instanceof Reference)) {
return fail('Expected expression to resolve to a reference');
}
@ -173,7 +178,8 @@ describe('ngtsc metadata', () => {
const host = new TypeScriptReflectionHost(checker);
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
const expr = result.initializer !;
const resolved = staticallyResolve(expr, host, checker);
const evaluator = new PartialEvaluator(host, checker);
const resolved = evaluator.evaluate(expr);
if (!(resolved instanceof AbsoluteReference)) {
return fail('Expected expression to resolve to an absolute reference');
}
@ -205,7 +211,8 @@ describe('ngtsc metadata', () => {
const host = new TypeScriptReflectionHost(checker);
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
const expr = result.initializer !;
expect(staticallyResolve(expr, host, checker)).toEqual('test');
const evaluator = new PartialEvaluator(host, checker);
expect(evaluator.evaluate(expr)).toEqual('test');
});
it('reads values from named exports', () => {
@ -223,7 +230,8 @@ describe('ngtsc metadata', () => {
const host = new TypeScriptReflectionHost(checker);
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
const expr = result.initializer !;
expect(staticallyResolve(expr, host, checker)).toEqual('test');
const evaluator = new PartialEvaluator(host, checker);
expect(evaluator.evaluate(expr)).toEqual('test');
});
it('chain of re-exports works', () => {
@ -241,7 +249,8 @@ describe('ngtsc metadata', () => {
const host = new TypeScriptReflectionHost(checker);
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
const expr = result.initializer !;
expect(staticallyResolve(expr, host, checker)).toEqual('test');
const evaluator = new PartialEvaluator(host, checker);
expect(evaluator.evaluate(expr)).toEqual('test');
});
it('map spread works', () => {
@ -297,7 +306,8 @@ describe('ngtsc metadata', () => {
const checker = program.getTypeChecker();
const host = new TypeScriptReflectionHost(checker);
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
const res = staticallyResolve(result.initializer !, host, checker);
const evaluator = new PartialEvaluator(host, checker);
const res = evaluator.evaluate(result.initializer !);
expect(res instanceof Reference).toBe(true);
});
});

View File

@ -7,7 +7,6 @@
*/
import {GeneratedFile} from '@angular/compiler';
import * as path from 'path';
import * as ts from 'typescript';
import * as api from '../transformers/api';
@ -16,7 +15,8 @@ import {nocollapseHack} from '../transformers/nocollapse_hack';
import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, NoopReferencesRegistry, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from './annotations';
import {BaseDefDecoratorHandler} from './annotations/src/base_def';
import {FlatIndexGenerator} from './entry_point';
import {TypeScriptReflectionHost} from './metadata';
import {PartialEvaluator} from './partial_evaluator';
import {TypeScriptReflectionHost} from './reflection';
import {FileResourceLoader, HostResourceLoader} from './resource_loader';
import {FactoryGenerator, FactoryInfo, GeneratedShimsHostWrapper, ShimGenerator, SummaryGenerator, generatedFactoryTransform} from './shims';
import {ivySwitchTransform} from './switch';
@ -251,20 +251,21 @@ export class NgtscProgram implements api.Program {
private makeCompilation(): IvyCompilation {
const checker = this.tsProgram.getTypeChecker();
const evaluator = new PartialEvaluator(this.reflector, checker);
const scopeRegistry = new SelectorScopeRegistry(checker, this.reflector);
const referencesRegistry = new NoopReferencesRegistry();
// Set up the IvyCompilation, which manages state for the Ivy transformer.
const handlers = [
new BaseDefDecoratorHandler(checker, this.reflector),
new BaseDefDecoratorHandler(this.reflector, evaluator),
new ComponentDecoratorHandler(
checker, this.reflector, scopeRegistry, this.isCore, this.resourceLoader, this.rootDirs,
this.reflector, evaluator, scopeRegistry, this.isCore, this.resourceLoader, this.rootDirs,
this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false),
new DirectiveDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore),
new DirectiveDecoratorHandler(this.reflector, evaluator, scopeRegistry, this.isCore),
new InjectableDecoratorHandler(this.reflector, this.isCore),
new NgModuleDecoratorHandler(
checker, this.reflector, scopeRegistry, referencesRegistry, this.isCore),
new PipeDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore),
this.reflector, evaluator, scopeRegistry, referencesRegistry, this.isCore),
new PipeDecoratorHandler(this.reflector, evaluator, scopeRegistry, this.isCore),
];
return new IvyCompilation(

View File

@ -3,11 +3,11 @@ package(default_visibility = ["//visibility:public"])
load("//tools:defaults.bzl", "ts_library")
ts_library(
name = "host",
name = "reflection",
srcs = glob([
"index.ts",
"src/**/*.ts",
]),
module_name = "@angular/compiler-cli/src/ngtsc/host",
module_name = "@angular/compiler-cli/src/ngtsc/reflection",
deps = ["@ngdeps//typescript"],
)

View File

@ -0,0 +1,10 @@
/**
* @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
*/
export * from './src/host';
export {TypeScriptReflectionHost, filterToMembersWithDecorator, reflectIdentifierOfDeclaration, reflectNameOfDeclaration, reflectObjectLiteral, reflectTypeEntityToDeclaration, typeNodeToValueExpr} from './src/typescript';

View File

@ -8,7 +8,7 @@
import * as ts from 'typescript';
import {ClassMember, ClassMemberKind, CtorParameter, Declaration, Decorator, FunctionDefinition, Import, ReflectionHost} from '../../host';
import {ClassMember, ClassMemberKind, CtorParameter, Declaration, Decorator, FunctionDefinition, Import, ReflectionHost} from './host';
/**
* reflector.ts implements static reflection of declarations using the TypeScript `ts.TypeChecker`.

View File

@ -10,9 +10,7 @@ ts_library(
]),
deps = [
"//packages:types",
"//packages/compiler",
"//packages/compiler-cli/src/ngtsc/host",
"//packages/compiler-cli/src/ngtsc/metadata",
"//packages/compiler-cli/src/ngtsc/reflection",
"//packages/compiler-cli/src/ngtsc/testing",
"@ngdeps//typescript",
],

View File

@ -8,9 +8,9 @@
import * as ts from 'typescript';
import {CtorParameter} from '../../host';
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
import {TypeScriptReflectionHost} from '../src/reflector';
import {CtorParameter} from '../src/host';
import {TypeScriptReflectionHost} from '../src/typescript';
describe('reflector', () => {
describe('ctor params', () => {

View File

@ -11,8 +11,6 @@ ts_library(
module_name = "@angular/compiler-cli/src/ngtsc/shims",
deps = [
"//packages/compiler",
"//packages/compiler-cli/src/ngtsc/host",
"//packages/compiler-cli/src/ngtsc/metadata",
"//packages/compiler-cli/src/ngtsc/util",
"@ngdeps//@types/node",
"@ngdeps//typescript",

View File

@ -6,7 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import * as path from 'path';
import * as ts from 'typescript';
export interface ShimGenerator {

View File

@ -11,9 +11,6 @@ ts_library(
module_name = "@angular/compiler-cli/src/ngtsc/switch",
deps = [
"//packages/compiler",
"//packages/compiler-cli/src/ngtsc/host",
"//packages/compiler-cli/src/ngtsc/metadata",
"//packages/compiler-cli/src/ngtsc/util",
"@ngdeps//typescript",
],
)

View File

@ -12,8 +12,7 @@ ts_library(
deps = [
"//packages/compiler",
"//packages/compiler-cli/src/ngtsc/diagnostics",
"//packages/compiler-cli/src/ngtsc/host",
"//packages/compiler-cli/src/ngtsc/metadata",
"//packages/compiler-cli/src/ngtsc/reflection",
"//packages/compiler-cli/src/ngtsc/translator",
"//packages/compiler-cli/src/ngtsc/typecheck",
"//packages/compiler-cli/src/ngtsc/util",

View File

@ -9,7 +9,7 @@
import {ConstantPool, Expression, Statement, Type} from '@angular/compiler';
import * as ts from 'typescript';
import {Decorator} from '../../host';
import {Decorator} from '../../reflection';
import {TypeCheckContext} from '../../typecheck';

View File

@ -10,8 +10,7 @@ import {ConstantPool} from '@angular/compiler';
import * as ts from 'typescript';
import {FatalDiagnosticError} from '../../diagnostics';
import {Decorator, ReflectionHost} from '../../host';
import {reflectNameOfDeclaration} from '../../metadata/src/reflector';
import {Decorator, ReflectionHost, reflectNameOfDeclaration} from '../../reflection';
import {TypeCheckContext} from '../../typecheck';
import {AnalysisOutput, CompileResult, DecoratorHandler} from './api';

View File

@ -9,9 +9,8 @@
import {ConstantPool} from '@angular/compiler';
import * as ts from 'typescript';
import {Decorator, ReflectionHost} from '../../host';
import {Decorator, ReflectionHost} from '../../reflection';
import {ImportManager, translateExpression, translateStatement} from '../../translator';
import {relativePathBetween} from '../../util/src/path';
import {VisitListEntryResult, Visitor, visit} from '../../util/src/visitor';
import {CompileResult} from './api';

View File

@ -9,7 +9,7 @@ ts_library(
deps = [
"//packages:types",
"//packages/compiler",
"//packages/compiler-cli/src/ngtsc/metadata",
"//packages/compiler-cli/src/ngtsc/imports",
"//packages/compiler-cli/src/ngtsc/translator",
"//packages/compiler-cli/src/ngtsc/util",
"@ngdeps//typescript",

View File

@ -9,7 +9,7 @@
import {BoundTarget, DirectiveMeta} from '@angular/compiler';
import * as ts from 'typescript';
import {Reference} from '../../metadata';
import {Reference} from '../../imports';
/**
* Extension of `DirectiveMeta` that includes additional information required to type-check the

View File

@ -9,7 +9,7 @@
import {AST, BindingType, BoundTarget, ImplicitReceiver, PropertyRead, TmplAstBoundText, TmplAstElement, TmplAstNode, TmplAstTemplate, TmplAstVariable} from '@angular/compiler';
import * as ts from 'typescript';
import {Reference} from '../../metadata';
import {Reference} from '../../imports';
import {ImportManager, translateExpression} from '../../translator';
import {TypeCheckBlockMetadata, TypeCheckableDirectiveMeta} from './api';

View File

@ -10,8 +10,6 @@ ts_library(
]),
deps = [
"//packages:types",
"//packages/compiler",
"//packages/compiler-cli/src/ngtsc/host",
"//packages/compiler-cli/src/ngtsc/testing",
"//packages/compiler-cli/src/ngtsc/typecheck",
"@ngdeps//typescript",