diff --git a/packages/compiler-cli/BUILD.bazel b/packages/compiler-cli/BUILD.bazel index 859161c0c5..398fb53865 100644 --- a/packages/compiler-cli/BUILD.bazel +++ b/packages/compiler-cli/BUILD.bazel @@ -27,7 +27,8 @@ ts_library( "//packages/compiler-cli/src/ngtsc/annotations", "//packages/compiler-cli/src/ngtsc/diagnostics", "//packages/compiler-cli/src/ngtsc/entry_point", - "//packages/compiler-cli/src/ngtsc/metadata", + "//packages/compiler-cli/src/ngtsc/partial_evaluator", + "//packages/compiler-cli/src/ngtsc/reflection", "//packages/compiler-cli/src/ngtsc/shims", "//packages/compiler-cli/src/ngtsc/switch", "//packages/compiler-cli/src/ngtsc/transform", diff --git a/packages/compiler-cli/src/ngcc/BUILD.bazel b/packages/compiler-cli/src/ngcc/BUILD.bazel index b0f98698e3..3457bfb246 100644 --- a/packages/compiler-cli/src/ngcc/BUILD.bazel +++ b/packages/compiler-cli/src/ngcc/BUILD.bazel @@ -13,8 +13,9 @@ ts_library( "//packages:types", "//packages/compiler", "//packages/compiler-cli/src/ngtsc/annotations", - "//packages/compiler-cli/src/ngtsc/host", - "//packages/compiler-cli/src/ngtsc/metadata", + "//packages/compiler-cli/src/ngtsc/imports", + "//packages/compiler-cli/src/ngtsc/partial_evaluator", + "//packages/compiler-cli/src/ngtsc/reflection", "//packages/compiler-cli/src/ngtsc/transform", "//packages/compiler-cli/src/ngtsc/translator", "@ngdeps//@types/convert-source-map", diff --git a/packages/compiler-cli/src/ngcc/src/analysis/decoration_analyzer.ts b/packages/compiler-cli/src/ngcc/src/analysis/decoration_analyzer.ts index d9749b1cb1..656a3400e9 100644 --- a/packages/compiler-cli/src/ngcc/src/analysis/decoration_analyzer.ts +++ b/packages/compiler-cli/src/ngcc/src/analysis/decoration_analyzer.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import {ConstantPool} from '@angular/compiler'; +import {PartialEvaluator} from '@angular/compiler-cli/src/ngtsc/partial_evaluator'; import * as path from 'canonical-path'; import * as fs from 'fs'; import * as ts from 'typescript'; @@ -59,16 +60,17 @@ export class FileResourceLoader implements ResourceLoader { export class DecorationAnalyzer { resourceLoader = new FileResourceLoader(); scopeRegistry = new SelectorScopeRegistry(this.typeChecker, this.host); + evaluator = new PartialEvaluator(this.host, this.typeChecker); handlers: DecoratorHandler[] = [ - new BaseDefDecoratorHandler(this.typeChecker, this.host), + new BaseDefDecoratorHandler(this.host, this.evaluator), new ComponentDecoratorHandler( - this.typeChecker, this.host, this.scopeRegistry, this.isCore, this.resourceLoader, + this.host, this.evaluator, this.scopeRegistry, this.isCore, this.resourceLoader, this.rootDirs, /* defaultPreserveWhitespaces */ false, /* i18nUseExternalIds */ true), - new DirectiveDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore), + new DirectiveDecoratorHandler(this.host, this.evaluator, this.scopeRegistry, this.isCore), new InjectableDecoratorHandler(this.host, this.isCore), new NgModuleDecoratorHandler( - this.typeChecker, this.host, this.scopeRegistry, this.referencesRegistry, this.isCore), - new PipeDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore), + this.host, this.evaluator, this.scopeRegistry, this.referencesRegistry, this.isCore), + new PipeDecoratorHandler(this.host, this.evaluator, this.scopeRegistry, this.isCore), ]; constructor( diff --git a/packages/compiler-cli/src/ngcc/src/analysis/module_with_providers_analyzer.ts b/packages/compiler-cli/src/ngcc/src/analysis/module_with_providers_analyzer.ts index fe774860d9..c02636bade 100644 --- a/packages/compiler-cli/src/ngcc/src/analysis/module_with_providers_analyzer.ts +++ b/packages/compiler-cli/src/ngcc/src/analysis/module_with_providers_analyzer.ts @@ -8,8 +8,8 @@ import * as ts from 'typescript'; import {ReferencesRegistry} from '../../../ngtsc/annotations'; -import {Declaration} from '../../../ngtsc/host'; -import {ResolvedReference} from '../../../ngtsc/metadata'; +import {ResolvedReference} from '../../../ngtsc/imports'; +import {Declaration} from '../../../ngtsc/reflection'; import {NgccReflectionHost} from '../host/ngcc_host'; import {isDefined} from '../utils'; diff --git a/packages/compiler-cli/src/ngcc/src/analysis/ngcc_references_registry.ts b/packages/compiler-cli/src/ngcc/src/analysis/ngcc_references_registry.ts index f4779456b6..eaf43bf834 100644 --- a/packages/compiler-cli/src/ngcc/src/analysis/ngcc_references_registry.ts +++ b/packages/compiler-cli/src/ngcc/src/analysis/ngcc_references_registry.ts @@ -8,8 +8,8 @@ import * as ts from 'typescript'; import {ReferencesRegistry} from '../../../ngtsc/annotations'; -import {Declaration, ReflectionHost} from '../../../ngtsc/host'; -import {Reference, ResolvedReference} from '../../../ngtsc/metadata'; +import {Reference, ResolvedReference} from '../../../ngtsc/imports'; +import {Declaration, ReflectionHost} from '../../../ngtsc/reflection'; import {hasNameIdentifier} from '../utils'; /** diff --git a/packages/compiler-cli/src/ngcc/src/analysis/private_declarations_analyzer.ts b/packages/compiler-cli/src/ngcc/src/analysis/private_declarations_analyzer.ts index 3420b669b6..d8b1ae02b1 100644 --- a/packages/compiler-cli/src/ngcc/src/analysis/private_declarations_analyzer.ts +++ b/packages/compiler-cli/src/ngcc/src/analysis/private_declarations_analyzer.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; import {ReferencesRegistry} from '../../../ngtsc/annotations'; -import {Declaration} from '../../../ngtsc/host'; +import {Declaration} from '../../../ngtsc/reflection'; import {NgccReflectionHost} from '../host/ngcc_host'; import {hasNameIdentifier, isDefined} from '../utils'; diff --git a/packages/compiler-cli/src/ngcc/src/host/decorated_class.ts b/packages/compiler-cli/src/ngcc/src/host/decorated_class.ts index 46cd4c8a19..985ef0a596 100644 --- a/packages/compiler-cli/src/ngcc/src/host/decorated_class.ts +++ b/packages/compiler-cli/src/ngcc/src/host/decorated_class.ts @@ -7,7 +7,7 @@ */ import * as ts from 'typescript'; -import {Decorator} from '../../../ngtsc/host'; +import {Decorator} from '../../../ngtsc/reflection'; /** * A simple container that holds the details of a decorated class that has been diff --git a/packages/compiler-cli/src/ngcc/src/host/esm2015_host.ts b/packages/compiler-cli/src/ngcc/src/host/esm2015_host.ts index 34f3345369..c3e57f23bf 100644 --- a/packages/compiler-cli/src/ngcc/src/host/esm2015_host.ts +++ b/packages/compiler-cli/src/ngcc/src/host/esm2015_host.ts @@ -8,8 +8,7 @@ import * as ts from 'typescript'; -import {ClassMember, ClassMemberKind, CtorParameter, Decorator, Import} from '../../../ngtsc/host'; -import {TypeScriptReflectionHost, reflectObjectLiteral} from '../../../ngtsc/metadata'; +import {ClassMember, ClassMemberKind, CtorParameter, Decorator, Import, TypeScriptReflectionHost, reflectObjectLiteral} from '../../../ngtsc/reflection'; import {BundleProgram} from '../packages/bundle_program'; import {findAll, getNameText, isDefined} from '../utils'; diff --git a/packages/compiler-cli/src/ngcc/src/host/esm5_host.ts b/packages/compiler-cli/src/ngcc/src/host/esm5_host.ts index 8eb0837607..9482e7730e 100644 --- a/packages/compiler-cli/src/ngcc/src/host/esm5_host.ts +++ b/packages/compiler-cli/src/ngcc/src/host/esm5_host.ts @@ -8,8 +8,7 @@ import * as ts from 'typescript'; -import {ClassMember, ClassMemberKind, Decorator, FunctionDefinition, Parameter} from '../../../ngtsc/host'; -import {reflectObjectLiteral} from '../../../ngtsc/metadata'; +import {ClassMember, ClassMemberKind, Decorator, FunctionDefinition, Parameter, reflectObjectLiteral} from '../../../ngtsc/reflection'; import {getNameText} from '../utils'; import {Esm2015ReflectionHost, ParamInfo, getPropertyValueFromSymbol, isAssignmentStatement} from './esm2015_host'; diff --git a/packages/compiler-cli/src/ngcc/src/host/ngcc_host.ts b/packages/compiler-cli/src/ngcc/src/host/ngcc_host.ts index 1dc7ae8759..38076c9d5e 100644 --- a/packages/compiler-cli/src/ngcc/src/host/ngcc_host.ts +++ b/packages/compiler-cli/src/ngcc/src/host/ngcc_host.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; -import {ReflectionHost} from '../../../ngtsc/host'; +import {ReflectionHost} from '../../../ngtsc/reflection'; import {DecoratedClass} from './decorated_class'; export const PRE_R3_MARKER = '__PRE_R3__'; diff --git a/packages/compiler-cli/src/ngcc/src/rendering/renderer.ts b/packages/compiler-cli/src/ngcc/src/rendering/renderer.ts index f88c6775bf..b6bc54b911 100644 --- a/packages/compiler-cli/src/ngcc/src/rendering/renderer.ts +++ b/packages/compiler-cli/src/ngcc/src/rendering/renderer.ts @@ -13,7 +13,6 @@ import {basename, dirname, relative, resolve} from 'canonical-path'; import {SourceMapConsumer, SourceMapGenerator, RawSourceMap} from 'source-map'; import * as ts from 'typescript'; -import {Decorator} from '../../../ngtsc/host'; import {CompileResult} from '@angular/compiler-cli/src/ngtsc/transform'; import {translateStatement, translateType, ImportManager} from '../../../ngtsc/translator'; import {NgccImportManager} from './ngcc_import_manager'; diff --git a/packages/compiler-cli/src/ngcc/test/BUILD.bazel b/packages/compiler-cli/src/ngcc/test/BUILD.bazel index 826a437aed..72ccc7d222 100644 --- a/packages/compiler-cli/src/ngcc/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngcc/test/BUILD.bazel @@ -10,8 +10,9 @@ ts_library( ]), deps = [ "//packages/compiler-cli/src/ngcc", - "//packages/compiler-cli/src/ngtsc/host", - "//packages/compiler-cli/src/ngtsc/metadata", + "//packages/compiler-cli/src/ngtsc/imports", + "//packages/compiler-cli/src/ngtsc/partial_evaluator", + "//packages/compiler-cli/src/ngtsc/reflection", "//packages/compiler-cli/src/ngtsc/testing", "//packages/compiler-cli/src/ngtsc/transform", "@ngdeps//@types/convert-source-map", diff --git a/packages/compiler-cli/src/ngcc/test/analysis/decoration_analyzer_spec.ts b/packages/compiler-cli/src/ngcc/test/analysis/decoration_analyzer_spec.ts index 1978ba02c8..56ec22c88c 100644 --- a/packages/compiler-cli/src/ngcc/test/analysis/decoration_analyzer_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/analysis/decoration_analyzer_spec.ts @@ -7,7 +7,7 @@ */ import * as ts from 'typescript'; -import {Decorator} from '../../../ngtsc/host'; +import {Decorator} from '../../../ngtsc/reflection'; import {DecoratorHandler} from '../../../ngtsc/transform'; import {DecorationAnalyses, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; diff --git a/packages/compiler-cli/src/ngcc/test/analysis/private_declarations_analyzer_spec.ts b/packages/compiler-cli/src/ngcc/test/analysis/private_declarations_analyzer_spec.ts index 9188a5344b..36b72f93d5 100644 --- a/packages/compiler-cli/src/ngcc/test/analysis/private_declarations_analyzer_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/analysis/private_declarations_analyzer_spec.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {ResolvedReference} from '@angular/compiler-cli/src/ngtsc/metadata'; import * as ts from 'typescript'; +import {ResolvedReference} from '../../../ngtsc/imports'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; import {PrivateDeclarationsAnalyzer} from '../../src/analysis/private_declarations_analyzer'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; diff --git a/packages/compiler-cli/src/ngcc/test/analysis/references_registry_spec.ts b/packages/compiler-cli/src/ngcc/test/analysis/references_registry_spec.ts index b2f9ce27aa..ffb6a46325 100644 --- a/packages/compiler-cli/src/ngcc/test/analysis/references_registry_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/analysis/references_registry_spec.ts @@ -8,7 +8,9 @@ import * as ts from 'typescript'; -import {Reference, TypeScriptReflectionHost, staticallyResolve} from '../../../ngtsc/metadata'; +import {Reference} from '../../../ngtsc/imports'; +import {PartialEvaluator} from '../../../ngtsc/partial_evaluator'; +import {TypeScriptReflectionHost} from '../../../ngtsc/reflection'; import {getDeclaration, makeProgram} from '../../../ngtsc/testing/in_memory_typescript'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; @@ -37,10 +39,10 @@ describe('NgccReferencesRegistry', () => { const testArrayExpression = testArrayDeclaration.initializer !; const host = new TypeScriptReflectionHost(checker); + const evaluator = new PartialEvaluator(host, checker); const registry = new NgccReferencesRegistry(host); - const references = - staticallyResolve(testArrayExpression, host, checker) as Reference[]; + const references = evaluator.evaluate(testArrayExpression) as Reference[]; registry.add(...references); const map = registry.getDeclarationMap(); diff --git a/packages/compiler-cli/src/ngcc/test/host/esm2015_host_import_helper_spec.ts b/packages/compiler-cli/src/ngcc/test/host/esm2015_host_import_helper_spec.ts index 9440289e86..c3d09c225c 100644 --- a/packages/compiler-cli/src/ngcc/test/host/esm2015_host_import_helper_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/host/esm2015_host_import_helper_spec.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {ClassMemberKind, Import} from '../../../ngtsc/host'; +import {ClassMemberKind, Import} from '../../../ngtsc/reflection'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {convertToDirectTsLibImport, getDeclaration, makeTestProgram} from '../helpers/utils'; diff --git a/packages/compiler-cli/src/ngcc/test/host/esm2015_host_spec.ts b/packages/compiler-cli/src/ngcc/test/host/esm2015_host_spec.ts index 5c40e9f44c..a68191af74 100644 --- a/packages/compiler-cli/src/ngcc/test/host/esm2015_host_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/host/esm2015_host_spec.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {ClassMemberKind, Import} from '../../../ngtsc/host'; +import {ClassMemberKind, Import} from '../../../ngtsc/reflection'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {getDeclaration, makeTestBundleProgram, makeTestProgram} from '../helpers/utils'; diff --git a/packages/compiler-cli/src/ngcc/test/host/esm5_host_import_helper_spec.ts b/packages/compiler-cli/src/ngcc/test/host/esm5_host_import_helper_spec.ts index a9d4928ef3..4fca679d42 100644 --- a/packages/compiler-cli/src/ngcc/test/host/esm5_host_import_helper_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/host/esm5_host_import_helper_spec.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {ClassMemberKind, Import} from '../../../ngtsc/host'; +import {ClassMemberKind, Import} from '../../../ngtsc/reflection'; import {Esm5ReflectionHost} from '../../src/host/esm5_host'; import {convertToDirectTsLibImport, getDeclaration, makeTestProgram} from '../helpers/utils'; diff --git a/packages/compiler-cli/src/ngcc/test/host/esm5_host_spec.ts b/packages/compiler-cli/src/ngcc/test/host/esm5_host_spec.ts index 4fe4b82447..7889ae74d3 100644 --- a/packages/compiler-cli/src/ngcc/test/host/esm5_host_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/host/esm5_host_spec.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {ClassMemberKind, Import} from '../../../ngtsc/host'; +import {ClassMemberKind, Import} from '../../../ngtsc/reflection'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {Esm5ReflectionHost} from '../../src/host/esm5_host'; import {getDeclaration, makeTestProgram} from '../helpers/utils'; diff --git a/packages/compiler-cli/src/ngtsc/annotations/BUILD.bazel b/packages/compiler-cli/src/ngtsc/annotations/BUILD.bazel index e86b8e6181..dd014a1670 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/annotations/BUILD.bazel @@ -12,8 +12,9 @@ ts_library( deps = [ "//packages/compiler", "//packages/compiler-cli/src/ngtsc/diagnostics", - "//packages/compiler-cli/src/ngtsc/host", - "//packages/compiler-cli/src/ngtsc/metadata", + "//packages/compiler-cli/src/ngtsc/imports", + "//packages/compiler-cli/src/ngtsc/partial_evaluator", + "//packages/compiler-cli/src/ngtsc/reflection", "//packages/compiler-cli/src/ngtsc/transform", "//packages/compiler-cli/src/ngtsc/typecheck", "@ngdeps//@types/node", diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/base_def.ts b/packages/compiler-cli/src/ngtsc/annotations/src/base_def.ts index 5924bde1e2..47c64bdb61 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/base_def.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/base_def.ts @@ -9,8 +9,8 @@ import {R3BaseRefMetaData, compileBaseDefFromMetadata} from '@angular/compiler'; import * as ts from 'typescript'; -import {ClassMember, Decorator, ReflectionHost} from '../../host'; -import {staticallyResolve} from '../../metadata'; +import {PartialEvaluator} from '../../partial_evaluator'; +import {ClassMember, Decorator, ReflectionHost} from '../../reflection'; import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform'; import {isAngularCore} from './util'; @@ -26,7 +26,7 @@ function containsNgTopLevelDecorator(decorators: Decorator[] | null): boolean { export class BaseDefDecoratorHandler implements DecoratorHandler { - constructor(private checker: ts.TypeChecker, private reflector: ReflectionHost, ) {} + constructor(private reflector: ReflectionHost, private evaluator: PartialEvaluator) {} detect(node: ts.ClassDeclaration, decorators: Decorator[]|null): R3BaseRefDecoratorDetection |undefined { @@ -69,7 +69,7 @@ export class BaseDefDecoratorHandler implements const args = decorator.args; let value: string|[string, string]; if (args && args.length > 0) { - const resolvedValue = staticallyResolve(args[0], this.reflector, this.checker); + const resolvedValue = this.evaluator.evaluate(args[0]); if (typeof resolvedValue !== 'string') { throw new TypeError('Input alias does not resolve to a string value'); } @@ -88,7 +88,7 @@ export class BaseDefDecoratorHandler implements const args = decorator.args; let value: string; if (args && args.length > 0) { - const resolvedValue = staticallyResolve(args[0], this.reflector, this.checker); + const resolvedValue = this.evaluator.evaluate(args[0]); if (typeof resolvedValue !== 'string') { throw new TypeError('Output alias does not resolve to a string value'); } diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts index 8631e89645..8d2f05ddc1 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts @@ -11,8 +11,9 @@ import * as path from 'path'; import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; -import {Decorator, ReflectionHost} from '../../host'; -import {AbsoluteReference, Reference, ResolvedReference, filterToMembersWithDecorator, reflectObjectLiteral, staticallyResolve} from '../../metadata'; +import {ResolvedReference} from '../../imports'; +import {PartialEvaluator} from '../../partial_evaluator'; +import {Decorator, ReflectionHost, filterToMembersWithDecorator, reflectObjectLiteral} from '../../reflection'; import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform'; import {TypeCheckContext, TypeCheckableDirectiveMeta} from '../../typecheck'; @@ -37,7 +38,7 @@ export interface ComponentHandlerData { export class ComponentDecoratorHandler implements DecoratorHandler { constructor( - private checker: ts.TypeChecker, private reflector: ReflectionHost, + private reflector: ReflectionHost, private evaluator: PartialEvaluator, private scopeRegistry: SelectorScopeRegistry, private isCore: boolean, private resourceLoader: ResourceLoader, private rootDirs: string[], private defaultPreserveWhitespaces: boolean, private i18nUseExternalIds: boolean) {} @@ -62,7 +63,7 @@ export class ComponentDecoratorHandler implements if (this.resourceLoader.preload !== undefined && component.has('templateUrl')) { const templateUrlExpr = component.get('templateUrl') !; - const templateUrl = staticallyResolve(templateUrlExpr, this.reflector, this.checker); + const templateUrl = this.evaluator.evaluate(templateUrlExpr); if (typeof templateUrl !== 'string') { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, templateUrlExpr, 'templateUrl must be a string'); @@ -97,7 +98,7 @@ export class ComponentDecoratorHandler implements // @Component inherits @Directive, so begin by extracting the @Directive metadata and building // on it. const directiveResult = extractDirectiveMetadata( - node, decorator, this.checker, this.reflector, this.isCore, + node, decorator, this.reflector, this.evaluator, this.isCore, this.elementSchemaRegistry.getDefaultComponentElementName()); if (directiveResult === undefined) { // `extractDirectiveMetadata` returns undefined when the @Directive has `jit: true`. In this @@ -112,7 +113,7 @@ export class ComponentDecoratorHandler implements let templateStr: string|null = null; if (component.has('templateUrl')) { const templateUrlExpr = component.get('templateUrl') !; - const templateUrl = staticallyResolve(templateUrlExpr, this.reflector, this.checker); + const templateUrl = this.evaluator.evaluate(templateUrlExpr); if (typeof templateUrl !== 'string') { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, templateUrlExpr, 'templateUrl must be a string'); @@ -120,7 +121,7 @@ export class ComponentDecoratorHandler implements templateStr = this.resourceLoader.load(templateUrl, containingFile); } else if (component.has('template')) { const templateExpr = component.get('template') !; - const resolvedTemplate = staticallyResolve(templateExpr, this.reflector, this.checker); + const resolvedTemplate = this.evaluator.evaluate(templateExpr); if (typeof resolvedTemplate !== 'string') { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, templateExpr, 'template must be a string'); @@ -134,7 +135,7 @@ export class ComponentDecoratorHandler implements let preserveWhitespaces: boolean = this.defaultPreserveWhitespaces; if (component.has('preserveWhitespaces')) { const expr = component.get('preserveWhitespaces') !; - const value = staticallyResolve(expr, this.reflector, this.checker); + const value = this.evaluator.evaluate(expr); if (typeof value !== 'boolean') { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, expr, 'preserveWhitespaces must be a boolean'); @@ -161,7 +162,7 @@ export class ComponentDecoratorHandler implements let interpolation: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG; if (component.has('interpolation')) { const expr = component.get('interpolation') !; - const value = staticallyResolve(expr, this.reflector, this.checker); + const value = this.evaluator.evaluate(expr); if (!Array.isArray(value) || value.length !== 2 || !value.every(element => typeof element === 'string')) { throw new FatalDiagnosticError( @@ -200,21 +201,21 @@ export class ComponentDecoratorHandler implements const coreModule = this.isCore ? undefined : '@angular/core'; const viewChildFromFields = queriesFromFields( filterToMembersWithDecorator(decoratedElements, 'ViewChild', coreModule), this.reflector, - this.checker); + this.evaluator); const viewChildrenFromFields = queriesFromFields( filterToMembersWithDecorator(decoratedElements, 'ViewChildren', coreModule), this.reflector, - this.checker); + this.evaluator); const viewQueries = [...viewChildFromFields, ...viewChildrenFromFields]; if (component.has('queries')) { const queriesFromDecorator = extractQueriesFromDecorator( - component.get('queries') !, this.reflector, this.checker, this.isCore); + component.get('queries') !, this.reflector, this.evaluator, this.isCore); viewQueries.push(...queriesFromDecorator.view); } let styles: string[]|null = null; if (component.has('styles')) { - styles = parseFieldArrayValue(component, 'styles', this.reflector, this.checker); + styles = parseFieldArrayValue(component, 'styles', this.evaluator); } let styleUrls = this._extractStyleUrls(component); @@ -227,8 +228,7 @@ export class ComponentDecoratorHandler implements let encapsulation: number = 0; if (component.has('encapsulation')) { - encapsulation = parseInt(staticallyResolve( - component.get('encapsulation') !, this.reflector, this.checker) as string); + encapsulation = parseInt(this.evaluator.evaluate(component.get('encapsulation') !) as string); } let animations: Expression|null = null; @@ -333,7 +333,7 @@ export class ComponentDecoratorHandler implements } const styleUrlsExpr = component.get('styleUrls') !; - const styleUrls = staticallyResolve(styleUrlsExpr, this.reflector, this.checker); + const styleUrls = this.evaluator.evaluate(styleUrlsExpr); if (!Array.isArray(styleUrls) || !styleUrls.every(url => typeof url === 'string')) { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, styleUrlsExpr, 'styleUrls must be an array of strings'); diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts index e83a36c7b8..a581461bd7 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts @@ -10,8 +10,9 @@ import {ConstantPool, Expression, R3DirectiveMetadata, R3QueryMetadata, Statemen import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; -import {ClassMember, ClassMemberKind, Decorator, Import, ReflectionHost} from '../../host'; -import {Reference, ResolvedReference, filterToMembersWithDecorator, reflectObjectLiteral, staticallyResolve} from '../../metadata'; +import {Reference, ResolvedReference} from '../../imports'; +import {PartialEvaluator} from '../../partial_evaluator'; +import {ClassMember, ClassMemberKind, Decorator, ReflectionHost, filterToMembersWithDecorator, reflectObjectLiteral} from '../../reflection'; import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform'; import {generateSetClassMetadataCall} from './metadata'; @@ -27,7 +28,7 @@ export interface DirectiveHandlerData { export class DirectiveDecoratorHandler implements DecoratorHandler { constructor( - private checker: ts.TypeChecker, private reflector: ReflectionHost, + private reflector: ReflectionHost, private evaluator: PartialEvaluator, private scopeRegistry: SelectorScopeRegistry, private isCore: boolean) {} detect(node: ts.Declaration, decorators: Decorator[]|null): Decorator|undefined { @@ -40,7 +41,7 @@ export class DirectiveDecoratorHandler implements analyze(node: ts.ClassDeclaration, decorator: Decorator): AnalysisOutput { const directiveResult = - extractDirectiveMetadata(node, decorator, this.checker, this.reflector, this.isCore); + extractDirectiveMetadata(node, decorator, this.reflector, this.evaluator, this.isCore); const analysis = directiveResult && directiveResult.metadata; // If the directive has a selector, it should be registered with the `SelectorScopeRegistry` so @@ -92,8 +93,8 @@ export class DirectiveDecoratorHandler implements * Helper function to extract metadata from a `Directive` or `Component`. */ export function extractDirectiveMetadata( - clazz: ts.ClassDeclaration, decorator: Decorator, checker: ts.TypeChecker, - reflector: ReflectionHost, isCore: boolean, defaultSelector: string | null = null): { + clazz: ts.ClassDeclaration, decorator: Decorator, reflector: ReflectionHost, + evaluator: PartialEvaluator, isCore: boolean, defaultSelector: string | null = null): { decorator: Map, metadata: R3DirectiveMetadata, decoratedElements: ClassMember[], @@ -127,29 +128,29 @@ export function extractDirectiveMetadata( // Construct the map of inputs both from the @Directive/@Component // decorator, and the decorated // fields. - const inputsFromMeta = parseFieldToPropertyMapping(directive, 'inputs', reflector, checker); + const inputsFromMeta = parseFieldToPropertyMapping(directive, 'inputs', evaluator); const inputsFromFields = parseDecoratedFields( - filterToMembersWithDecorator(decoratedElements, 'Input', coreModule), reflector, checker, + filterToMembersWithDecorator(decoratedElements, 'Input', coreModule), evaluator, resolveInput); // And outputs. - const outputsFromMeta = parseFieldToPropertyMapping(directive, 'outputs', reflector, checker); + const outputsFromMeta = parseFieldToPropertyMapping(directive, 'outputs', evaluator); const outputsFromFields = parseDecoratedFields( - filterToMembersWithDecorator(decoratedElements, 'Output', coreModule), reflector, checker, + filterToMembersWithDecorator(decoratedElements, 'Output', coreModule), evaluator, resolveOutput) as{[field: string]: string}; // Construct the list of queries. const contentChildFromFields = queriesFromFields( filterToMembersWithDecorator(decoratedElements, 'ContentChild', coreModule), reflector, - checker); + evaluator); const contentChildrenFromFields = queriesFromFields( filterToMembersWithDecorator(decoratedElements, 'ContentChildren', coreModule), reflector, - checker); + evaluator); const queries = [...contentChildFromFields, ...contentChildrenFromFields]; if (directive.has('queries')) { const queriesFromDecorator = - extractQueriesFromDecorator(directive.get('queries') !, reflector, checker, isCore); + extractQueriesFromDecorator(directive.get('queries') !, reflector, evaluator, isCore); queries.push(...queriesFromDecorator.content); } @@ -157,7 +158,7 @@ export function extractDirectiveMetadata( let selector = defaultSelector; if (directive.has('selector')) { const expr = directive.get('selector') !; - const resolved = staticallyResolve(expr, reflector, checker); + const resolved = evaluator.evaluate(expr); if (typeof resolved !== 'string') { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `selector must be a string`); @@ -165,7 +166,7 @@ export function extractDirectiveMetadata( selector = resolved; } - const host = extractHostBindings(directive, decoratedElements, reflector, checker, coreModule); + const host = extractHostBindings(directive, decoratedElements, evaluator, coreModule); const providers: Expression|null = directive.has('providers') ? new WrappedNodeExpr(directive.get('providers') !) : null; @@ -179,7 +180,7 @@ export function extractDirectiveMetadata( let exportAs: string|null = null; if (directive.has('exportAs')) { const expr = directive.get('exportAs') !; - const resolved = staticallyResolve(expr, reflector, checker); + const resolved = evaluator.evaluate(expr); if (typeof resolved !== 'string') { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `exportAs must be a string`); @@ -207,14 +208,14 @@ export function extractDirectiveMetadata( export function extractQueryMetadata( exprNode: ts.Node, name: string, args: ReadonlyArray, propertyName: string, - reflector: ReflectionHost, checker: ts.TypeChecker): R3QueryMetadata { + reflector: ReflectionHost, evaluator: PartialEvaluator): R3QueryMetadata { if (args.length === 0) { throw new FatalDiagnosticError( ErrorCode.DECORATOR_ARITY_WRONG, exprNode, `@${name} must have arguments`); } const first = name === 'ViewChild' || name === 'ContentChild'; const node = unwrapForwardRef(args[0], reflector); - const arg = staticallyResolve(node, reflector, checker); + const arg = evaluator.evaluate(node); // Extract the predicate let predicate: Expression|string[]|null = null; @@ -244,7 +245,7 @@ export function extractQueryMetadata( } if (options.has('descendants')) { - const descendantsValue = staticallyResolve(options.get('descendants') !, reflector, checker); + const descendantsValue = evaluator.evaluate(options.get('descendants') !); if (typeof descendantsValue !== 'boolean') { throw new Error(`@${name} options.descendants must be a boolean`); } @@ -261,7 +262,7 @@ export function extractQueryMetadata( } export function extractQueriesFromDecorator( - queryData: ts.Expression, reflector: ReflectionHost, checker: ts.TypeChecker, + queryData: ts.Expression, reflector: ReflectionHost, evaluator: PartialEvaluator, isCore: boolean): { content: R3QueryMetadata[], view: R3QueryMetadata[], @@ -283,7 +284,7 @@ export function extractQueriesFromDecorator( } const query = extractQueryMetadata( - queryExpr, type.name, queryExpr.arguments || [], propertyName, reflector, checker); + queryExpr, type.name, queryExpr.arguments || [], propertyName, reflector, evaluator); if (type.name.startsWith('Content')) { content.push(query); } else { @@ -307,14 +308,14 @@ function isStringArrayOrDie(value: any, name: string): value is string[] { } export function parseFieldArrayValue( - directive: Map, field: string, reflector: ReflectionHost, - checker: ts.TypeChecker): null|string[] { + directive: Map, field: string, evaluator: PartialEvaluator): null| + string[] { if (!directive.has(field)) { return null; } // Resolve the field of interest from the directive metadata to a string[]. - const value = staticallyResolve(directive.get(field) !, reflector, checker); + const value = evaluator.evaluate(directive.get(field) !); if (!isStringArrayOrDie(value, field)) { throw new Error(`Failed to resolve @Directive.${field}`); } @@ -327,9 +328,9 @@ export function parseFieldArrayValue( * correctly shaped metadata object. */ function parseFieldToPropertyMapping( - directive: Map, field: string, reflector: ReflectionHost, - checker: ts.TypeChecker): {[field: string]: string} { - const metaValues = parseFieldArrayValue(directive, field, reflector, checker); + directive: Map, field: string, + evaluator: PartialEvaluator): {[field: string]: string} { + const metaValues = parseFieldArrayValue(directive, field, evaluator); if (!metaValues) { return EMPTY_OBJECT; } @@ -350,8 +351,7 @@ function parseFieldToPropertyMapping( * object. */ function parseDecoratedFields( - fields: {member: ClassMember, decorators: Decorator[]}[], reflector: ReflectionHost, - checker: ts.TypeChecker, + fields: {member: ClassMember, decorators: Decorator[]}[], evaluator: PartialEvaluator, mapValueResolver: (publicName: string, internalName: string) => string | [string, string]): {[field: string]: string | [string, string]} { return fields.reduce( @@ -363,7 +363,7 @@ function parseDecoratedFields( if (decorator.args == null || decorator.args.length === 0) { results[fieldName] = fieldName; } else if (decorator.args.length === 1) { - const property = staticallyResolve(decorator.args[0], reflector, checker); + const property = evaluator.evaluate(decorator.args[0]); if (typeof property !== 'string') { throw new Error(`Decorator argument must resolve to a string`); } @@ -389,7 +389,7 @@ function resolveOutput(publicName: string, internalName: string) { export function queriesFromFields( fields: {member: ClassMember, decorators: Decorator[]}[], reflector: ReflectionHost, - checker: ts.TypeChecker): R3QueryMetadata[] { + evaluator: PartialEvaluator): R3QueryMetadata[] { return fields.map(({member, decorators}) => { if (decorators.length !== 1) { throw new Error(`Cannot have multiple query decorators on the same class member`); @@ -398,7 +398,7 @@ export function queriesFromFields( } const decorator = decorators[0]; return extractQueryMetadata( - decorator.node, decorator.name, decorator.args || [], member.name, reflector, checker); + decorator.node, decorator.name, decorator.args || [], member.name, reflector, evaluator); }); } @@ -412,8 +412,8 @@ type StringMap = { }; function extractHostBindings( - metadata: Map, members: ClassMember[], reflector: ReflectionHost, - checker: ts.TypeChecker, coreModule: string | undefined): { + metadata: Map, members: ClassMember[], evaluator: PartialEvaluator, + coreModule: string | undefined): { attributes: StringMap, listeners: StringMap, properties: StringMap, @@ -421,7 +421,7 @@ function extractHostBindings( let hostMetadata: StringMap = {}; if (metadata.has('host')) { const expr = metadata.get('host') !; - const hostMetaMap = staticallyResolve(expr, reflector, checker); + const hostMetaMap = evaluator.evaluate(expr); if (!(hostMetaMap instanceof Map)) { throw new FatalDiagnosticError( ErrorCode.DECORATOR_ARG_NOT_LITERAL, expr, `Decorator host metadata must be an object`); @@ -445,7 +445,7 @@ function extractHostBindings( throw new Error(`@HostBinding() can have at most one argument`); } - const resolved = staticallyResolve(decorator.args[0], reflector, checker); + const resolved = evaluator.evaluate(decorator.args[0]); if (typeof resolved !== 'string') { throw new Error(`@HostBinding()'s argument must be a string`); } @@ -469,7 +469,7 @@ function extractHostBindings( `@HostListener() can have at most two arguments`); } - const resolved = staticallyResolve(decorator.args[0], reflector, checker); + const resolved = evaluator.evaluate(decorator.args[0]); if (typeof resolved !== 'string') { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, decorator.args[0], @@ -479,7 +479,7 @@ function extractHostBindings( eventName = resolved; if (decorator.args.length === 2) { - const resolvedArgs = staticallyResolve(decorator.args[1], reflector, checker); + const resolvedArgs = evaluator.evaluate(decorator.args[1]); if (!isStringArrayOrDie(resolvedArgs, '@HostListener.args')) { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, decorator.args[1], diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts b/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts index d779bd4f41..638523efa9 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts @@ -10,8 +10,7 @@ import {Expression, LiteralExpr, R3DependencyMetadata, R3InjectableMetadata, R3R import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; -import {Decorator, ReflectionHost} from '../../host'; -import {reflectObjectLiteral} from '../../metadata'; +import {Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection'; import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform'; import {generateSetClassMetadataCall} from './metadata'; diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/metadata.ts b/packages/compiler-cli/src/ngtsc/annotations/src/metadata.ts index 79d18220c4..dc8faa1673 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/metadata.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/metadata.ts @@ -9,7 +9,7 @@ import {ExternalExpr, Identifiers, InvokeFunctionExpr, Statement, WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; -import {CtorParameter, Decorator, ReflectionHost} from '../../host'; +import {CtorParameter, Decorator, ReflectionHost} from '../../reflection'; /** * Given a class declaration, generate a call to `setClassMetadata` with the Angular metadata diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts b/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts index 54cb3a65cb..9cdcdcc720 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts @@ -10,8 +10,9 @@ import {Expression, LiteralArrayExpr, R3InjectorMetadata, R3NgModuleMetadata, R3 import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; -import {Decorator, ReflectionHost} from '../../host'; -import {Reference, ResolvedReference, ResolvedValue, reflectObjectLiteral, staticallyResolve, typeNodeToValueExpr} from '../../metadata'; +import {Reference, ResolvedReference} from '../../imports'; +import {PartialEvaluator, ResolvedValue} from '../../partial_evaluator'; +import {Decorator, ReflectionHost, reflectObjectLiteral, typeNodeToValueExpr} from '../../reflection'; import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform'; import {generateSetClassMetadataCall} from './metadata'; @@ -32,7 +33,7 @@ export interface NgModuleAnalysis { */ export class NgModuleDecoratorHandler implements DecoratorHandler { constructor( - private checker: ts.TypeChecker, private reflector: ReflectionHost, + private reflector: ReflectionHost, private evaluator: PartialEvaluator, private scopeRegistry: SelectorScopeRegistry, private referencesRegistry: ReferencesRegistry, private isCore: boolean) {} @@ -72,32 +73,30 @@ export class NgModuleDecoratorHandler implements DecoratorHandler[] = []; if (ngModule.has('declarations')) { const expr = ngModule.get('declarations') !; - const declarationMeta = staticallyResolve(expr, this.reflector, this.checker); + const declarationMeta = this.evaluator.evaluate(expr); declarations = this.resolveTypeList(expr, declarationMeta, 'declarations'); this.referencesRegistry.add(...declarations); } let imports: Reference[] = []; if (ngModule.has('imports')) { const expr = ngModule.get('imports') !; - const importsMeta = staticallyResolve( - expr, this.reflector, this.checker, - ref => this._extractModuleFromModuleWithProvidersFn(ref.node)); + const importsMeta = this.evaluator.evaluate( + expr, ref => this._extractModuleFromModuleWithProvidersFn(ref.node)); imports = this.resolveTypeList(expr, importsMeta, 'imports'); this.referencesRegistry.add(...imports); } let exports: Reference[] = []; if (ngModule.has('exports')) { const expr = ngModule.get('exports') !; - const exportsMeta = staticallyResolve( - expr, this.reflector, this.checker, - ref => this._extractModuleFromModuleWithProvidersFn(ref.node)); + const exportsMeta = this.evaluator.evaluate( + expr, ref => this._extractModuleFromModuleWithProvidersFn(ref.node)); exports = this.resolveTypeList(expr, exportsMeta, 'exports'); this.referencesRegistry.add(...exports); } let bootstrap: Reference[] = []; if (ngModule.has('bootstrap')) { const expr = ngModule.get('bootstrap') !; - const bootstrapMeta = staticallyResolve(expr, this.reflector, this.checker); + const bootstrapMeta = this.evaluator.evaluate(expr); bootstrap = this.resolveTypeList(expr, bootstrapMeta, 'bootstrap'); this.referencesRegistry.add(...bootstrap); } diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts b/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts index 71a8109276..c8f5f25ad0 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts @@ -10,8 +10,8 @@ import {LiteralExpr, R3PipeMetadata, Statement, WrappedNodeExpr, compilePipeFrom import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; -import {Decorator, ReflectionHost} from '../../host'; -import {reflectObjectLiteral, staticallyResolve} from '../../metadata'; +import {PartialEvaluator} from '../../partial_evaluator'; +import {Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection'; import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform'; import {generateSetClassMetadataCall} from './metadata'; @@ -25,7 +25,7 @@ export interface PipeHandlerData { export class PipeDecoratorHandler implements DecoratorHandler { constructor( - private checker: ts.TypeChecker, private reflector: ReflectionHost, + private reflector: ReflectionHost, private evaluator: PartialEvaluator, private scopeRegistry: SelectorScopeRegistry, private isCore: boolean) {} detect(node: ts.Declaration, decorators: Decorator[]|null): Decorator|undefined { @@ -63,7 +63,7 @@ export class PipeDecoratorHandler implements DecoratorHandler { ]); const checker = program.getTypeChecker(); const host = new TypeScriptReflectionHost(checker); + const evaluator = new PartialEvaluator(host, checker); const handler = new ComponentDecoratorHandler( - checker, host, new SelectorScopeRegistry(checker, host), false, new NoopResourceLoader(), + host, evaluator, new SelectorScopeRegistry(checker, host), false, new NoopResourceLoader(), [''], false, true); const TestCmp = getDeclaration(program, 'entry.ts', 'TestCmp', ts.isClassDeclaration); const detected = handler.detect(TestCmp, host.getDecoratorsOfDeclaration(TestCmp)); diff --git a/packages/compiler-cli/src/ngtsc/annotations/test/metadata_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/test/metadata_spec.ts index 405e6ef6aa..be298b3a55 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/test/metadata_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/test/metadata_spec.ts @@ -6,12 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import {Statement} from '@angular/compiler'; import * as ts from 'typescript'; -import {TypeScriptReflectionHost} from '../../metadata'; +import {TypeScriptReflectionHost} from '../../reflection'; import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript'; import {ImportManager, translateStatement} from '../../translator'; + import {generateSetClassMetadataCall} from '../src/metadata'; const CORE = { diff --git a/packages/compiler-cli/src/ngtsc/annotations/test/selector_scope_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/test/selector_scope_spec.ts index b926dfba15..c3228f21f7 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/test/selector_scope_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/test/selector_scope_spec.ts @@ -8,10 +8,10 @@ import * as ts from 'typescript'; -import {TypeScriptReflectionHost} from '../../metadata'; -import {AbsoluteReference, ResolvedReference} from '../../metadata/src/resolver'; +import {AbsoluteReference, ResolvedReference} from '../../imports'; +import {TypeScriptReflectionHost} from '../../reflection'; import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript'; -import {NgModuleDecoratorHandler} from '../src/ng_module'; + import {SelectorScopeRegistry} from '../src/selector_scope'; describe('SelectorScopeRegistry', () => { diff --git a/packages/compiler-cli/src/ngtsc/imports/BUILD.bazel b/packages/compiler-cli/src/ngtsc/imports/BUILD.bazel new file mode 100644 index 0000000000..816a1f4f9f --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/imports/BUILD.bazel @@ -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", + ], +) diff --git a/packages/compiler-cli/src/ngtsc/host/index.ts b/packages/compiler-cli/src/ngtsc/imports/index.ts similarity index 65% rename from packages/compiler-cli/src/ngtsc/host/index.ts rename to packages/compiler-cli/src/ngtsc/imports/index.ts index 93a06d7a93..94db07ea1a 100644 --- a/packages/compiler-cli/src/ngtsc/host/index.ts +++ b/packages/compiler-cli/src/ngtsc/imports/index.ts @@ -6,4 +6,4 @@ * found in the LICENSE file at https://angular.io/license */ -export * from './src/reflection'; +export {AbsoluteReference, ImportMode, NodeReference, Reference, ResolvedReference} from './src/references'; diff --git a/packages/compiler-cli/src/ngtsc/imports/src/references.ts b/packages/compiler-cli/src/ngtsc/imports/src/references.ts new file mode 100644 index 0000000000..2be1cc4a03 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/imports/src/references.ts @@ -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 + */ + +/// + +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 { + 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 extends Reference { + 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 extends Reference { + 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 extends Reference { + 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; + } +} \ No newline at end of file diff --git a/packages/compiler-cli/src/ngtsc/metadata/index.ts b/packages/compiler-cli/src/ngtsc/metadata/index.ts deleted file mode 100644 index 8e8e7c852c..0000000000 --- a/packages/compiler-cli/src/ngtsc/metadata/index.ts +++ /dev/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 - */ - -/// - -export {TypeScriptReflectionHost, filterToMembersWithDecorator, findMember, reflectObjectLiteral, reflectTypeEntityToDeclaration, typeNodeToValueExpr} from './src/reflector'; -export {AbsoluteReference, EnumValue, ImportMode, Reference, ResolvedReference, ResolvedValue, isDynamicValue, staticallyResolve} from './src/resolver'; diff --git a/packages/compiler-cli/src/ngtsc/metadata/BUILD.bazel b/packages/compiler-cli/src/ngtsc/partial_evaluator/BUILD.bazel similarity index 63% rename from packages/compiler-cli/src/ngtsc/metadata/BUILD.bazel rename to packages/compiler-cli/src/ngtsc/partial_evaluator/BUILD.bazel index 530adc1b09..95c2478682 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/BUILD.bazel @@ -3,16 +3,17 @@ package(default_visibility = ["//visibility:public"]) load("//tools:defaults.bzl", "ts_library") ts_library( - name = "metadata", + name = "partial_evaluator", srcs = glob([ "index.ts", "src/*.ts", ]), - module_name = "@angular/compiler-cli/src/ngtsc/metadata", + module_name = "@angular/compiler-cli/src/ngtsc/partial_evaluator", deps = [ "//packages:types", "//packages/compiler", - "//packages/compiler-cli/src/ngtsc/host", + "//packages/compiler-cli/src/ngtsc/imports", + "//packages/compiler-cli/src/ngtsc/reflection", "//packages/compiler-cli/src/ngtsc/util", "@ngdeps//@types/node", "@ngdeps//typescript", diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/index.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/index.ts new file mode 100644 index 0000000000..2d32afc308 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/index.ts @@ -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'; diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/builtin.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/builtin.ts new file mode 100644 index 0000000000..758853946e --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/builtin.ts @@ -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; + } + } +} diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interface.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interface.ts new file mode 100644 index 0000000000..695f536765 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interface.ts @@ -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, 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(), foreignFunctionResolver, + }); + } +} diff --git a/packages/compiler-cli/src/ngtsc/metadata/src/resolver.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts similarity index 69% rename from packages/compiler-cli/src/ngtsc/metadata/src/resolver.ts rename to packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts index c323160fd9..4fb0fca483 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/src/resolver.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts @@ -6,97 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ -/** - * resolver.ts implements partial computation of expressions, resolving expressions to static - * values where possible and returning a `DynamicValue` signal when not. - */ - -import {Expression, ExternalExpr, ExternalReference, WrappedNodeExpr} from '@angular/compiler'; -import * as path from 'path'; import * as ts from 'typescript'; -import {ClassMemberKind, ReflectionHost} from '../../host'; +import {AbsoluteReference, NodeReference, Reference, ResolvedReference} from '../../imports'; +import {ReflectionHost} from '../../reflection'; -const TS_DTS_JS_EXTENSION = /(?:\.d)?\.ts$|\.js$/; +import {ArraySliceBuiltinFn} from './builtin'; +import {BuiltinFn, DYNAMIC_VALUE, EnumValue, ResolvedValue, ResolvedValueArray, ResolvedValueMap, isDynamicValue} from './result'; -/** - * Represents a value which cannot be determined statically. - * - * Use `isDynamicValue` to determine whether a `ResolvedValue` is a `DynamicValue`. - */ -export class DynamicValue { - /** - * This is needed so the "is DynamicValue" assertion of `isDynamicValue` actually has meaning. - * - * Otherwise, "is DynamicValue" is akin to "is {}" which doesn't trigger narrowing. - */ - private _isDynamic = true; -} - -/** - * An internal flyweight for `DynamicValue`. Eventually the dynamic value will carry information - * on the location of the node that could not be statically computed. - */ -const DYNAMIC_VALUE: DynamicValue = new DynamicValue(); - -/** - * Used to test whether a `ResolvedValue` is a `DynamicValue`. - */ -export function isDynamicValue(value: any): value is DynamicValue { - return value === DYNAMIC_VALUE; -} - -/** - * A value resulting from static resolution. - * - * This could be a primitive, collection type, reference to a `ts.Node` that declares a - * non-primitive value, or a special `DynamicValue` type which indicates the value was not - * available statically. - */ -export type ResolvedValue = number | boolean | string | null | undefined | Reference | EnumValue | - ResolvedValueArray | ResolvedValueMap | BuiltinFn | DynamicValue; - -/** - * An array of `ResolvedValue`s. - * - * This is a reified type to allow the circular reference of `ResolvedValue` -> `ResolvedValueArray` - * -> - * `ResolvedValue`. - */ -export interface ResolvedValueArray extends Array {} - -/** - * 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 {} - -/** - * 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, readonly name: string) {} -} - -/** - * An implementation of a builtin function, such as `Array.prototype.slice`. - */ -export abstract class BuiltinFn { abstract evaluate(args: ResolvedValueArray): ResolvedValue; } - -class ArraySliceBuiltinFn extends BuiltinFn { - constructor(private lhs: ResolvedValueArray) { super(); } - - evaluate(args: ResolvedValueArray): ResolvedValue { - if (args.length === 0) { - return this.lhs; - } else { - return DYNAMIC_VALUE; - } - } -} /** * Tracks the scope of a function body, which includes `ResolvedValue`s for the parameters of that @@ -104,164 +21,6 @@ class ArraySliceBuiltinFn extends BuiltinFn { */ type Scope = Map; -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 { - 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 extends Reference { - 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 extends Reference { - 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 extends Reference { - 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, args: ts.Expression[]) => - ts.Expression | null): ResolvedValue { - return new StaticInterpreter(host, checker).visit(node, { - absoluteModuleName: null, - scope: new Map(), foreignFunctionResolver, - }); -} - interface BinaryOperatorDef { literal: boolean; op: (a: any, b: any) => ResolvedValue; @@ -309,7 +68,7 @@ interface Context { args: ReadonlyArray): ts.Expression|null; } -class StaticInterpreter { +export class StaticInterpreter { constructor(private host: ReflectionHost, private checker: ts.TypeChecker) {} visit(node: ts.Expression, context: Context): ResolvedValue { diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/result.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/result.ts new file mode 100644 index 0000000000..219563aefd --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/result.ts @@ -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 {} + +/** + * 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 {} + +/** + * 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, readonly name: string) {} +} + +/** + * An implementation of a builtin function, such as `Array.prototype.slice`. + */ +export abstract class BuiltinFn { abstract evaluate(args: ResolvedValueArray): ResolvedValue; } diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/BUILD.bazel new file mode 100644 index 0000000000..c79c44c2cb --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/BUILD.bazel @@ -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", + ], +) diff --git a/packages/compiler-cli/src/ngtsc/metadata/test/resolver_spec.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts similarity index 90% rename from packages/compiler-cli/src/ngtsc/metadata/test/resolver_spec.ts rename to packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts index 8a4ed0a3fd..6f6f82cf2f 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/test/resolver_spec.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts @@ -9,9 +9,11 @@ import {WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; -import {TypeScriptReflectionHost} from '..'; +import {AbsoluteReference, Reference} from '../../imports'; +import {TypeScriptReflectionHost} from '../../reflection'; import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript'; -import {AbsoluteReference, EnumValue, Reference, ResolvedValue, staticallyResolve} from '../src/resolver'; +import {PartialEvaluator} from '../src/interface'; +import {EnumValue, ResolvedValue} from '../src/result'; function makeSimpleProgram(contents: string): ts.Program { return makeProgram([{name: 'entry.ts', contents}]).program; @@ -32,7 +34,8 @@ function makeExpression( function evaluate(code: string, expr: string): T { const {expression, checker} = makeExpression(code, expr); const host = new TypeScriptReflectionHost(checker); - return staticallyResolve(expression, host, checker) as T; + const evaluator = new PartialEvaluator(host, checker); + return evaluator.evaluate(expression) as T; } describe('ngtsc metadata', () => { @@ -55,8 +58,9 @@ describe('ngtsc metadata', () => { ]); const decl = getDeclaration(program, 'entry.ts', 'X', ts.isVariableDeclaration); const host = new TypeScriptReflectionHost(program.getTypeChecker()); + const evaluator = new PartialEvaluator(host, program.getTypeChecker()); - const value = staticallyResolve(decl.initializer !, host, program.getTypeChecker()); + const value = evaluator.evaluate(decl.initializer !); expect(value).toEqual('test'); }); @@ -142,7 +146,8 @@ describe('ngtsc metadata', () => { const host = new TypeScriptReflectionHost(checker); const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration); const expr = result.initializer !; - const resolved = staticallyResolve(expr, host, checker); + const evaluator = new PartialEvaluator(host, checker); + const resolved = evaluator.evaluate(expr); if (!(resolved instanceof Reference)) { return fail('Expected expression to resolve to a reference'); } @@ -173,7 +178,8 @@ describe('ngtsc metadata', () => { const host = new TypeScriptReflectionHost(checker); const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration); const expr = result.initializer !; - const resolved = staticallyResolve(expr, host, checker); + const evaluator = new PartialEvaluator(host, checker); + const resolved = evaluator.evaluate(expr); if (!(resolved instanceof AbsoluteReference)) { return fail('Expected expression to resolve to an absolute reference'); } @@ -205,7 +211,8 @@ describe('ngtsc metadata', () => { const host = new TypeScriptReflectionHost(checker); const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration); const expr = result.initializer !; - expect(staticallyResolve(expr, host, checker)).toEqual('test'); + const evaluator = new PartialEvaluator(host, checker); + expect(evaluator.evaluate(expr)).toEqual('test'); }); it('reads values from named exports', () => { @@ -223,7 +230,8 @@ describe('ngtsc metadata', () => { const host = new TypeScriptReflectionHost(checker); const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration); const expr = result.initializer !; - expect(staticallyResolve(expr, host, checker)).toEqual('test'); + const evaluator = new PartialEvaluator(host, checker); + expect(evaluator.evaluate(expr)).toEqual('test'); }); it('chain of re-exports works', () => { @@ -241,7 +249,8 @@ describe('ngtsc metadata', () => { const host = new TypeScriptReflectionHost(checker); const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration); const expr = result.initializer !; - expect(staticallyResolve(expr, host, checker)).toEqual('test'); + const evaluator = new PartialEvaluator(host, checker); + expect(evaluator.evaluate(expr)).toEqual('test'); }); it('map spread works', () => { @@ -297,7 +306,8 @@ describe('ngtsc metadata', () => { const checker = program.getTypeChecker(); const host = new TypeScriptReflectionHost(checker); const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration); - const res = staticallyResolve(result.initializer !, host, checker); + const evaluator = new PartialEvaluator(host, checker); + const res = evaluator.evaluate(result.initializer !); expect(res instanceof Reference).toBe(true); }); }); diff --git a/packages/compiler-cli/src/ngtsc/program.ts b/packages/compiler-cli/src/ngtsc/program.ts index f6e7c95816..1cb8599b32 100644 --- a/packages/compiler-cli/src/ngtsc/program.ts +++ b/packages/compiler-cli/src/ngtsc/program.ts @@ -7,7 +7,6 @@ */ import {GeneratedFile} from '@angular/compiler'; -import * as path from 'path'; import * as ts from 'typescript'; import * as api from '../transformers/api'; @@ -16,7 +15,8 @@ import {nocollapseHack} from '../transformers/nocollapse_hack'; import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, NoopReferencesRegistry, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from './annotations'; import {BaseDefDecoratorHandler} from './annotations/src/base_def'; import {FlatIndexGenerator} from './entry_point'; -import {TypeScriptReflectionHost} from './metadata'; +import {PartialEvaluator} from './partial_evaluator'; +import {TypeScriptReflectionHost} from './reflection'; import {FileResourceLoader, HostResourceLoader} from './resource_loader'; import {FactoryGenerator, FactoryInfo, GeneratedShimsHostWrapper, ShimGenerator, SummaryGenerator, generatedFactoryTransform} from './shims'; import {ivySwitchTransform} from './switch'; @@ -251,20 +251,21 @@ export class NgtscProgram implements api.Program { private makeCompilation(): IvyCompilation { const checker = this.tsProgram.getTypeChecker(); + const evaluator = new PartialEvaluator(this.reflector, checker); const scopeRegistry = new SelectorScopeRegistry(checker, this.reflector); const referencesRegistry = new NoopReferencesRegistry(); // Set up the IvyCompilation, which manages state for the Ivy transformer. const handlers = [ - new BaseDefDecoratorHandler(checker, this.reflector), + new BaseDefDecoratorHandler(this.reflector, evaluator), new ComponentDecoratorHandler( - checker, this.reflector, scopeRegistry, this.isCore, this.resourceLoader, this.rootDirs, + this.reflector, evaluator, scopeRegistry, this.isCore, this.resourceLoader, this.rootDirs, this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false), - new DirectiveDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore), + new DirectiveDecoratorHandler(this.reflector, evaluator, scopeRegistry, this.isCore), new InjectableDecoratorHandler(this.reflector, this.isCore), new NgModuleDecoratorHandler( - checker, this.reflector, scopeRegistry, referencesRegistry, this.isCore), - new PipeDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore), + this.reflector, evaluator, scopeRegistry, referencesRegistry, this.isCore), + new PipeDecoratorHandler(this.reflector, evaluator, scopeRegistry, this.isCore), ]; return new IvyCompilation( diff --git a/packages/compiler-cli/src/ngtsc/host/BUILD.bazel b/packages/compiler-cli/src/ngtsc/reflection/BUILD.bazel similarity index 71% rename from packages/compiler-cli/src/ngtsc/host/BUILD.bazel rename to packages/compiler-cli/src/ngtsc/reflection/BUILD.bazel index b0cfa74ad6..440d3398e0 100644 --- a/packages/compiler-cli/src/ngtsc/host/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/reflection/BUILD.bazel @@ -3,11 +3,11 @@ package(default_visibility = ["//visibility:public"]) load("//tools:defaults.bzl", "ts_library") ts_library( - name = "host", + name = "reflection", srcs = glob([ "index.ts", "src/**/*.ts", ]), - module_name = "@angular/compiler-cli/src/ngtsc/host", + module_name = "@angular/compiler-cli/src/ngtsc/reflection", deps = ["@ngdeps//typescript"], ) diff --git a/packages/compiler-cli/src/ngtsc/reflection/index.ts b/packages/compiler-cli/src/ngtsc/reflection/index.ts new file mode 100644 index 0000000000..d5615ed5ac --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/reflection/index.ts @@ -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'; \ No newline at end of file diff --git a/packages/compiler-cli/src/ngtsc/host/src/reflection.ts b/packages/compiler-cli/src/ngtsc/reflection/src/host.ts similarity index 100% rename from packages/compiler-cli/src/ngtsc/host/src/reflection.ts rename to packages/compiler-cli/src/ngtsc/reflection/src/host.ts diff --git a/packages/compiler-cli/src/ngtsc/metadata/src/reflector.ts b/packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts similarity index 99% rename from packages/compiler-cli/src/ngtsc/metadata/src/reflector.ts rename to packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts index 2211a54a2a..460a1e3eea 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/src/reflector.ts +++ b/packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {ClassMember, ClassMemberKind, CtorParameter, Declaration, Decorator, FunctionDefinition, Import, ReflectionHost} from '../../host'; +import {ClassMember, ClassMemberKind, CtorParameter, Declaration, Decorator, FunctionDefinition, Import, ReflectionHost} from './host'; /** * reflector.ts implements static reflection of declarations using the TypeScript `ts.TypeChecker`. diff --git a/packages/compiler-cli/src/ngtsc/metadata/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/reflection/test/BUILD.bazel similarity index 80% rename from packages/compiler-cli/src/ngtsc/metadata/test/BUILD.bazel rename to packages/compiler-cli/src/ngtsc/reflection/test/BUILD.bazel index 7fd3b12092..c9301bc16d 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/reflection/test/BUILD.bazel @@ -10,9 +10,7 @@ ts_library( ]), deps = [ "//packages:types", - "//packages/compiler", - "//packages/compiler-cli/src/ngtsc/host", - "//packages/compiler-cli/src/ngtsc/metadata", + "//packages/compiler-cli/src/ngtsc/reflection", "//packages/compiler-cli/src/ngtsc/testing", "@ngdeps//typescript", ], diff --git a/packages/compiler-cli/src/ngtsc/metadata/test/reflector_spec.ts b/packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts similarity index 98% rename from packages/compiler-cli/src/ngtsc/metadata/test/reflector_spec.ts rename to packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts index d8d2c3c2e9..e9e596b434 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/test/reflector_spec.ts +++ b/packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts @@ -8,9 +8,9 @@ import * as ts from 'typescript'; -import {CtorParameter} from '../../host'; import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript'; -import {TypeScriptReflectionHost} from '../src/reflector'; +import {CtorParameter} from '../src/host'; +import {TypeScriptReflectionHost} from '../src/typescript'; describe('reflector', () => { describe('ctor params', () => { diff --git a/packages/compiler-cli/src/ngtsc/shims/BUILD.bazel b/packages/compiler-cli/src/ngtsc/shims/BUILD.bazel index 68e66fb562..d936b34d9b 100644 --- a/packages/compiler-cli/src/ngtsc/shims/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/shims/BUILD.bazel @@ -11,8 +11,6 @@ ts_library( module_name = "@angular/compiler-cli/src/ngtsc/shims", deps = [ "//packages/compiler", - "//packages/compiler-cli/src/ngtsc/host", - "//packages/compiler-cli/src/ngtsc/metadata", "//packages/compiler-cli/src/ngtsc/util", "@ngdeps//@types/node", "@ngdeps//typescript", diff --git a/packages/compiler-cli/src/ngtsc/shims/src/host.ts b/packages/compiler-cli/src/ngtsc/shims/src/host.ts index 4bcf98e2f8..5dcf0af8dc 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/host.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/host.ts @@ -6,7 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -import * as path from 'path'; import * as ts from 'typescript'; export interface ShimGenerator { diff --git a/packages/compiler-cli/src/ngtsc/switch/BUILD.bazel b/packages/compiler-cli/src/ngtsc/switch/BUILD.bazel index 59b24432f9..d57955dcec 100644 --- a/packages/compiler-cli/src/ngtsc/switch/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/switch/BUILD.bazel @@ -11,9 +11,6 @@ ts_library( module_name = "@angular/compiler-cli/src/ngtsc/switch", deps = [ "//packages/compiler", - "//packages/compiler-cli/src/ngtsc/host", - "//packages/compiler-cli/src/ngtsc/metadata", - "//packages/compiler-cli/src/ngtsc/util", "@ngdeps//typescript", ], ) diff --git a/packages/compiler-cli/src/ngtsc/transform/BUILD.bazel b/packages/compiler-cli/src/ngtsc/transform/BUILD.bazel index 67a726fdbc..cece39c676 100644 --- a/packages/compiler-cli/src/ngtsc/transform/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/transform/BUILD.bazel @@ -12,8 +12,7 @@ ts_library( deps = [ "//packages/compiler", "//packages/compiler-cli/src/ngtsc/diagnostics", - "//packages/compiler-cli/src/ngtsc/host", - "//packages/compiler-cli/src/ngtsc/metadata", + "//packages/compiler-cli/src/ngtsc/reflection", "//packages/compiler-cli/src/ngtsc/translator", "//packages/compiler-cli/src/ngtsc/typecheck", "//packages/compiler-cli/src/ngtsc/util", diff --git a/packages/compiler-cli/src/ngtsc/transform/src/api.ts b/packages/compiler-cli/src/ngtsc/transform/src/api.ts index 59a3182350..6580e425ad 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/api.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/api.ts @@ -9,7 +9,7 @@ import {ConstantPool, Expression, Statement, Type} from '@angular/compiler'; import * as ts from 'typescript'; -import {Decorator} from '../../host'; +import {Decorator} from '../../reflection'; import {TypeCheckContext} from '../../typecheck'; diff --git a/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts b/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts index f42e828a43..06e075c4b7 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts @@ -10,8 +10,7 @@ import {ConstantPool} from '@angular/compiler'; import * as ts from 'typescript'; import {FatalDiagnosticError} from '../../diagnostics'; -import {Decorator, ReflectionHost} from '../../host'; -import {reflectNameOfDeclaration} from '../../metadata/src/reflector'; +import {Decorator, ReflectionHost, reflectNameOfDeclaration} from '../../reflection'; import {TypeCheckContext} from '../../typecheck'; import {AnalysisOutput, CompileResult, DecoratorHandler} from './api'; diff --git a/packages/compiler-cli/src/ngtsc/transform/src/transform.ts b/packages/compiler-cli/src/ngtsc/transform/src/transform.ts index 267eeff035..8eba7da50b 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/transform.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/transform.ts @@ -9,9 +9,8 @@ import {ConstantPool} from '@angular/compiler'; import * as ts from 'typescript'; -import {Decorator, ReflectionHost} from '../../host'; +import {Decorator, ReflectionHost} from '../../reflection'; import {ImportManager, translateExpression, translateStatement} from '../../translator'; -import {relativePathBetween} from '../../util/src/path'; import {VisitListEntryResult, Visitor, visit} from '../../util/src/visitor'; import {CompileResult} from './api'; diff --git a/packages/compiler-cli/src/ngtsc/typecheck/BUILD.bazel b/packages/compiler-cli/src/ngtsc/typecheck/BUILD.bazel index fd79b3cd3c..9b8dd51221 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/typecheck/BUILD.bazel @@ -9,7 +9,7 @@ ts_library( deps = [ "//packages:types", "//packages/compiler", - "//packages/compiler-cli/src/ngtsc/metadata", + "//packages/compiler-cli/src/ngtsc/imports", "//packages/compiler-cli/src/ngtsc/translator", "//packages/compiler-cli/src/ngtsc/util", "@ngdeps//typescript", diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/api.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/api.ts index 79ce553b37..b603836a05 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/api.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/api.ts @@ -9,7 +9,7 @@ import {BoundTarget, DirectiveMeta} from '@angular/compiler'; import * as ts from 'typescript'; -import {Reference} from '../../metadata'; +import {Reference} from '../../imports'; /** * Extension of `DirectiveMeta` that includes additional information required to type-check the diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts index c37d7a10e5..08d207f5ac 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts @@ -9,7 +9,7 @@ import {AST, BindingType, BoundTarget, ImplicitReceiver, PropertyRead, TmplAstBoundText, TmplAstElement, TmplAstNode, TmplAstTemplate, TmplAstVariable} from '@angular/compiler'; import * as ts from 'typescript'; -import {Reference} from '../../metadata'; +import {Reference} from '../../imports'; import {ImportManager, translateExpression} from '../../translator'; import {TypeCheckBlockMetadata, TypeCheckableDirectiveMeta} from './api'; diff --git a/packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel index 6de544a767..97da7159e6 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel @@ -10,8 +10,6 @@ ts_library( ]), deps = [ "//packages:types", - "//packages/compiler", - "//packages/compiler-cli/src/ngtsc/host", "//packages/compiler-cli/src/ngtsc/testing", "//packages/compiler-cli/src/ngtsc/typecheck", "@ngdeps//typescript",