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:
parent
37b716b298
commit
2a6108af97
|
@ -27,7 +27,8 @@ ts_library(
|
||||||
"//packages/compiler-cli/src/ngtsc/annotations",
|
"//packages/compiler-cli/src/ngtsc/annotations",
|
||||||
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
||||||
"//packages/compiler-cli/src/ngtsc/entry_point",
|
"//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/shims",
|
||||||
"//packages/compiler-cli/src/ngtsc/switch",
|
"//packages/compiler-cli/src/ngtsc/switch",
|
||||||
"//packages/compiler-cli/src/ngtsc/transform",
|
"//packages/compiler-cli/src/ngtsc/transform",
|
||||||
|
|
|
@ -13,8 +13,9 @@ ts_library(
|
||||||
"//packages:types",
|
"//packages:types",
|
||||||
"//packages/compiler",
|
"//packages/compiler",
|
||||||
"//packages/compiler-cli/src/ngtsc/annotations",
|
"//packages/compiler-cli/src/ngtsc/annotations",
|
||||||
"//packages/compiler-cli/src/ngtsc/host",
|
"//packages/compiler-cli/src/ngtsc/imports",
|
||||||
"//packages/compiler-cli/src/ngtsc/metadata",
|
"//packages/compiler-cli/src/ngtsc/partial_evaluator",
|
||||||
|
"//packages/compiler-cli/src/ngtsc/reflection",
|
||||||
"//packages/compiler-cli/src/ngtsc/transform",
|
"//packages/compiler-cli/src/ngtsc/transform",
|
||||||
"//packages/compiler-cli/src/ngtsc/translator",
|
"//packages/compiler-cli/src/ngtsc/translator",
|
||||||
"@ngdeps//@types/convert-source-map",
|
"@ngdeps//@types/convert-source-map",
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {ConstantPool} from '@angular/compiler';
|
import {ConstantPool} from '@angular/compiler';
|
||||||
|
import {PartialEvaluator} from '@angular/compiler-cli/src/ngtsc/partial_evaluator';
|
||||||
import * as path from 'canonical-path';
|
import * as path from 'canonical-path';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
@ -59,16 +60,17 @@ export class FileResourceLoader implements ResourceLoader {
|
||||||
export class DecorationAnalyzer {
|
export class DecorationAnalyzer {
|
||||||
resourceLoader = new FileResourceLoader();
|
resourceLoader = new FileResourceLoader();
|
||||||
scopeRegistry = new SelectorScopeRegistry(this.typeChecker, this.host);
|
scopeRegistry = new SelectorScopeRegistry(this.typeChecker, this.host);
|
||||||
|
evaluator = new PartialEvaluator(this.host, this.typeChecker);
|
||||||
handlers: DecoratorHandler<any, any>[] = [
|
handlers: DecoratorHandler<any, any>[] = [
|
||||||
new BaseDefDecoratorHandler(this.typeChecker, this.host),
|
new BaseDefDecoratorHandler(this.host, this.evaluator),
|
||||||
new ComponentDecoratorHandler(
|
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),
|
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 InjectableDecoratorHandler(this.host, this.isCore),
|
||||||
new NgModuleDecoratorHandler(
|
new NgModuleDecoratorHandler(
|
||||||
this.typeChecker, this.host, this.scopeRegistry, this.referencesRegistry, this.isCore),
|
this.host, this.evaluator, this.scopeRegistry, this.referencesRegistry, this.isCore),
|
||||||
new PipeDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore),
|
new PipeDecoratorHandler(this.host, this.evaluator, this.scopeRegistry, this.isCore),
|
||||||
];
|
];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ReferencesRegistry} from '../../../ngtsc/annotations';
|
import {ReferencesRegistry} from '../../../ngtsc/annotations';
|
||||||
import {Declaration} from '../../../ngtsc/host';
|
import {ResolvedReference} from '../../../ngtsc/imports';
|
||||||
import {ResolvedReference} from '../../../ngtsc/metadata';
|
import {Declaration} from '../../../ngtsc/reflection';
|
||||||
import {NgccReflectionHost} from '../host/ngcc_host';
|
import {NgccReflectionHost} from '../host/ngcc_host';
|
||||||
import {isDefined} from '../utils';
|
import {isDefined} from '../utils';
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {ReferencesRegistry} from '../../../ngtsc/annotations';
|
import {ReferencesRegistry} from '../../../ngtsc/annotations';
|
||||||
import {Declaration, ReflectionHost} from '../../../ngtsc/host';
|
import {Reference, ResolvedReference} from '../../../ngtsc/imports';
|
||||||
import {Reference, ResolvedReference} from '../../../ngtsc/metadata';
|
import {Declaration, ReflectionHost} from '../../../ngtsc/reflection';
|
||||||
import {hasNameIdentifier} from '../utils';
|
import {hasNameIdentifier} from '../utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ReferencesRegistry} from '../../../ngtsc/annotations';
|
import {ReferencesRegistry} from '../../../ngtsc/annotations';
|
||||||
import {Declaration} from '../../../ngtsc/host';
|
import {Declaration} from '../../../ngtsc/reflection';
|
||||||
import {NgccReflectionHost} from '../host/ngcc_host';
|
import {NgccReflectionHost} from '../host/ngcc_host';
|
||||||
import {hasNameIdentifier, isDefined} from '../utils';
|
import {hasNameIdentifier, isDefined} from '../utils';
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
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
|
* A simple container that holds the details of a decorated class that has been
|
||||||
|
|
|
@ -8,8 +8,7 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ClassMember, ClassMemberKind, CtorParameter, Decorator, Import} from '../../../ngtsc/host';
|
import {ClassMember, ClassMemberKind, CtorParameter, Decorator, Import, TypeScriptReflectionHost, reflectObjectLiteral} from '../../../ngtsc/reflection';
|
||||||
import {TypeScriptReflectionHost, reflectObjectLiteral} from '../../../ngtsc/metadata';
|
|
||||||
import {BundleProgram} from '../packages/bundle_program';
|
import {BundleProgram} from '../packages/bundle_program';
|
||||||
import {findAll, getNameText, isDefined} from '../utils';
|
import {findAll, getNameText, isDefined} from '../utils';
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,7 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ClassMember, ClassMemberKind, Decorator, FunctionDefinition, Parameter} from '../../../ngtsc/host';
|
import {ClassMember, ClassMemberKind, Decorator, FunctionDefinition, Parameter, reflectObjectLiteral} from '../../../ngtsc/reflection';
|
||||||
import {reflectObjectLiteral} from '../../../ngtsc/metadata';
|
|
||||||
import {getNameText} from '../utils';
|
import {getNameText} from '../utils';
|
||||||
|
|
||||||
import {Esm2015ReflectionHost, ParamInfo, getPropertyValueFromSymbol, isAssignmentStatement} from './esm2015_host';
|
import {Esm2015ReflectionHost, ParamInfo, getPropertyValueFromSymbol, isAssignmentStatement} from './esm2015_host';
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {ReflectionHost} from '../../../ngtsc/host';
|
import {ReflectionHost} from '../../../ngtsc/reflection';
|
||||||
import {DecoratedClass} from './decorated_class';
|
import {DecoratedClass} from './decorated_class';
|
||||||
|
|
||||||
export const PRE_R3_MARKER = '__PRE_R3__';
|
export const PRE_R3_MARKER = '__PRE_R3__';
|
||||||
|
|
|
@ -13,7 +13,6 @@ import {basename, dirname, relative, resolve} from 'canonical-path';
|
||||||
import {SourceMapConsumer, SourceMapGenerator, RawSourceMap} from 'source-map';
|
import {SourceMapConsumer, SourceMapGenerator, RawSourceMap} from 'source-map';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {Decorator} from '../../../ngtsc/host';
|
|
||||||
import {CompileResult} from '@angular/compiler-cli/src/ngtsc/transform';
|
import {CompileResult} from '@angular/compiler-cli/src/ngtsc/transform';
|
||||||
import {translateStatement, translateType, ImportManager} from '../../../ngtsc/translator';
|
import {translateStatement, translateType, ImportManager} from '../../../ngtsc/translator';
|
||||||
import {NgccImportManager} from './ngcc_import_manager';
|
import {NgccImportManager} from './ngcc_import_manager';
|
||||||
|
|
|
@ -10,8 +10,9 @@ ts_library(
|
||||||
]),
|
]),
|
||||||
deps = [
|
deps = [
|
||||||
"//packages/compiler-cli/src/ngcc",
|
"//packages/compiler-cli/src/ngcc",
|
||||||
"//packages/compiler-cli/src/ngtsc/host",
|
"//packages/compiler-cli/src/ngtsc/imports",
|
||||||
"//packages/compiler-cli/src/ngtsc/metadata",
|
"//packages/compiler-cli/src/ngtsc/partial_evaluator",
|
||||||
|
"//packages/compiler-cli/src/ngtsc/reflection",
|
||||||
"//packages/compiler-cli/src/ngtsc/testing",
|
"//packages/compiler-cli/src/ngtsc/testing",
|
||||||
"//packages/compiler-cli/src/ngtsc/transform",
|
"//packages/compiler-cli/src/ngtsc/transform",
|
||||||
"@ngdeps//@types/convert-source-map",
|
"@ngdeps//@types/convert-source-map",
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {Decorator} from '../../../ngtsc/host';
|
import {Decorator} from '../../../ngtsc/reflection';
|
||||||
import {DecoratorHandler} from '../../../ngtsc/transform';
|
import {DecoratorHandler} from '../../../ngtsc/transform';
|
||||||
import {DecorationAnalyses, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
|
import {DecorationAnalyses, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
|
||||||
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
|
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* 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 * as ts from 'typescript';
|
||||||
|
|
||||||
|
import {ResolvedReference} from '../../../ngtsc/imports';
|
||||||
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
|
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
|
||||||
import {PrivateDeclarationsAnalyzer} from '../../src/analysis/private_declarations_analyzer';
|
import {PrivateDeclarationsAnalyzer} from '../../src/analysis/private_declarations_analyzer';
|
||||||
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
|
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
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 {getDeclaration, makeProgram} from '../../../ngtsc/testing/in_memory_typescript';
|
||||||
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
|
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
|
||||||
|
|
||||||
|
@ -37,10 +39,10 @@ describe('NgccReferencesRegistry', () => {
|
||||||
const testArrayExpression = testArrayDeclaration.initializer !;
|
const testArrayExpression = testArrayDeclaration.initializer !;
|
||||||
|
|
||||||
const host = new TypeScriptReflectionHost(checker);
|
const host = new TypeScriptReflectionHost(checker);
|
||||||
|
const evaluator = new PartialEvaluator(host, checker);
|
||||||
const registry = new NgccReferencesRegistry(host);
|
const registry = new NgccReferencesRegistry(host);
|
||||||
|
|
||||||
const references =
|
const references = evaluator.evaluate(testArrayExpression) as Reference<ts.Declaration>[];
|
||||||
staticallyResolve(testArrayExpression, host, checker) as Reference<ts.Declaration>[];
|
|
||||||
registry.add(...references);
|
registry.add(...references);
|
||||||
|
|
||||||
const map = registry.getDeclarationMap();
|
const map = registry.getDeclarationMap();
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
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 {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
|
||||||
import {convertToDirectTsLibImport, getDeclaration, makeTestProgram} from '../helpers/utils';
|
import {convertToDirectTsLibImport, getDeclaration, makeTestProgram} from '../helpers/utils';
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
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 {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
|
||||||
import {getDeclaration, makeTestBundleProgram, makeTestProgram} from '../helpers/utils';
|
import {getDeclaration, makeTestBundleProgram, makeTestProgram} from '../helpers/utils';
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
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 {Esm5ReflectionHost} from '../../src/host/esm5_host';
|
||||||
import {convertToDirectTsLibImport, getDeclaration, makeTestProgram} from '../helpers/utils';
|
import {convertToDirectTsLibImport, getDeclaration, makeTestProgram} from '../helpers/utils';
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
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 {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
|
||||||
import {Esm5ReflectionHost} from '../../src/host/esm5_host';
|
import {Esm5ReflectionHost} from '../../src/host/esm5_host';
|
||||||
import {getDeclaration, makeTestProgram} from '../helpers/utils';
|
import {getDeclaration, makeTestProgram} from '../helpers/utils';
|
||||||
|
|
|
@ -12,8 +12,9 @@ ts_library(
|
||||||
deps = [
|
deps = [
|
||||||
"//packages/compiler",
|
"//packages/compiler",
|
||||||
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
||||||
"//packages/compiler-cli/src/ngtsc/host",
|
"//packages/compiler-cli/src/ngtsc/imports",
|
||||||
"//packages/compiler-cli/src/ngtsc/metadata",
|
"//packages/compiler-cli/src/ngtsc/partial_evaluator",
|
||||||
|
"//packages/compiler-cli/src/ngtsc/reflection",
|
||||||
"//packages/compiler-cli/src/ngtsc/transform",
|
"//packages/compiler-cli/src/ngtsc/transform",
|
||||||
"//packages/compiler-cli/src/ngtsc/typecheck",
|
"//packages/compiler-cli/src/ngtsc/typecheck",
|
||||||
"@ngdeps//@types/node",
|
"@ngdeps//@types/node",
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
import {R3BaseRefMetaData, compileBaseDefFromMetadata} from '@angular/compiler';
|
import {R3BaseRefMetaData, compileBaseDefFromMetadata} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ClassMember, Decorator, ReflectionHost} from '../../host';
|
import {PartialEvaluator} from '../../partial_evaluator';
|
||||||
import {staticallyResolve} from '../../metadata';
|
import {ClassMember, Decorator, ReflectionHost} from '../../reflection';
|
||||||
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
|
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
|
||||||
import {isAngularCore} from './util';
|
import {isAngularCore} from './util';
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ function containsNgTopLevelDecorator(decorators: Decorator[] | null): boolean {
|
||||||
|
|
||||||
export class BaseDefDecoratorHandler implements
|
export class BaseDefDecoratorHandler implements
|
||||||
DecoratorHandler<R3BaseRefMetaData, R3BaseRefDecoratorDetection> {
|
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
|
detect(node: ts.ClassDeclaration, decorators: Decorator[]|null): R3BaseRefDecoratorDetection
|
||||||
|undefined {
|
|undefined {
|
||||||
|
@ -69,7 +69,7 @@ export class BaseDefDecoratorHandler implements
|
||||||
const args = decorator.args;
|
const args = decorator.args;
|
||||||
let value: string|[string, string];
|
let value: string|[string, string];
|
||||||
if (args && args.length > 0) {
|
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') {
|
if (typeof resolvedValue !== 'string') {
|
||||||
throw new TypeError('Input alias does not resolve to a string value');
|
throw new TypeError('Input alias does not resolve to a string value');
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ export class BaseDefDecoratorHandler implements
|
||||||
const args = decorator.args;
|
const args = decorator.args;
|
||||||
let value: string;
|
let value: string;
|
||||||
if (args && args.length > 0) {
|
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') {
|
if (typeof resolvedValue !== 'string') {
|
||||||
throw new TypeError('Output alias does not resolve to a string value');
|
throw new TypeError('Output alias does not resolve to a string value');
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,9 @@ import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||||
import {Decorator, ReflectionHost} from '../../host';
|
import {ResolvedReference} from '../../imports';
|
||||||
import {AbsoluteReference, Reference, ResolvedReference, filterToMembersWithDecorator, reflectObjectLiteral, staticallyResolve} from '../../metadata';
|
import {PartialEvaluator} from '../../partial_evaluator';
|
||||||
|
import {Decorator, ReflectionHost, filterToMembersWithDecorator, reflectObjectLiteral} from '../../reflection';
|
||||||
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
|
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
|
||||||
import {TypeCheckContext, TypeCheckableDirectiveMeta} from '../../typecheck';
|
import {TypeCheckContext, TypeCheckableDirectiveMeta} from '../../typecheck';
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ export interface ComponentHandlerData {
|
||||||
export class ComponentDecoratorHandler implements
|
export class ComponentDecoratorHandler implements
|
||||||
DecoratorHandler<ComponentHandlerData, Decorator> {
|
DecoratorHandler<ComponentHandlerData, Decorator> {
|
||||||
constructor(
|
constructor(
|
||||||
private checker: ts.TypeChecker, private reflector: ReflectionHost,
|
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
|
||||||
private scopeRegistry: SelectorScopeRegistry, private isCore: boolean,
|
private scopeRegistry: SelectorScopeRegistry, private isCore: boolean,
|
||||||
private resourceLoader: ResourceLoader, private rootDirs: string[],
|
private resourceLoader: ResourceLoader, private rootDirs: string[],
|
||||||
private defaultPreserveWhitespaces: boolean, private i18nUseExternalIds: boolean) {}
|
private defaultPreserveWhitespaces: boolean, private i18nUseExternalIds: boolean) {}
|
||||||
|
@ -62,7 +63,7 @@ export class ComponentDecoratorHandler implements
|
||||||
|
|
||||||
if (this.resourceLoader.preload !== undefined && component.has('templateUrl')) {
|
if (this.resourceLoader.preload !== undefined && component.has('templateUrl')) {
|
||||||
const templateUrlExpr = component.get('templateUrl') !;
|
const templateUrlExpr = component.get('templateUrl') !;
|
||||||
const templateUrl = staticallyResolve(templateUrlExpr, this.reflector, this.checker);
|
const templateUrl = this.evaluator.evaluate(templateUrlExpr);
|
||||||
if (typeof templateUrl !== 'string') {
|
if (typeof templateUrl !== 'string') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, templateUrlExpr, 'templateUrl must be a string');
|
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
|
// @Component inherits @Directive, so begin by extracting the @Directive metadata and building
|
||||||
// on it.
|
// on it.
|
||||||
const directiveResult = extractDirectiveMetadata(
|
const directiveResult = extractDirectiveMetadata(
|
||||||
node, decorator, this.checker, this.reflector, this.isCore,
|
node, decorator, this.reflector, this.evaluator, this.isCore,
|
||||||
this.elementSchemaRegistry.getDefaultComponentElementName());
|
this.elementSchemaRegistry.getDefaultComponentElementName());
|
||||||
if (directiveResult === undefined) {
|
if (directiveResult === undefined) {
|
||||||
// `extractDirectiveMetadata` returns undefined when the @Directive has `jit: true`. In this
|
// `extractDirectiveMetadata` returns undefined when the @Directive has `jit: true`. In this
|
||||||
|
@ -112,7 +113,7 @@ export class ComponentDecoratorHandler implements
|
||||||
let templateStr: string|null = null;
|
let templateStr: string|null = null;
|
||||||
if (component.has('templateUrl')) {
|
if (component.has('templateUrl')) {
|
||||||
const templateUrlExpr = component.get('templateUrl') !;
|
const templateUrlExpr = component.get('templateUrl') !;
|
||||||
const templateUrl = staticallyResolve(templateUrlExpr, this.reflector, this.checker);
|
const templateUrl = this.evaluator.evaluate(templateUrlExpr);
|
||||||
if (typeof templateUrl !== 'string') {
|
if (typeof templateUrl !== 'string') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, templateUrlExpr, 'templateUrl must be a string');
|
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);
|
templateStr = this.resourceLoader.load(templateUrl, containingFile);
|
||||||
} else if (component.has('template')) {
|
} else if (component.has('template')) {
|
||||||
const templateExpr = component.get('template') !;
|
const templateExpr = component.get('template') !;
|
||||||
const resolvedTemplate = staticallyResolve(templateExpr, this.reflector, this.checker);
|
const resolvedTemplate = this.evaluator.evaluate(templateExpr);
|
||||||
if (typeof resolvedTemplate !== 'string') {
|
if (typeof resolvedTemplate !== 'string') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, templateExpr, 'template must be a string');
|
ErrorCode.VALUE_HAS_WRONG_TYPE, templateExpr, 'template must be a string');
|
||||||
|
@ -134,7 +135,7 @@ export class ComponentDecoratorHandler implements
|
||||||
let preserveWhitespaces: boolean = this.defaultPreserveWhitespaces;
|
let preserveWhitespaces: boolean = this.defaultPreserveWhitespaces;
|
||||||
if (component.has('preserveWhitespaces')) {
|
if (component.has('preserveWhitespaces')) {
|
||||||
const expr = component.get('preserveWhitespaces') !;
|
const expr = component.get('preserveWhitespaces') !;
|
||||||
const value = staticallyResolve(expr, this.reflector, this.checker);
|
const value = this.evaluator.evaluate(expr);
|
||||||
if (typeof value !== 'boolean') {
|
if (typeof value !== 'boolean') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, expr, 'preserveWhitespaces must be a boolean');
|
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;
|
let interpolation: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG;
|
||||||
if (component.has('interpolation')) {
|
if (component.has('interpolation')) {
|
||||||
const expr = component.get('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 ||
|
if (!Array.isArray(value) || value.length !== 2 ||
|
||||||
!value.every(element => typeof element === 'string')) {
|
!value.every(element => typeof element === 'string')) {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
|
@ -200,21 +201,21 @@ export class ComponentDecoratorHandler implements
|
||||||
const coreModule = this.isCore ? undefined : '@angular/core';
|
const coreModule = this.isCore ? undefined : '@angular/core';
|
||||||
const viewChildFromFields = queriesFromFields(
|
const viewChildFromFields = queriesFromFields(
|
||||||
filterToMembersWithDecorator(decoratedElements, 'ViewChild', coreModule), this.reflector,
|
filterToMembersWithDecorator(decoratedElements, 'ViewChild', coreModule), this.reflector,
|
||||||
this.checker);
|
this.evaluator);
|
||||||
const viewChildrenFromFields = queriesFromFields(
|
const viewChildrenFromFields = queriesFromFields(
|
||||||
filterToMembersWithDecorator(decoratedElements, 'ViewChildren', coreModule), this.reflector,
|
filterToMembersWithDecorator(decoratedElements, 'ViewChildren', coreModule), this.reflector,
|
||||||
this.checker);
|
this.evaluator);
|
||||||
const viewQueries = [...viewChildFromFields, ...viewChildrenFromFields];
|
const viewQueries = [...viewChildFromFields, ...viewChildrenFromFields];
|
||||||
|
|
||||||
if (component.has('queries')) {
|
if (component.has('queries')) {
|
||||||
const queriesFromDecorator = extractQueriesFromDecorator(
|
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);
|
viewQueries.push(...queriesFromDecorator.view);
|
||||||
}
|
}
|
||||||
|
|
||||||
let styles: string[]|null = null;
|
let styles: string[]|null = null;
|
||||||
if (component.has('styles')) {
|
if (component.has('styles')) {
|
||||||
styles = parseFieldArrayValue(component, 'styles', this.reflector, this.checker);
|
styles = parseFieldArrayValue(component, 'styles', this.evaluator);
|
||||||
}
|
}
|
||||||
|
|
||||||
let styleUrls = this._extractStyleUrls(component);
|
let styleUrls = this._extractStyleUrls(component);
|
||||||
|
@ -227,8 +228,7 @@ export class ComponentDecoratorHandler implements
|
||||||
|
|
||||||
let encapsulation: number = 0;
|
let encapsulation: number = 0;
|
||||||
if (component.has('encapsulation')) {
|
if (component.has('encapsulation')) {
|
||||||
encapsulation = parseInt(staticallyResolve(
|
encapsulation = parseInt(this.evaluator.evaluate(component.get('encapsulation') !) as string);
|
||||||
component.get('encapsulation') !, this.reflector, this.checker) as string);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let animations: Expression|null = null;
|
let animations: Expression|null = null;
|
||||||
|
@ -333,7 +333,7 @@ export class ComponentDecoratorHandler implements
|
||||||
}
|
}
|
||||||
|
|
||||||
const styleUrlsExpr = component.get('styleUrls') !;
|
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')) {
|
if (!Array.isArray(styleUrls) || !styleUrls.every(url => typeof url === 'string')) {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, styleUrlsExpr, 'styleUrls must be an array of strings');
|
ErrorCode.VALUE_HAS_WRONG_TYPE, styleUrlsExpr, 'styleUrls must be an array of strings');
|
||||||
|
|
|
@ -10,8 +10,9 @@ import {ConstantPool, Expression, R3DirectiveMetadata, R3QueryMetadata, Statemen
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||||
import {ClassMember, ClassMemberKind, Decorator, Import, ReflectionHost} from '../../host';
|
import {Reference, ResolvedReference} from '../../imports';
|
||||||
import {Reference, ResolvedReference, filterToMembersWithDecorator, reflectObjectLiteral, staticallyResolve} from '../../metadata';
|
import {PartialEvaluator} from '../../partial_evaluator';
|
||||||
|
import {ClassMember, ClassMemberKind, Decorator, ReflectionHost, filterToMembersWithDecorator, reflectObjectLiteral} from '../../reflection';
|
||||||
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
|
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
|
||||||
|
|
||||||
import {generateSetClassMetadataCall} from './metadata';
|
import {generateSetClassMetadataCall} from './metadata';
|
||||||
|
@ -27,7 +28,7 @@ export interface DirectiveHandlerData {
|
||||||
export class DirectiveDecoratorHandler implements
|
export class DirectiveDecoratorHandler implements
|
||||||
DecoratorHandler<DirectiveHandlerData, Decorator> {
|
DecoratorHandler<DirectiveHandlerData, Decorator> {
|
||||||
constructor(
|
constructor(
|
||||||
private checker: ts.TypeChecker, private reflector: ReflectionHost,
|
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
|
||||||
private scopeRegistry: SelectorScopeRegistry, private isCore: boolean) {}
|
private scopeRegistry: SelectorScopeRegistry, private isCore: boolean) {}
|
||||||
|
|
||||||
detect(node: ts.Declaration, decorators: Decorator[]|null): Decorator|undefined {
|
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> {
|
analyze(node: ts.ClassDeclaration, decorator: Decorator): AnalysisOutput<DirectiveHandlerData> {
|
||||||
const directiveResult =
|
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;
|
const analysis = directiveResult && directiveResult.metadata;
|
||||||
|
|
||||||
// If the directive has a selector, it should be registered with the `SelectorScopeRegistry` so
|
// 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`.
|
* Helper function to extract metadata from a `Directive` or `Component`.
|
||||||
*/
|
*/
|
||||||
export function extractDirectiveMetadata(
|
export function extractDirectiveMetadata(
|
||||||
clazz: ts.ClassDeclaration, decorator: Decorator, checker: ts.TypeChecker,
|
clazz: ts.ClassDeclaration, decorator: Decorator, reflector: ReflectionHost,
|
||||||
reflector: ReflectionHost, isCore: boolean, defaultSelector: string | null = null): {
|
evaluator: PartialEvaluator, isCore: boolean, defaultSelector: string | null = null): {
|
||||||
decorator: Map<string, ts.Expression>,
|
decorator: Map<string, ts.Expression>,
|
||||||
metadata: R3DirectiveMetadata,
|
metadata: R3DirectiveMetadata,
|
||||||
decoratedElements: ClassMember[],
|
decoratedElements: ClassMember[],
|
||||||
|
@ -127,29 +128,29 @@ export function extractDirectiveMetadata(
|
||||||
// Construct the map of inputs both from the @Directive/@Component
|
// Construct the map of inputs both from the @Directive/@Component
|
||||||
// decorator, and the decorated
|
// decorator, and the decorated
|
||||||
// fields.
|
// fields.
|
||||||
const inputsFromMeta = parseFieldToPropertyMapping(directive, 'inputs', reflector, checker);
|
const inputsFromMeta = parseFieldToPropertyMapping(directive, 'inputs', evaluator);
|
||||||
const inputsFromFields = parseDecoratedFields(
|
const inputsFromFields = parseDecoratedFields(
|
||||||
filterToMembersWithDecorator(decoratedElements, 'Input', coreModule), reflector, checker,
|
filterToMembersWithDecorator(decoratedElements, 'Input', coreModule), evaluator,
|
||||||
resolveInput);
|
resolveInput);
|
||||||
|
|
||||||
// And outputs.
|
// And outputs.
|
||||||
const outputsFromMeta = parseFieldToPropertyMapping(directive, 'outputs', reflector, checker);
|
const outputsFromMeta = parseFieldToPropertyMapping(directive, 'outputs', evaluator);
|
||||||
const outputsFromFields = parseDecoratedFields(
|
const outputsFromFields = parseDecoratedFields(
|
||||||
filterToMembersWithDecorator(decoratedElements, 'Output', coreModule), reflector, checker,
|
filterToMembersWithDecorator(decoratedElements, 'Output', coreModule), evaluator,
|
||||||
resolveOutput) as{[field: string]: string};
|
resolveOutput) as{[field: string]: string};
|
||||||
// Construct the list of queries.
|
// Construct the list of queries.
|
||||||
const contentChildFromFields = queriesFromFields(
|
const contentChildFromFields = queriesFromFields(
|
||||||
filterToMembersWithDecorator(decoratedElements, 'ContentChild', coreModule), reflector,
|
filterToMembersWithDecorator(decoratedElements, 'ContentChild', coreModule), reflector,
|
||||||
checker);
|
evaluator);
|
||||||
const contentChildrenFromFields = queriesFromFields(
|
const contentChildrenFromFields = queriesFromFields(
|
||||||
filterToMembersWithDecorator(decoratedElements, 'ContentChildren', coreModule), reflector,
|
filterToMembersWithDecorator(decoratedElements, 'ContentChildren', coreModule), reflector,
|
||||||
checker);
|
evaluator);
|
||||||
|
|
||||||
const queries = [...contentChildFromFields, ...contentChildrenFromFields];
|
const queries = [...contentChildFromFields, ...contentChildrenFromFields];
|
||||||
|
|
||||||
if (directive.has('queries')) {
|
if (directive.has('queries')) {
|
||||||
const queriesFromDecorator =
|
const queriesFromDecorator =
|
||||||
extractQueriesFromDecorator(directive.get('queries') !, reflector, checker, isCore);
|
extractQueriesFromDecorator(directive.get('queries') !, reflector, evaluator, isCore);
|
||||||
queries.push(...queriesFromDecorator.content);
|
queries.push(...queriesFromDecorator.content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +158,7 @@ export function extractDirectiveMetadata(
|
||||||
let selector = defaultSelector;
|
let selector = defaultSelector;
|
||||||
if (directive.has('selector')) {
|
if (directive.has('selector')) {
|
||||||
const expr = directive.get('selector') !;
|
const expr = directive.get('selector') !;
|
||||||
const resolved = staticallyResolve(expr, reflector, checker);
|
const resolved = evaluator.evaluate(expr);
|
||||||
if (typeof resolved !== 'string') {
|
if (typeof resolved !== 'string') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `selector must be a string`);
|
ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `selector must be a string`);
|
||||||
|
@ -165,7 +166,7 @@ export function extractDirectiveMetadata(
|
||||||
selector = resolved;
|
selector = resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
const host = extractHostBindings(directive, decoratedElements, reflector, checker, coreModule);
|
const host = extractHostBindings(directive, decoratedElements, evaluator, coreModule);
|
||||||
|
|
||||||
const providers: Expression|null =
|
const providers: Expression|null =
|
||||||
directive.has('providers') ? new WrappedNodeExpr(directive.get('providers') !) : null;
|
directive.has('providers') ? new WrappedNodeExpr(directive.get('providers') !) : null;
|
||||||
|
@ -179,7 +180,7 @@ export function extractDirectiveMetadata(
|
||||||
let exportAs: string|null = null;
|
let exportAs: string|null = null;
|
||||||
if (directive.has('exportAs')) {
|
if (directive.has('exportAs')) {
|
||||||
const expr = directive.get('exportAs') !;
|
const expr = directive.get('exportAs') !;
|
||||||
const resolved = staticallyResolve(expr, reflector, checker);
|
const resolved = evaluator.evaluate(expr);
|
||||||
if (typeof resolved !== 'string') {
|
if (typeof resolved !== 'string') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `exportAs must be a string`);
|
ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `exportAs must be a string`);
|
||||||
|
@ -207,14 +208,14 @@ export function extractDirectiveMetadata(
|
||||||
|
|
||||||
export function extractQueryMetadata(
|
export function extractQueryMetadata(
|
||||||
exprNode: ts.Node, name: string, args: ReadonlyArray<ts.Expression>, propertyName: string,
|
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) {
|
if (args.length === 0) {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.DECORATOR_ARITY_WRONG, exprNode, `@${name} must have arguments`);
|
ErrorCode.DECORATOR_ARITY_WRONG, exprNode, `@${name} must have arguments`);
|
||||||
}
|
}
|
||||||
const first = name === 'ViewChild' || name === 'ContentChild';
|
const first = name === 'ViewChild' || name === 'ContentChild';
|
||||||
const node = unwrapForwardRef(args[0], reflector);
|
const node = unwrapForwardRef(args[0], reflector);
|
||||||
const arg = staticallyResolve(node, reflector, checker);
|
const arg = evaluator.evaluate(node);
|
||||||
|
|
||||||
// Extract the predicate
|
// Extract the predicate
|
||||||
let predicate: Expression|string[]|null = null;
|
let predicate: Expression|string[]|null = null;
|
||||||
|
@ -244,7 +245,7 @@ export function extractQueryMetadata(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.has('descendants')) {
|
if (options.has('descendants')) {
|
||||||
const descendantsValue = staticallyResolve(options.get('descendants') !, reflector, checker);
|
const descendantsValue = evaluator.evaluate(options.get('descendants') !);
|
||||||
if (typeof descendantsValue !== 'boolean') {
|
if (typeof descendantsValue !== 'boolean') {
|
||||||
throw new Error(`@${name} options.descendants must be a boolean`);
|
throw new Error(`@${name} options.descendants must be a boolean`);
|
||||||
}
|
}
|
||||||
|
@ -261,7 +262,7 @@ export function extractQueryMetadata(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extractQueriesFromDecorator(
|
export function extractQueriesFromDecorator(
|
||||||
queryData: ts.Expression, reflector: ReflectionHost, checker: ts.TypeChecker,
|
queryData: ts.Expression, reflector: ReflectionHost, evaluator: PartialEvaluator,
|
||||||
isCore: boolean): {
|
isCore: boolean): {
|
||||||
content: R3QueryMetadata[],
|
content: R3QueryMetadata[],
|
||||||
view: R3QueryMetadata[],
|
view: R3QueryMetadata[],
|
||||||
|
@ -283,7 +284,7 @@ export function extractQueriesFromDecorator(
|
||||||
}
|
}
|
||||||
|
|
||||||
const query = extractQueryMetadata(
|
const query = extractQueryMetadata(
|
||||||
queryExpr, type.name, queryExpr.arguments || [], propertyName, reflector, checker);
|
queryExpr, type.name, queryExpr.arguments || [], propertyName, reflector, evaluator);
|
||||||
if (type.name.startsWith('Content')) {
|
if (type.name.startsWith('Content')) {
|
||||||
content.push(query);
|
content.push(query);
|
||||||
} else {
|
} else {
|
||||||
|
@ -307,14 +308,14 @@ function isStringArrayOrDie(value: any, name: string): value is string[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseFieldArrayValue(
|
export function parseFieldArrayValue(
|
||||||
directive: Map<string, ts.Expression>, field: string, reflector: ReflectionHost,
|
directive: Map<string, ts.Expression>, field: string, evaluator: PartialEvaluator): null|
|
||||||
checker: ts.TypeChecker): null|string[] {
|
string[] {
|
||||||
if (!directive.has(field)) {
|
if (!directive.has(field)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve the field of interest from the directive metadata to a string[].
|
// 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)) {
|
if (!isStringArrayOrDie(value, field)) {
|
||||||
throw new Error(`Failed to resolve @Directive.${field}`);
|
throw new Error(`Failed to resolve @Directive.${field}`);
|
||||||
}
|
}
|
||||||
|
@ -327,9 +328,9 @@ export function parseFieldArrayValue(
|
||||||
* correctly shaped metadata object.
|
* correctly shaped metadata object.
|
||||||
*/
|
*/
|
||||||
function parseFieldToPropertyMapping(
|
function parseFieldToPropertyMapping(
|
||||||
directive: Map<string, ts.Expression>, field: string, reflector: ReflectionHost,
|
directive: Map<string, ts.Expression>, field: string,
|
||||||
checker: ts.TypeChecker): {[field: string]: string} {
|
evaluator: PartialEvaluator): {[field: string]: string} {
|
||||||
const metaValues = parseFieldArrayValue(directive, field, reflector, checker);
|
const metaValues = parseFieldArrayValue(directive, field, evaluator);
|
||||||
if (!metaValues) {
|
if (!metaValues) {
|
||||||
return EMPTY_OBJECT;
|
return EMPTY_OBJECT;
|
||||||
}
|
}
|
||||||
|
@ -350,8 +351,7 @@ function parseFieldToPropertyMapping(
|
||||||
* object.
|
* object.
|
||||||
*/
|
*/
|
||||||
function parseDecoratedFields(
|
function parseDecoratedFields(
|
||||||
fields: {member: ClassMember, decorators: Decorator[]}[], reflector: ReflectionHost,
|
fields: {member: ClassMember, decorators: Decorator[]}[], evaluator: PartialEvaluator,
|
||||||
checker: ts.TypeChecker,
|
|
||||||
mapValueResolver: (publicName: string, internalName: string) =>
|
mapValueResolver: (publicName: string, internalName: string) =>
|
||||||
string | [string, string]): {[field: string]: string | [string, string]} {
|
string | [string, string]): {[field: string]: string | [string, string]} {
|
||||||
return fields.reduce(
|
return fields.reduce(
|
||||||
|
@ -363,7 +363,7 @@ function parseDecoratedFields(
|
||||||
if (decorator.args == null || decorator.args.length === 0) {
|
if (decorator.args == null || decorator.args.length === 0) {
|
||||||
results[fieldName] = fieldName;
|
results[fieldName] = fieldName;
|
||||||
} else if (decorator.args.length === 1) {
|
} 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') {
|
if (typeof property !== 'string') {
|
||||||
throw new Error(`Decorator argument must resolve to a string`);
|
throw new Error(`Decorator argument must resolve to a string`);
|
||||||
}
|
}
|
||||||
|
@ -389,7 +389,7 @@ function resolveOutput(publicName: string, internalName: string) {
|
||||||
|
|
||||||
export function queriesFromFields(
|
export function queriesFromFields(
|
||||||
fields: {member: ClassMember, decorators: Decorator[]}[], reflector: ReflectionHost,
|
fields: {member: ClassMember, decorators: Decorator[]}[], reflector: ReflectionHost,
|
||||||
checker: ts.TypeChecker): R3QueryMetadata[] {
|
evaluator: PartialEvaluator): R3QueryMetadata[] {
|
||||||
return fields.map(({member, decorators}) => {
|
return fields.map(({member, decorators}) => {
|
||||||
if (decorators.length !== 1) {
|
if (decorators.length !== 1) {
|
||||||
throw new Error(`Cannot have multiple query decorators on the same class member`);
|
throw new Error(`Cannot have multiple query decorators on the same class member`);
|
||||||
|
@ -398,7 +398,7 @@ export function queriesFromFields(
|
||||||
}
|
}
|
||||||
const decorator = decorators[0];
|
const decorator = decorators[0];
|
||||||
return extractQueryMetadata(
|
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(
|
function extractHostBindings(
|
||||||
metadata: Map<string, ts.Expression>, members: ClassMember[], reflector: ReflectionHost,
|
metadata: Map<string, ts.Expression>, members: ClassMember[], evaluator: PartialEvaluator,
|
||||||
checker: ts.TypeChecker, coreModule: string | undefined): {
|
coreModule: string | undefined): {
|
||||||
attributes: StringMap,
|
attributes: StringMap,
|
||||||
listeners: StringMap,
|
listeners: StringMap,
|
||||||
properties: StringMap,
|
properties: StringMap,
|
||||||
|
@ -421,7 +421,7 @@ function extractHostBindings(
|
||||||
let hostMetadata: StringMap = {};
|
let hostMetadata: StringMap = {};
|
||||||
if (metadata.has('host')) {
|
if (metadata.has('host')) {
|
||||||
const expr = metadata.get('host') !;
|
const expr = metadata.get('host') !;
|
||||||
const hostMetaMap = staticallyResolve(expr, reflector, checker);
|
const hostMetaMap = evaluator.evaluate(expr);
|
||||||
if (!(hostMetaMap instanceof Map)) {
|
if (!(hostMetaMap instanceof Map)) {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.DECORATOR_ARG_NOT_LITERAL, expr, `Decorator host metadata must be an object`);
|
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`);
|
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') {
|
if (typeof resolved !== 'string') {
|
||||||
throw new Error(`@HostBinding()'s argument must be a string`);
|
throw new Error(`@HostBinding()'s argument must be a string`);
|
||||||
}
|
}
|
||||||
|
@ -469,7 +469,7 @@ function extractHostBindings(
|
||||||
`@HostListener() can have at most two arguments`);
|
`@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') {
|
if (typeof resolved !== 'string') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, decorator.args[0],
|
ErrorCode.VALUE_HAS_WRONG_TYPE, decorator.args[0],
|
||||||
|
@ -479,7 +479,7 @@ function extractHostBindings(
|
||||||
eventName = resolved;
|
eventName = resolved;
|
||||||
|
|
||||||
if (decorator.args.length === 2) {
|
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')) {
|
if (!isStringArrayOrDie(resolvedArgs, '@HostListener.args')) {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, decorator.args[1],
|
ErrorCode.VALUE_HAS_WRONG_TYPE, decorator.args[1],
|
||||||
|
|
|
@ -10,8 +10,7 @@ import {Expression, LiteralExpr, R3DependencyMetadata, R3InjectableMetadata, R3R
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||||
import {Decorator, ReflectionHost} from '../../host';
|
import {Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection';
|
||||||
import {reflectObjectLiteral} from '../../metadata';
|
|
||||||
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
|
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
|
||||||
|
|
||||||
import {generateSetClassMetadataCall} from './metadata';
|
import {generateSetClassMetadataCall} from './metadata';
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import {ExternalExpr, Identifiers, InvokeFunctionExpr, Statement, WrappedNodeExpr} from '@angular/compiler';
|
import {ExternalExpr, Identifiers, InvokeFunctionExpr, Statement, WrappedNodeExpr} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
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
|
* Given a class declaration, generate a call to `setClassMetadata` with the Angular metadata
|
||||||
|
|
|
@ -10,8 +10,9 @@ import {Expression, LiteralArrayExpr, R3InjectorMetadata, R3NgModuleMetadata, R3
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||||
import {Decorator, ReflectionHost} from '../../host';
|
import {Reference, ResolvedReference} from '../../imports';
|
||||||
import {Reference, ResolvedReference, ResolvedValue, reflectObjectLiteral, staticallyResolve, typeNodeToValueExpr} from '../../metadata';
|
import {PartialEvaluator, ResolvedValue} from '../../partial_evaluator';
|
||||||
|
import {Decorator, ReflectionHost, reflectObjectLiteral, typeNodeToValueExpr} from '../../reflection';
|
||||||
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
|
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
|
||||||
|
|
||||||
import {generateSetClassMetadataCall} from './metadata';
|
import {generateSetClassMetadataCall} from './metadata';
|
||||||
|
@ -32,7 +33,7 @@ export interface NgModuleAnalysis {
|
||||||
*/
|
*/
|
||||||
export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalysis, Decorator> {
|
export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalysis, Decorator> {
|
||||||
constructor(
|
constructor(
|
||||||
private checker: ts.TypeChecker, private reflector: ReflectionHost,
|
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
|
||||||
private scopeRegistry: SelectorScopeRegistry, private referencesRegistry: ReferencesRegistry,
|
private scopeRegistry: SelectorScopeRegistry, private referencesRegistry: ReferencesRegistry,
|
||||||
private isCore: boolean) {}
|
private isCore: boolean) {}
|
||||||
|
|
||||||
|
@ -72,32 +73,30 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
|
||||||
let declarations: Reference<ts.Declaration>[] = [];
|
let declarations: Reference<ts.Declaration>[] = [];
|
||||||
if (ngModule.has('declarations')) {
|
if (ngModule.has('declarations')) {
|
||||||
const expr = ngModule.get('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');
|
declarations = this.resolveTypeList(expr, declarationMeta, 'declarations');
|
||||||
this.referencesRegistry.add(...declarations);
|
this.referencesRegistry.add(...declarations);
|
||||||
}
|
}
|
||||||
let imports: Reference<ts.Declaration>[] = [];
|
let imports: Reference<ts.Declaration>[] = [];
|
||||||
if (ngModule.has('imports')) {
|
if (ngModule.has('imports')) {
|
||||||
const expr = ngModule.get('imports') !;
|
const expr = ngModule.get('imports') !;
|
||||||
const importsMeta = staticallyResolve(
|
const importsMeta = this.evaluator.evaluate(
|
||||||
expr, this.reflector, this.checker,
|
expr, ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
|
||||||
ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
|
|
||||||
imports = this.resolveTypeList(expr, importsMeta, 'imports');
|
imports = this.resolveTypeList(expr, importsMeta, 'imports');
|
||||||
this.referencesRegistry.add(...imports);
|
this.referencesRegistry.add(...imports);
|
||||||
}
|
}
|
||||||
let exports: Reference<ts.Declaration>[] = [];
|
let exports: Reference<ts.Declaration>[] = [];
|
||||||
if (ngModule.has('exports')) {
|
if (ngModule.has('exports')) {
|
||||||
const expr = ngModule.get('exports') !;
|
const expr = ngModule.get('exports') !;
|
||||||
const exportsMeta = staticallyResolve(
|
const exportsMeta = this.evaluator.evaluate(
|
||||||
expr, this.reflector, this.checker,
|
expr, ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
|
||||||
ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
|
|
||||||
exports = this.resolveTypeList(expr, exportsMeta, 'exports');
|
exports = this.resolveTypeList(expr, exportsMeta, 'exports');
|
||||||
this.referencesRegistry.add(...exports);
|
this.referencesRegistry.add(...exports);
|
||||||
}
|
}
|
||||||
let bootstrap: Reference<ts.Declaration>[] = [];
|
let bootstrap: Reference<ts.Declaration>[] = [];
|
||||||
if (ngModule.has('bootstrap')) {
|
if (ngModule.has('bootstrap')) {
|
||||||
const expr = ngModule.get('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');
|
bootstrap = this.resolveTypeList(expr, bootstrapMeta, 'bootstrap');
|
||||||
this.referencesRegistry.add(...bootstrap);
|
this.referencesRegistry.add(...bootstrap);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@ import {LiteralExpr, R3PipeMetadata, Statement, WrappedNodeExpr, compilePipeFrom
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||||
import {Decorator, ReflectionHost} from '../../host';
|
import {PartialEvaluator} from '../../partial_evaluator';
|
||||||
import {reflectObjectLiteral, staticallyResolve} from '../../metadata';
|
import {Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection';
|
||||||
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
|
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
|
||||||
|
|
||||||
import {generateSetClassMetadataCall} from './metadata';
|
import {generateSetClassMetadataCall} from './metadata';
|
||||||
|
@ -25,7 +25,7 @@ export interface PipeHandlerData {
|
||||||
|
|
||||||
export class PipeDecoratorHandler implements DecoratorHandler<PipeHandlerData, Decorator> {
|
export class PipeDecoratorHandler implements DecoratorHandler<PipeHandlerData, Decorator> {
|
||||||
constructor(
|
constructor(
|
||||||
private checker: ts.TypeChecker, private reflector: ReflectionHost,
|
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
|
||||||
private scopeRegistry: SelectorScopeRegistry, private isCore: boolean) {}
|
private scopeRegistry: SelectorScopeRegistry, private isCore: boolean) {}
|
||||||
|
|
||||||
detect(node: ts.Declaration, decorators: Decorator[]|null): Decorator|undefined {
|
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`);
|
ErrorCode.PIPE_MISSING_NAME, meta, `@Pipe decorator is missing name field`);
|
||||||
}
|
}
|
||||||
const pipeNameExpr = pipe.get('name') !;
|
const pipeNameExpr = pipe.get('name') !;
|
||||||
const pipeName = staticallyResolve(pipeNameExpr, this.reflector, this.checker);
|
const pipeName = this.evaluator.evaluate(pipeNameExpr);
|
||||||
if (typeof pipeName !== 'string') {
|
if (typeof pipeName !== 'string') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, pipeNameExpr, `@Pipe.name must be a string`);
|
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;
|
let pure = true;
|
||||||
if (pipe.has('pure')) {
|
if (pipe.has('pure')) {
|
||||||
const expr = pipe.get('pure') !;
|
const expr = pipe.get('pure') !;
|
||||||
const pureValue = staticallyResolve(expr, this.reflector, this.checker);
|
const pureValue = this.evaluator.evaluate(expr);
|
||||||
if (typeof pureValue !== 'boolean') {
|
if (typeof pureValue !== 'boolean') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `@Pipe.pure must be a boolean`);
|
ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `@Pipe.pure must be a boolean`);
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {Declaration} from '../../host';
|
import {Reference} from '../../imports';
|
||||||
import {Reference} from '../../metadata';
|
import {Declaration} from '../../reflection';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implement this interface if you want DecoratorHandlers to register
|
* Implement this interface if you want DecoratorHandlers to register
|
||||||
|
|
|
@ -6,12 +6,11 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* 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 * as ts from 'typescript';
|
||||||
|
|
||||||
import {ReflectionHost} from '../../host';
|
import {AbsoluteReference, Reference, ResolvedReference} from '../../imports';
|
||||||
import {AbsoluteReference, Reference, ResolvedReference, reflectTypeEntityToDeclaration} from '../../metadata';
|
import {ReflectionHost, reflectIdentifierOfDeclaration, reflectNameOfDeclaration, reflectTypeEntityToDeclaration} from '../../reflection';
|
||||||
import {reflectIdentifierOfDeclaration, reflectNameOfDeclaration} from '../../metadata/src/reflector';
|
|
||||||
import {TypeCheckableDirectiveMeta} from '../../typecheck';
|
import {TypeCheckableDirectiveMeta} from '../../typecheck';
|
||||||
|
|
||||||
import {extractDirectiveGuards} from './util';
|
import {extractDirectiveGuards} from './util';
|
||||||
|
|
|
@ -6,12 +6,12 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* 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 * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||||
import {ClassMemberKind, Decorator, ReflectionHost} from '../../host';
|
import {AbsoluteReference, ImportMode, Reference} from '../../imports';
|
||||||
import {AbsoluteReference, ImportMode, Reference} from '../../metadata';
|
import {ClassMemberKind, Decorator, ReflectionHost} from '../../reflection';
|
||||||
|
|
||||||
export function getConstructorDependencies(
|
export function getConstructorDependencies(
|
||||||
clazz: ts.ClassDeclaration, reflector: ReflectionHost, isCore: boolean): R3DependencyMetadata[]|
|
clazz: ts.ClassDeclaration, reflector: ReflectionHost, isCore: boolean): R3DependencyMetadata[]|
|
||||||
|
|
|
@ -13,7 +13,9 @@ ts_library(
|
||||||
"//packages/compiler",
|
"//packages/compiler",
|
||||||
"//packages/compiler-cli/src/ngtsc/annotations",
|
"//packages/compiler-cli/src/ngtsc/annotations",
|
||||||
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
"//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/testing",
|
||||||
"//packages/compiler-cli/src/ngtsc/translator",
|
"//packages/compiler-cli/src/ngtsc/translator",
|
||||||
"@ngdeps//typescript",
|
"@ngdeps//typescript",
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
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 {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
|
||||||
import {ResourceLoader} from '../src/api';
|
import {ResourceLoader} from '../src/api';
|
||||||
import {ComponentDecoratorHandler} from '../src/component';
|
import {ComponentDecoratorHandler} from '../src/component';
|
||||||
|
@ -38,8 +40,9 @@ describe('ComponentDecoratorHandler', () => {
|
||||||
]);
|
]);
|
||||||
const checker = program.getTypeChecker();
|
const checker = program.getTypeChecker();
|
||||||
const host = new TypeScriptReflectionHost(checker);
|
const host = new TypeScriptReflectionHost(checker);
|
||||||
|
const evaluator = new PartialEvaluator(host, checker);
|
||||||
const handler = new ComponentDecoratorHandler(
|
const handler = new ComponentDecoratorHandler(
|
||||||
checker, host, new SelectorScopeRegistry(checker, host), false, new NoopResourceLoader(),
|
host, evaluator, new SelectorScopeRegistry(checker, host), false, new NoopResourceLoader(),
|
||||||
[''], false, true);
|
[''], false, true);
|
||||||
const TestCmp = getDeclaration(program, 'entry.ts', 'TestCmp', ts.isClassDeclaration);
|
const TestCmp = getDeclaration(program, 'entry.ts', 'TestCmp', ts.isClassDeclaration);
|
||||||
const detected = handler.detect(TestCmp, host.getDecoratorsOfDeclaration(TestCmp));
|
const detected = handler.detect(TestCmp, host.getDecoratorsOfDeclaration(TestCmp));
|
||||||
|
|
|
@ -6,12 +6,12 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Statement} from '@angular/compiler';
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {TypeScriptReflectionHost} from '../../metadata';
|
import {TypeScriptReflectionHost} from '../../reflection';
|
||||||
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
|
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
|
||||||
import {ImportManager, translateStatement} from '../../translator';
|
import {ImportManager, translateStatement} from '../../translator';
|
||||||
|
|
||||||
import {generateSetClassMetadataCall} from '../src/metadata';
|
import {generateSetClassMetadataCall} from '../src/metadata';
|
||||||
|
|
||||||
const CORE = {
|
const CORE = {
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {TypeScriptReflectionHost} from '../../metadata';
|
import {AbsoluteReference, ResolvedReference} from '../../imports';
|
||||||
import {AbsoluteReference, ResolvedReference} from '../../metadata/src/resolver';
|
import {TypeScriptReflectionHost} from '../../reflection';
|
||||||
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
|
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
|
||||||
import {NgModuleDecoratorHandler} from '../src/ng_module';
|
|
||||||
import {SelectorScopeRegistry} from '../src/selector_scope';
|
import {SelectorScopeRegistry} from '../src/selector_scope';
|
||||||
|
|
||||||
describe('SelectorScopeRegistry', () => {
|
describe('SelectorScopeRegistry', () => {
|
||||||
|
|
|
@ -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",
|
||||||
|
],
|
||||||
|
)
|
|
@ -6,4 +6,4 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export * from './src/reflection';
|
export {AbsoluteReference, ImportMode, NodeReference, Reference, ResolvedReference} from './src/references';
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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';
|
|
|
@ -3,16 +3,17 @@ package(default_visibility = ["//visibility:public"])
|
||||||
load("//tools:defaults.bzl", "ts_library")
|
load("//tools:defaults.bzl", "ts_library")
|
||||||
|
|
||||||
ts_library(
|
ts_library(
|
||||||
name = "metadata",
|
name = "partial_evaluator",
|
||||||
srcs = glob([
|
srcs = glob([
|
||||||
"index.ts",
|
"index.ts",
|
||||||
"src/*.ts",
|
"src/*.ts",
|
||||||
]),
|
]),
|
||||||
module_name = "@angular/compiler-cli/src/ngtsc/metadata",
|
module_name = "@angular/compiler-cli/src/ngtsc/partial_evaluator",
|
||||||
deps = [
|
deps = [
|
||||||
"//packages:types",
|
"//packages:types",
|
||||||
"//packages/compiler",
|
"//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",
|
"//packages/compiler-cli/src/ngtsc/util",
|
||||||
"@ngdeps//@types/node",
|
"@ngdeps//@types/node",
|
||||||
"@ngdeps//typescript",
|
"@ngdeps//typescript",
|
|
@ -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';
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,97 +6,14 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* 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 * 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
|
* 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>;
|
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 {
|
interface BinaryOperatorDef {
|
||||||
literal: boolean;
|
literal: boolean;
|
||||||
op: (a: any, b: any) => ResolvedValue;
|
op: (a: any, b: any) => ResolvedValue;
|
||||||
|
@ -309,7 +68,7 @@ interface Context {
|
||||||
args: ReadonlyArray<ts.Expression>): ts.Expression|null;
|
args: ReadonlyArray<ts.Expression>): ts.Expression|null;
|
||||||
}
|
}
|
||||||
|
|
||||||
class StaticInterpreter {
|
export class StaticInterpreter {
|
||||||
constructor(private host: ReflectionHost, private checker: ts.TypeChecker) {}
|
constructor(private host: ReflectionHost, private checker: ts.TypeChecker) {}
|
||||||
|
|
||||||
visit(node: ts.Expression, context: Context): ResolvedValue {
|
visit(node: ts.Expression, context: Context): ResolvedValue {
|
|
@ -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; }
|
|
@ -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",
|
||||||
|
],
|
||||||
|
)
|
|
@ -9,9 +9,11 @@
|
||||||
import {WrappedNodeExpr} from '@angular/compiler';
|
import {WrappedNodeExpr} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
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 {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 {
|
function makeSimpleProgram(contents: string): ts.Program {
|
||||||
return makeProgram([{name: 'entry.ts', contents}]).program;
|
return makeProgram([{name: 'entry.ts', contents}]).program;
|
||||||
|
@ -32,7 +34,8 @@ function makeExpression(
|
||||||
function evaluate<T extends ResolvedValue>(code: string, expr: string): T {
|
function evaluate<T extends ResolvedValue>(code: string, expr: string): T {
|
||||||
const {expression, checker} = makeExpression(code, expr);
|
const {expression, checker} = makeExpression(code, expr);
|
||||||
const host = new TypeScriptReflectionHost(checker);
|
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', () => {
|
describe('ngtsc metadata', () => {
|
||||||
|
@ -55,8 +58,9 @@ describe('ngtsc metadata', () => {
|
||||||
]);
|
]);
|
||||||
const decl = getDeclaration(program, 'entry.ts', 'X', ts.isVariableDeclaration);
|
const decl = getDeclaration(program, 'entry.ts', 'X', ts.isVariableDeclaration);
|
||||||
const host = new TypeScriptReflectionHost(program.getTypeChecker());
|
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');
|
expect(value).toEqual('test');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -142,7 +146,8 @@ describe('ngtsc metadata', () => {
|
||||||
const host = new TypeScriptReflectionHost(checker);
|
const host = new TypeScriptReflectionHost(checker);
|
||||||
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
|
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
|
||||||
const expr = result.initializer !;
|
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)) {
|
if (!(resolved instanceof Reference)) {
|
||||||
return fail('Expected expression to resolve to a reference');
|
return fail('Expected expression to resolve to a reference');
|
||||||
}
|
}
|
||||||
|
@ -173,7 +178,8 @@ describe('ngtsc metadata', () => {
|
||||||
const host = new TypeScriptReflectionHost(checker);
|
const host = new TypeScriptReflectionHost(checker);
|
||||||
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
|
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
|
||||||
const expr = result.initializer !;
|
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)) {
|
if (!(resolved instanceof AbsoluteReference)) {
|
||||||
return fail('Expected expression to resolve to an absolute reference');
|
return fail('Expected expression to resolve to an absolute reference');
|
||||||
}
|
}
|
||||||
|
@ -205,7 +211,8 @@ describe('ngtsc metadata', () => {
|
||||||
const host = new TypeScriptReflectionHost(checker);
|
const host = new TypeScriptReflectionHost(checker);
|
||||||
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
|
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
|
||||||
const expr = result.initializer !;
|
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', () => {
|
it('reads values from named exports', () => {
|
||||||
|
@ -223,7 +230,8 @@ describe('ngtsc metadata', () => {
|
||||||
const host = new TypeScriptReflectionHost(checker);
|
const host = new TypeScriptReflectionHost(checker);
|
||||||
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
|
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
|
||||||
const expr = result.initializer !;
|
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', () => {
|
it('chain of re-exports works', () => {
|
||||||
|
@ -241,7 +249,8 @@ describe('ngtsc metadata', () => {
|
||||||
const host = new TypeScriptReflectionHost(checker);
|
const host = new TypeScriptReflectionHost(checker);
|
||||||
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
|
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
|
||||||
const expr = result.initializer !;
|
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', () => {
|
it('map spread works', () => {
|
||||||
|
@ -297,7 +306,8 @@ describe('ngtsc metadata', () => {
|
||||||
const checker = program.getTypeChecker();
|
const checker = program.getTypeChecker();
|
||||||
const host = new TypeScriptReflectionHost(checker);
|
const host = new TypeScriptReflectionHost(checker);
|
||||||
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
|
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);
|
expect(res instanceof Reference).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -7,7 +7,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {GeneratedFile} from '@angular/compiler';
|
import {GeneratedFile} from '@angular/compiler';
|
||||||
import * as path from 'path';
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import * as api from '../transformers/api';
|
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 {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, NoopReferencesRegistry, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from './annotations';
|
||||||
import {BaseDefDecoratorHandler} from './annotations/src/base_def';
|
import {BaseDefDecoratorHandler} from './annotations/src/base_def';
|
||||||
import {FlatIndexGenerator} from './entry_point';
|
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 {FileResourceLoader, HostResourceLoader} from './resource_loader';
|
||||||
import {FactoryGenerator, FactoryInfo, GeneratedShimsHostWrapper, ShimGenerator, SummaryGenerator, generatedFactoryTransform} from './shims';
|
import {FactoryGenerator, FactoryInfo, GeneratedShimsHostWrapper, ShimGenerator, SummaryGenerator, generatedFactoryTransform} from './shims';
|
||||||
import {ivySwitchTransform} from './switch';
|
import {ivySwitchTransform} from './switch';
|
||||||
|
@ -251,20 +251,21 @@ export class NgtscProgram implements api.Program {
|
||||||
|
|
||||||
private makeCompilation(): IvyCompilation {
|
private makeCompilation(): IvyCompilation {
|
||||||
const checker = this.tsProgram.getTypeChecker();
|
const checker = this.tsProgram.getTypeChecker();
|
||||||
|
const evaluator = new PartialEvaluator(this.reflector, checker);
|
||||||
const scopeRegistry = new SelectorScopeRegistry(checker, this.reflector);
|
const scopeRegistry = new SelectorScopeRegistry(checker, this.reflector);
|
||||||
const referencesRegistry = new NoopReferencesRegistry();
|
const referencesRegistry = new NoopReferencesRegistry();
|
||||||
|
|
||||||
// Set up the IvyCompilation, which manages state for the Ivy transformer.
|
// Set up the IvyCompilation, which manages state for the Ivy transformer.
|
||||||
const handlers = [
|
const handlers = [
|
||||||
new BaseDefDecoratorHandler(checker, this.reflector),
|
new BaseDefDecoratorHandler(this.reflector, evaluator),
|
||||||
new ComponentDecoratorHandler(
|
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),
|
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 InjectableDecoratorHandler(this.reflector, this.isCore),
|
||||||
new NgModuleDecoratorHandler(
|
new NgModuleDecoratorHandler(
|
||||||
checker, this.reflector, scopeRegistry, referencesRegistry, this.isCore),
|
this.reflector, evaluator, scopeRegistry, referencesRegistry, this.isCore),
|
||||||
new PipeDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore),
|
new PipeDecoratorHandler(this.reflector, evaluator, scopeRegistry, this.isCore),
|
||||||
];
|
];
|
||||||
|
|
||||||
return new IvyCompilation(
|
return new IvyCompilation(
|
||||||
|
|
|
@ -3,11 +3,11 @@ package(default_visibility = ["//visibility:public"])
|
||||||
load("//tools:defaults.bzl", "ts_library")
|
load("//tools:defaults.bzl", "ts_library")
|
||||||
|
|
||||||
ts_library(
|
ts_library(
|
||||||
name = "host",
|
name = "reflection",
|
||||||
srcs = glob([
|
srcs = glob([
|
||||||
"index.ts",
|
"index.ts",
|
||||||
"src/**/*.ts",
|
"src/**/*.ts",
|
||||||
]),
|
]),
|
||||||
module_name = "@angular/compiler-cli/src/ngtsc/host",
|
module_name = "@angular/compiler-cli/src/ngtsc/reflection",
|
||||||
deps = ["@ngdeps//typescript"],
|
deps = ["@ngdeps//typescript"],
|
||||||
)
|
)
|
|
@ -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';
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
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`.
|
* reflector.ts implements static reflection of declarations using the TypeScript `ts.TypeChecker`.
|
|
@ -10,9 +10,7 @@ ts_library(
|
||||||
]),
|
]),
|
||||||
deps = [
|
deps = [
|
||||||
"//packages:types",
|
"//packages:types",
|
||||||
"//packages/compiler",
|
"//packages/compiler-cli/src/ngtsc/reflection",
|
||||||
"//packages/compiler-cli/src/ngtsc/host",
|
|
||||||
"//packages/compiler-cli/src/ngtsc/metadata",
|
|
||||||
"//packages/compiler-cli/src/ngtsc/testing",
|
"//packages/compiler-cli/src/ngtsc/testing",
|
||||||
"@ngdeps//typescript",
|
"@ngdeps//typescript",
|
||||||
],
|
],
|
|
@ -8,9 +8,9 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {CtorParameter} from '../../host';
|
|
||||||
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
|
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('reflector', () => {
|
||||||
describe('ctor params', () => {
|
describe('ctor params', () => {
|
|
@ -11,8 +11,6 @@ ts_library(
|
||||||
module_name = "@angular/compiler-cli/src/ngtsc/shims",
|
module_name = "@angular/compiler-cli/src/ngtsc/shims",
|
||||||
deps = [
|
deps = [
|
||||||
"//packages/compiler",
|
"//packages/compiler",
|
||||||
"//packages/compiler-cli/src/ngtsc/host",
|
|
||||||
"//packages/compiler-cli/src/ngtsc/metadata",
|
|
||||||
"//packages/compiler-cli/src/ngtsc/util",
|
"//packages/compiler-cli/src/ngtsc/util",
|
||||||
"@ngdeps//@types/node",
|
"@ngdeps//@types/node",
|
||||||
"@ngdeps//typescript",
|
"@ngdeps//typescript",
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as path from 'path';
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
export interface ShimGenerator {
|
export interface ShimGenerator {
|
||||||
|
|
|
@ -11,9 +11,6 @@ ts_library(
|
||||||
module_name = "@angular/compiler-cli/src/ngtsc/switch",
|
module_name = "@angular/compiler-cli/src/ngtsc/switch",
|
||||||
deps = [
|
deps = [
|
||||||
"//packages/compiler",
|
"//packages/compiler",
|
||||||
"//packages/compiler-cli/src/ngtsc/host",
|
|
||||||
"//packages/compiler-cli/src/ngtsc/metadata",
|
|
||||||
"//packages/compiler-cli/src/ngtsc/util",
|
|
||||||
"@ngdeps//typescript",
|
"@ngdeps//typescript",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -12,8 +12,7 @@ ts_library(
|
||||||
deps = [
|
deps = [
|
||||||
"//packages/compiler",
|
"//packages/compiler",
|
||||||
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
||||||
"//packages/compiler-cli/src/ngtsc/host",
|
"//packages/compiler-cli/src/ngtsc/reflection",
|
||||||
"//packages/compiler-cli/src/ngtsc/metadata",
|
|
||||||
"//packages/compiler-cli/src/ngtsc/translator",
|
"//packages/compiler-cli/src/ngtsc/translator",
|
||||||
"//packages/compiler-cli/src/ngtsc/typecheck",
|
"//packages/compiler-cli/src/ngtsc/typecheck",
|
||||||
"//packages/compiler-cli/src/ngtsc/util",
|
"//packages/compiler-cli/src/ngtsc/util",
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import {ConstantPool, Expression, Statement, Type} from '@angular/compiler';
|
import {ConstantPool, Expression, Statement, Type} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {Decorator} from '../../host';
|
import {Decorator} from '../../reflection';
|
||||||
import {TypeCheckContext} from '../../typecheck';
|
import {TypeCheckContext} from '../../typecheck';
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,7 @@ import {ConstantPool} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {FatalDiagnosticError} from '../../diagnostics';
|
import {FatalDiagnosticError} from '../../diagnostics';
|
||||||
import {Decorator, ReflectionHost} from '../../host';
|
import {Decorator, ReflectionHost, reflectNameOfDeclaration} from '../../reflection';
|
||||||
import {reflectNameOfDeclaration} from '../../metadata/src/reflector';
|
|
||||||
import {TypeCheckContext} from '../../typecheck';
|
import {TypeCheckContext} from '../../typecheck';
|
||||||
|
|
||||||
import {AnalysisOutput, CompileResult, DecoratorHandler} from './api';
|
import {AnalysisOutput, CompileResult, DecoratorHandler} from './api';
|
||||||
|
|
|
@ -9,9 +9,8 @@
|
||||||
import {ConstantPool} from '@angular/compiler';
|
import {ConstantPool} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {Decorator, ReflectionHost} from '../../host';
|
import {Decorator, ReflectionHost} from '../../reflection';
|
||||||
import {ImportManager, translateExpression, translateStatement} from '../../translator';
|
import {ImportManager, translateExpression, translateStatement} from '../../translator';
|
||||||
import {relativePathBetween} from '../../util/src/path';
|
|
||||||
import {VisitListEntryResult, Visitor, visit} from '../../util/src/visitor';
|
import {VisitListEntryResult, Visitor, visit} from '../../util/src/visitor';
|
||||||
|
|
||||||
import {CompileResult} from './api';
|
import {CompileResult} from './api';
|
||||||
|
|
|
@ -9,7 +9,7 @@ ts_library(
|
||||||
deps = [
|
deps = [
|
||||||
"//packages:types",
|
"//packages:types",
|
||||||
"//packages/compiler",
|
"//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/translator",
|
||||||
"//packages/compiler-cli/src/ngtsc/util",
|
"//packages/compiler-cli/src/ngtsc/util",
|
||||||
"@ngdeps//typescript",
|
"@ngdeps//typescript",
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import {BoundTarget, DirectiveMeta} from '@angular/compiler';
|
import {BoundTarget, DirectiveMeta} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
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
|
* Extension of `DirectiveMeta` that includes additional information required to type-check the
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import {AST, BindingType, BoundTarget, ImplicitReceiver, PropertyRead, TmplAstBoundText, TmplAstElement, TmplAstNode, TmplAstTemplate, TmplAstVariable} from '@angular/compiler';
|
import {AST, BindingType, BoundTarget, ImplicitReceiver, PropertyRead, TmplAstBoundText, TmplAstElement, TmplAstNode, TmplAstTemplate, TmplAstVariable} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {Reference} from '../../metadata';
|
import {Reference} from '../../imports';
|
||||||
import {ImportManager, translateExpression} from '../../translator';
|
import {ImportManager, translateExpression} from '../../translator';
|
||||||
|
|
||||||
import {TypeCheckBlockMetadata, TypeCheckableDirectiveMeta} from './api';
|
import {TypeCheckBlockMetadata, TypeCheckableDirectiveMeta} from './api';
|
||||||
|
|
|
@ -10,8 +10,6 @@ ts_library(
|
||||||
]),
|
]),
|
||||||
deps = [
|
deps = [
|
||||||
"//packages:types",
|
"//packages:types",
|
||||||
"//packages/compiler",
|
|
||||||
"//packages/compiler-cli/src/ngtsc/host",
|
|
||||||
"//packages/compiler-cli/src/ngtsc/testing",
|
"//packages/compiler-cli/src/ngtsc/testing",
|
||||||
"//packages/compiler-cli/src/ngtsc/typecheck",
|
"//packages/compiler-cli/src/ngtsc/typecheck",
|
||||||
"@ngdeps//typescript",
|
"@ngdeps//typescript",
|
||||||
|
|
Loading…
Reference in New Issue