refactor(compiler): move `findDeclaration` into the `StaticReflector`
Previously, this was part of the `AotCompilerHost`. The `AotCompilerHost` is now also greatly simplified.
This commit is contained in:
parent
912ca44979
commit
24099bdbd2
|
@ -6,9 +6,9 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export {StaticReflector, StaticReflectorHost, StaticSymbol} from '@angular/compiler';
|
export {AotCompilerHost, AotCompilerHost as StaticReflectorHost, StaticReflector, StaticSymbol} from '@angular/compiler';
|
||||||
export {CodeGenerator} from './src/codegen';
|
export {CodeGenerator} from './src/codegen';
|
||||||
export {Extractor} from './src/extractor';
|
export {Extractor} from './src/extractor';
|
||||||
export {NodeReflectorHostContext, ReflectorHost, ReflectorHostContext} from './src/reflector_host';
|
export {NgHost, NgHostContext, NodeNgHostContext} from './src/ng_host';
|
||||||
|
|
||||||
export * from '@angular/tsc-wrapped';
|
export * from '@angular/tsc-wrapped';
|
||||||
|
|
|
@ -17,9 +17,9 @@ import {readFileSync} from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {PathMappedReflectorHost} from './path_mapped_reflector_host';
|
import {NgHost, NgHostContext} from './ng_host';
|
||||||
|
import {PathMappedNgHost} from './path_mapped_ng_host';
|
||||||
import {Console} from './private_import_core';
|
import {Console} from './private_import_core';
|
||||||
import {ReflectorHost, ReflectorHostContext} from './reflector_host';
|
|
||||||
|
|
||||||
const GENERATED_FILES = /\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
|
const GENERATED_FILES = /\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
|
||||||
const GENERATED_OR_DTS_FILES = /\.d\.ts$|\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
|
const GENERATED_OR_DTS_FILES = /\.d\.ts$|\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
|
||||||
|
@ -37,8 +37,7 @@ export class CodeGenerator {
|
||||||
constructor(
|
constructor(
|
||||||
private options: AngularCompilerOptions, private program: ts.Program,
|
private options: AngularCompilerOptions, private program: ts.Program,
|
||||||
public host: ts.CompilerHost, private staticReflector: compiler.StaticReflector,
|
public host: ts.CompilerHost, private staticReflector: compiler.StaticReflector,
|
||||||
private compiler: compiler.AotCompiler, private reflectorHost: compiler.StaticReflectorHost) {
|
private compiler: compiler.AotCompiler, private ngHost: NgHost) {}
|
||||||
}
|
|
||||||
|
|
||||||
// Write codegen in a directory structure matching the sources.
|
// Write codegen in a directory structure matching the sources.
|
||||||
private calculateEmitPath(filePath: string): string {
|
private calculateEmitPath(filePath: string): string {
|
||||||
|
@ -65,7 +64,7 @@ export class CodeGenerator {
|
||||||
|
|
||||||
codegen(options: {transitiveModules: boolean}): Promise<any> {
|
codegen(options: {transitiveModules: boolean}): Promise<any> {
|
||||||
const staticSymbols =
|
const staticSymbols =
|
||||||
extractProgramSymbols(this.program, this.staticReflector, this.reflectorHost, this.options);
|
extractProgramSymbols(this.program, this.staticReflector, this.ngHost, this.options);
|
||||||
|
|
||||||
return this.compiler.compileModules(staticSymbols, options).then(generatedModules => {
|
return this.compiler.compileModules(staticSymbols, options).then(generatedModules => {
|
||||||
generatedModules.forEach(generatedModule => {
|
generatedModules.forEach(generatedModule => {
|
||||||
|
@ -79,8 +78,8 @@ export class CodeGenerator {
|
||||||
|
|
||||||
static create(
|
static create(
|
||||||
options: AngularCompilerOptions, cliOptions: NgcCliOptions, program: ts.Program,
|
options: AngularCompilerOptions, cliOptions: NgcCliOptions, program: ts.Program,
|
||||||
compilerHost: ts.CompilerHost, reflectorHostContext?: ReflectorHostContext,
|
compilerHost: ts.CompilerHost, ngHostContext?: NgHostContext,
|
||||||
resourceLoader?: compiler.ResourceLoader, reflectorHost?: ReflectorHost): CodeGenerator {
|
resourceLoader?: compiler.ResourceLoader, ngHost?: NgHost): CodeGenerator {
|
||||||
resourceLoader = resourceLoader || {
|
resourceLoader = resourceLoader || {
|
||||||
get: (s: string) => {
|
get: (s: string) => {
|
||||||
if (!compilerHost.fileExists(s)) {
|
if (!compilerHost.fileExists(s)) {
|
||||||
|
@ -102,13 +101,13 @@ export class CodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver();
|
const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver();
|
||||||
if (!reflectorHost) {
|
if (!ngHost) {
|
||||||
const usePathMapping = !!options.rootDirs && options.rootDirs.length > 0;
|
const usePathMapping = !!options.rootDirs && options.rootDirs.length > 0;
|
||||||
reflectorHost = usePathMapping ?
|
ngHost = usePathMapping ?
|
||||||
new PathMappedReflectorHost(program, compilerHost, options, reflectorHostContext) :
|
new PathMappedNgHost(program, compilerHost, options, ngHostContext) :
|
||||||
new ReflectorHost(program, compilerHost, options, reflectorHostContext);
|
new NgHost(program, compilerHost, options, ngHostContext);
|
||||||
}
|
}
|
||||||
const staticReflector = new compiler.StaticReflector(reflectorHost);
|
const staticReflector = new compiler.StaticReflector(ngHost);
|
||||||
compiler.StaticAndDynamicReflectionCapabilities.install(staticReflector);
|
compiler.StaticAndDynamicReflectionCapabilities.install(staticReflector);
|
||||||
const htmlParser =
|
const htmlParser =
|
||||||
new compiler.I18NHtmlParser(new compiler.HtmlParser(), transContent, cliOptions.i18nFormat);
|
new compiler.I18NHtmlParser(new compiler.HtmlParser(), transContent, cliOptions.i18nFormat);
|
||||||
|
@ -135,18 +134,15 @@ export class CodeGenerator {
|
||||||
new compiler.ViewCompiler(config, elementSchemaRegistry),
|
new compiler.ViewCompiler(config, elementSchemaRegistry),
|
||||||
new compiler.DirectiveWrapperCompiler(
|
new compiler.DirectiveWrapperCompiler(
|
||||||
config, expressionParser, elementSchemaRegistry, console),
|
config, expressionParser, elementSchemaRegistry, console),
|
||||||
new compiler.NgModuleCompiler(), new compiler.TypeScriptEmitter(reflectorHost),
|
new compiler.NgModuleCompiler(), new compiler.TypeScriptEmitter(ngHost), cliOptions.locale,
|
||||||
cliOptions.locale, cliOptions.i18nFormat,
|
cliOptions.i18nFormat, new compiler.AnimationParser(elementSchemaRegistry));
|
||||||
new compiler.AnimationParser(elementSchemaRegistry));
|
|
||||||
|
|
||||||
return new CodeGenerator(
|
return new CodeGenerator(options, program, compilerHost, staticReflector, aotCompiler, ngHost);
|
||||||
options, program, compilerHost, staticReflector, aotCompiler, reflectorHost);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extractProgramSymbols(
|
export function extractProgramSymbols(
|
||||||
program: ts.Program, staticReflector: compiler.StaticReflector,
|
program: ts.Program, staticReflector: compiler.StaticReflector, ngHost: NgHost,
|
||||||
reflectorHost: compiler.StaticReflectorHost,
|
|
||||||
options: AngularCompilerOptions): compiler.StaticSymbol[] {
|
options: AngularCompilerOptions): compiler.StaticSymbol[] {
|
||||||
// Compare with false since the default should be true
|
// Compare with false since the default should be true
|
||||||
const skipFileNames =
|
const skipFileNames =
|
||||||
|
@ -157,7 +153,7 @@ export function extractProgramSymbols(
|
||||||
program.getSourceFiles()
|
program.getSourceFiles()
|
||||||
.filter(sourceFile => !skipFileNames.test(sourceFile.fileName))
|
.filter(sourceFile => !skipFileNames.test(sourceFile.fileName))
|
||||||
.forEach(sourceFile => {
|
.forEach(sourceFile => {
|
||||||
const absSrcPath = reflectorHost.getCanonicalFileName(sourceFile.fileName);
|
const absSrcPath = ngHost.getCanonicalFileName(sourceFile.fileName);
|
||||||
|
|
||||||
const moduleMetadata = staticReflector.getModuleMetadata(absSrcPath);
|
const moduleMetadata = staticReflector.getModuleMetadata(absSrcPath);
|
||||||
if (!moduleMetadata) {
|
if (!moduleMetadata) {
|
||||||
|
@ -176,7 +172,7 @@ export function extractProgramSymbols(
|
||||||
// Ignore symbols that are only included to record error information.
|
// Ignore symbols that are only included to record error information.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
staticSymbols.push(reflectorHost.findDeclaration(absSrcPath, symbol, absSrcPath));
|
staticSymbols.push(staticReflector.findDeclaration(absSrcPath, symbol, absSrcPath));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -19,18 +19,18 @@ import * as tsc from '@angular/tsc-wrapped';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {extractProgramSymbols} from './codegen';
|
import {extractProgramSymbols} from './codegen';
|
||||||
import {ReflectorHost} from './reflector_host';
|
import {NgHost} from './ng_host';
|
||||||
|
|
||||||
export class Extractor {
|
export class Extractor {
|
||||||
constructor(
|
constructor(
|
||||||
private options: tsc.AngularCompilerOptions, private program: ts.Program,
|
private options: tsc.AngularCompilerOptions, private program: ts.Program,
|
||||||
public host: ts.CompilerHost, private staticReflector: compiler.StaticReflector,
|
public host: ts.CompilerHost, private staticReflector: compiler.StaticReflector,
|
||||||
private messageBundle: compiler.MessageBundle, private reflectorHost: ReflectorHost,
|
private messageBundle: compiler.MessageBundle, private ngHost: NgHost,
|
||||||
private metadataResolver: compiler.CompileMetadataResolver) {}
|
private metadataResolver: compiler.CompileMetadataResolver) {}
|
||||||
|
|
||||||
extract(): Promise<compiler.MessageBundle> {
|
extract(): Promise<compiler.MessageBundle> {
|
||||||
const programSymbols: compiler.StaticSymbol[] =
|
const programSymbols: compiler.StaticSymbol[] =
|
||||||
extractProgramSymbols(this.program, this.staticReflector, this.reflectorHost, this.options);
|
extractProgramSymbols(this.program, this.staticReflector, this.ngHost, this.options);
|
||||||
|
|
||||||
const {ngModules, files} = compiler.analyzeAndValidateNgModules(
|
const {ngModules, files} = compiler.analyzeAndValidateNgModules(
|
||||||
programSymbols, {transitiveModules: true}, this.metadataResolver);
|
programSymbols, {transitiveModules: true}, this.metadataResolver);
|
||||||
|
@ -65,12 +65,12 @@ export class Extractor {
|
||||||
static create(
|
static create(
|
||||||
options: tsc.AngularCompilerOptions, translationsFormat: string, program: ts.Program,
|
options: tsc.AngularCompilerOptions, translationsFormat: string, program: ts.Program,
|
||||||
compilerHost: ts.CompilerHost, resourceLoader: compiler.ResourceLoader,
|
compilerHost: ts.CompilerHost, resourceLoader: compiler.ResourceLoader,
|
||||||
reflectorHost?: ReflectorHost): Extractor {
|
ngHost?: NgHost): Extractor {
|
||||||
const htmlParser = new compiler.I18NHtmlParser(new compiler.HtmlParser());
|
const htmlParser = new compiler.I18NHtmlParser(new compiler.HtmlParser());
|
||||||
|
|
||||||
const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver();
|
const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver();
|
||||||
if (!reflectorHost) reflectorHost = new ReflectorHost(program, compilerHost, options);
|
if (!ngHost) ngHost = new NgHost(program, compilerHost, options);
|
||||||
const staticReflector = new compiler.StaticReflector(reflectorHost);
|
const staticReflector = new compiler.StaticReflector(ngHost);
|
||||||
compiler.StaticAndDynamicReflectionCapabilities.install(staticReflector);
|
compiler.StaticAndDynamicReflectionCapabilities.install(staticReflector);
|
||||||
|
|
||||||
const config = new compiler.CompilerConfig({
|
const config = new compiler.CompilerConfig({
|
||||||
|
@ -92,6 +92,6 @@ export class Extractor {
|
||||||
const messageBundle = new compiler.MessageBundle(htmlParser, [], {});
|
const messageBundle = new compiler.MessageBundle(htmlParser, [], {});
|
||||||
|
|
||||||
return new Extractor(
|
return new Extractor(
|
||||||
options, program, compilerHost, staticReflector, messageBundle, reflectorHost, resolver);
|
options, program, compilerHost, staticReflector, messageBundle, ngHost, resolver);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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 {AssetUrl, ImportGenerator, StaticReflectorHost, StaticSymbol} from '@angular/compiler';
|
import {AotCompilerHost, AssetUrl, StaticSymbol} from '@angular/compiler';
|
||||||
import {AngularCompilerOptions, MetadataCollector, ModuleMetadata} from '@angular/tsc-wrapped';
|
import {AngularCompilerOptions, MetadataCollector, ModuleMetadata} from '@angular/tsc-wrapped';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
@ -17,46 +17,42 @@ const DTS = /\.d\.ts$/;
|
||||||
const NODE_MODULES = '/node_modules/';
|
const NODE_MODULES = '/node_modules/';
|
||||||
const IS_GENERATED = /\.(ngfactory|css(\.shim)?)$/;
|
const IS_GENERATED = /\.(ngfactory|css(\.shim)?)$/;
|
||||||
|
|
||||||
export interface ReflectorHostContext {
|
export interface NgHostContext {
|
||||||
fileExists(fileName: string): boolean;
|
fileExists(fileName: string): boolean;
|
||||||
directoryExists(directoryName: string): boolean;
|
directoryExists(directoryName: string): boolean;
|
||||||
readFile(fileName: string): string;
|
readFile(fileName: string): string;
|
||||||
assumeFileExists(fileName: string): void;
|
assumeFileExists(fileName: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ReflectorHost implements StaticReflectorHost, ImportGenerator {
|
export class NgHost implements AotCompilerHost {
|
||||||
protected metadataCollector = new MetadataCollector();
|
protected metadataCollector = new MetadataCollector();
|
||||||
protected context: ReflectorHostContext;
|
protected context: NgHostContext;
|
||||||
private isGenDirChildOfRootDir: boolean;
|
private isGenDirChildOfRootDir: boolean;
|
||||||
protected basePath: string;
|
protected basePath: string;
|
||||||
private genDir: string;
|
private genDir: string;
|
||||||
constructor(
|
constructor(
|
||||||
protected program: ts.Program, protected compilerHost: ts.CompilerHost,
|
protected program: ts.Program, protected compilerHost: ts.CompilerHost,
|
||||||
protected options: AngularCompilerOptions, context?: ReflectorHostContext) {
|
protected options: AngularCompilerOptions, context?: NgHostContext) {
|
||||||
// normalize the path so that it never ends with '/'.
|
// normalize the path so that it never ends with '/'.
|
||||||
this.basePath = path.normalize(path.join(this.options.basePath, '.')).replace(/\\/g, '/');
|
this.basePath = path.normalize(path.join(this.options.basePath, '.')).replace(/\\/g, '/');
|
||||||
this.genDir = path.normalize(path.join(this.options.genDir, '.')).replace(/\\/g, '/');
|
this.genDir = path.normalize(path.join(this.options.genDir, '.')).replace(/\\/g, '/');
|
||||||
|
|
||||||
this.context = context || new NodeReflectorHostContext(compilerHost);
|
this.context = context || new NodeNgHostContext(compilerHost);
|
||||||
const genPath: string = path.relative(this.basePath, this.genDir);
|
const genPath: string = path.relative(this.basePath, this.genDir);
|
||||||
this.isGenDirChildOfRootDir = genPath === '' || !genPath.startsWith('..');
|
this.isGenDirChildOfRootDir = genPath === '' || !genPath.startsWith('..');
|
||||||
}
|
}
|
||||||
|
|
||||||
angularImportLocations() {
|
|
||||||
return {
|
|
||||||
coreDecorators: '@angular/core/src/metadata',
|
|
||||||
diDecorators: '@angular/core/src/di/metadata',
|
|
||||||
diMetadata: '@angular/core/src/di/metadata',
|
|
||||||
diOpaqueToken: '@angular/core/src/di/opaque_token',
|
|
||||||
animationMetadata: '@angular/core/src/animation/metadata',
|
|
||||||
provider: '@angular/core/src/di/provider'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// We use absolute paths on disk as canonical.
|
// We use absolute paths on disk as canonical.
|
||||||
getCanonicalFileName(fileName: string): string { return fileName; }
|
getCanonicalFileName(fileName: string): string { return fileName; }
|
||||||
|
|
||||||
protected resolve(m: string, containingFile: string) {
|
resolveImportToFile(m: string, containingFile: string) {
|
||||||
|
if (!containingFile || !containingFile.length) {
|
||||||
|
if (m.indexOf('.') === 0) {
|
||||||
|
throw new Error('Resolution of relative paths requires a containing file.');
|
||||||
|
}
|
||||||
|
// Any containing file gives the same result for absolute imports
|
||||||
|
containingFile = path.join(this.basePath, 'index.ts');
|
||||||
|
}
|
||||||
m = m.replace(EXT, '');
|
m = m.replace(EXT, '');
|
||||||
const resolved =
|
const resolved =
|
||||||
ts.resolveModuleName(m, containingFile.replace(/\\/g, '/'), this.options, this.context)
|
ts.resolveModuleName(m, containingFile.replace(/\\/g, '/'), this.options, this.context)
|
||||||
|
@ -73,7 +69,7 @@ export class ReflectorHost implements StaticReflectorHost, ImportGenerator {
|
||||||
protected resolveAssetUrl(url: string, containingFile: string): string {
|
protected resolveAssetUrl(url: string, containingFile: string): string {
|
||||||
const assetUrl = this.normalizeAssetUrl(url);
|
const assetUrl = this.normalizeAssetUrl(url);
|
||||||
if (assetUrl) {
|
if (assetUrl) {
|
||||||
return this.getCanonicalFileName(this.resolve(assetUrl, containingFile));
|
return this.getCanonicalFileName(this.resolveImportToFile(assetUrl, containingFile));
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
@ -158,80 +154,8 @@ export class ReflectorHost implements StaticReflectorHost, ImportGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
findDeclaration(
|
|
||||||
module: string, symbolName: string, containingFile: string,
|
|
||||||
containingModule?: string): StaticSymbol {
|
|
||||||
if (!containingFile || !containingFile.length) {
|
|
||||||
if (module.indexOf('.') === 0) {
|
|
||||||
throw new Error('Resolution of relative paths requires a containing file.');
|
|
||||||
}
|
|
||||||
// Any containing file gives the same result for absolute imports
|
|
||||||
containingFile = path.join(this.basePath, 'index.ts');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const assetUrl = this.normalizeAssetUrl(module);
|
|
||||||
if (assetUrl) {
|
|
||||||
module = assetUrl;
|
|
||||||
}
|
|
||||||
const filePath = this.resolve(module, containingFile);
|
|
||||||
|
|
||||||
if (!filePath) {
|
|
||||||
// If the file cannot be found the module is probably referencing a declared module
|
|
||||||
// for which there is no disambiguating file and we also don't need to track
|
|
||||||
// re-exports. Just use the module name.
|
|
||||||
return this.getStaticSymbol(module, symbolName);
|
|
||||||
}
|
|
||||||
|
|
||||||
const tc = this.program.getTypeChecker();
|
|
||||||
const sf = this.program.getSourceFile(filePath);
|
|
||||||
if (!sf || !(<any>sf).symbol) {
|
|
||||||
// The source file was not needed in the compile but we do need the values from
|
|
||||||
// the corresponding .ts files stored in the .metadata.json file. Check the file
|
|
||||||
// for exports to see if the file is exported.
|
|
||||||
return this.resolveExportedSymbol(filePath, symbolName) ||
|
|
||||||
this.getStaticSymbol(filePath, symbolName);
|
|
||||||
}
|
|
||||||
|
|
||||||
let symbol = tc.getExportsOfModule((<any>sf).symbol).find(m => m.name === symbolName);
|
|
||||||
if (!symbol) {
|
|
||||||
throw new Error(`can't find symbol ${symbolName} exported from module ${filePath}`);
|
|
||||||
}
|
|
||||||
if (symbol &&
|
|
||||||
symbol.flags & ts.SymbolFlags.Alias) { // This is an alias, follow what it aliases
|
|
||||||
symbol = tc.getAliasedSymbol(symbol);
|
|
||||||
}
|
|
||||||
const declaration = symbol.getDeclarations()[0];
|
|
||||||
const declarationFile = this.getCanonicalFileName(declaration.getSourceFile().fileName);
|
|
||||||
|
|
||||||
return this.getStaticSymbol(declarationFile, symbol.getName());
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`can't resolve module ${module} from ${containingFile}`);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private typeCache = new Map<string, StaticSymbol>();
|
|
||||||
private resolverCache = new Map<string, ModuleMetadata>();
|
private resolverCache = new Map<string, ModuleMetadata>();
|
||||||
|
|
||||||
/**
|
|
||||||
* getStaticSymbol produces a Type whose metadata is known but whose implementation is not loaded.
|
|
||||||
* All types passed to the StaticResolver should be pseudo-types returned by this method.
|
|
||||||
*
|
|
||||||
* @param declarationFile the absolute path of the file where the symbol is declared
|
|
||||||
* @param name the name of the type.
|
|
||||||
*/
|
|
||||||
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol {
|
|
||||||
const memberSuffix = members ? `.${ members.join('.')}` : '';
|
|
||||||
const key = `"${declarationFile}".${name}${memberSuffix}`;
|
|
||||||
let result = this.typeCache.get(key);
|
|
||||||
if (!result) {
|
|
||||||
result = new StaticSymbol(declarationFile, name, members);
|
|
||||||
this.typeCache.set(key, result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
getMetadataFor(filePath: string): ModuleMetadata {
|
getMetadataFor(filePath: string): ModuleMetadata {
|
||||||
if (!this.context.fileExists(filePath)) {
|
if (!this.context.fileExists(filePath)) {
|
||||||
// If the file doesn't exists then we cannot return metadata for the file.
|
// If the file doesn't exists then we cannot return metadata for the file.
|
||||||
|
@ -277,59 +201,9 @@ export class ReflectorHost implements StaticReflectorHost, ImportGenerator {
|
||||||
}
|
}
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected resolveExportedSymbol(filePath: string, symbolName: string): StaticSymbol {
|
|
||||||
const resolveModule = (moduleName: string): string => {
|
|
||||||
const resolvedModulePath = this.getCanonicalFileName(this.resolve(moduleName, filePath));
|
|
||||||
if (!resolvedModulePath) {
|
|
||||||
throw new Error(`Could not resolve module '${moduleName}' relative to file ${filePath}`);
|
|
||||||
}
|
|
||||||
return resolvedModulePath;
|
|
||||||
};
|
|
||||||
const metadata = this.getResolverMetadata(filePath);
|
|
||||||
if (metadata) {
|
|
||||||
// If we have metadata for the symbol, this is the original exporting location.
|
|
||||||
if (metadata.metadata[symbolName]) {
|
|
||||||
return this.getStaticSymbol(filePath, symbolName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no, try to find the symbol in one of the re-export location
|
|
||||||
if (metadata.exports) {
|
|
||||||
// Try and find the symbol in the list of explicitly re-exported symbols.
|
|
||||||
for (const moduleExport of metadata.exports) {
|
|
||||||
if (moduleExport.export) {
|
|
||||||
const exportSymbol = moduleExport.export.find(symbol => {
|
|
||||||
if (typeof symbol === 'string') {
|
|
||||||
return symbol == symbolName;
|
|
||||||
} else {
|
|
||||||
return symbol.as == symbolName;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (exportSymbol) {
|
|
||||||
let symName = symbolName;
|
|
||||||
if (typeof exportSymbol !== 'string') {
|
|
||||||
symName = exportSymbol.name;
|
|
||||||
}
|
|
||||||
return this.resolveExportedSymbol(resolveModule(moduleExport.from), symName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to find the symbol via export * directives.
|
|
||||||
for (const moduleExport of metadata.exports) {
|
|
||||||
if (!moduleExport.export) {
|
|
||||||
const resolvedModule = resolveModule(moduleExport.from);
|
|
||||||
const candidateSymbol = this.resolveExportedSymbol(resolvedModule, symbolName);
|
|
||||||
if (candidateSymbol) return candidateSymbol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NodeReflectorHostContext implements ReflectorHostContext {
|
export class NodeNgHostContext implements NgHostContext {
|
||||||
constructor(private host: ts.CompilerHost) {}
|
constructor(private host: ts.CompilerHost) {}
|
||||||
|
|
||||||
private assumedExists: {[fileName: string]: boolean} = {};
|
private assumedExists: {[fileName: string]: boolean} = {};
|
|
@ -12,22 +12,22 @@ import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ReflectorHost, ReflectorHostContext} from './reflector_host';
|
import {NgHost, NgHostContext} from './ng_host';
|
||||||
|
|
||||||
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
||||||
const DTS = /\.d\.ts$/;
|
const DTS = /\.d\.ts$/;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This version of the reflector host expects that the program will be compiled
|
* This version of the AotCompilerHost expects that the program will be compiled
|
||||||
* and executed with a "path mapped" directory structure, where generated files
|
* and executed with a "path mapped" directory structure, where generated files
|
||||||
* are in a parallel tree with the sources, and imported using a `./` relative
|
* are in a parallel tree with the sources, and imported using a `./` relative
|
||||||
* import. This requires using TS `rootDirs` option and also teaching the module
|
* import. This requires using TS `rootDirs` option and also teaching the module
|
||||||
* loader what to do.
|
* loader what to do.
|
||||||
*/
|
*/
|
||||||
export class PathMappedReflectorHost extends ReflectorHost {
|
export class PathMappedNgHost extends NgHost {
|
||||||
constructor(
|
constructor(
|
||||||
program: ts.Program, compilerHost: ts.CompilerHost, options: AngularCompilerOptions,
|
program: ts.Program, compilerHost: ts.CompilerHost, options: AngularCompilerOptions,
|
||||||
context?: ReflectorHostContext) {
|
context?: NgHostContext) {
|
||||||
super(program, compilerHost, options, context);
|
super(program, compilerHost, options, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,14 @@ export class PathMappedReflectorHost extends ReflectorHost {
|
||||||
return fileName;
|
return fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected resolve(m: string, containingFile: string) {
|
resolveImportToFile(m: string, containingFile: string) {
|
||||||
|
if (!containingFile || !containingFile.length) {
|
||||||
|
if (m.indexOf('.') === 0) {
|
||||||
|
throw new Error('Resolution of relative paths requires a containing file.');
|
||||||
|
}
|
||||||
|
// Any containing file gives the same result for absolute imports
|
||||||
|
containingFile = path.join(this.basePath, 'index.ts');
|
||||||
|
}
|
||||||
for (const root of this.options.rootDirs || ['']) {
|
for (const root of this.options.rootDirs || ['']) {
|
||||||
const rootedContainingFile = path.join(root, containingFile);
|
const rootedContainingFile = path.join(root, containingFile);
|
||||||
const resolved =
|
const resolved =
|
||||||
|
@ -82,7 +89,7 @@ export class PathMappedReflectorHost extends ReflectorHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolvable = (candidate: string) => {
|
const resolvable = (candidate: string) => {
|
||||||
const resolved = this.getCanonicalFileName(this.resolve(candidate, importedFile));
|
const resolved = this.getCanonicalFileName(this.resolveImportToFile(candidate, importedFile));
|
||||||
return resolved && resolved.replace(EXT, '') === importedFile.replace(EXT, '');
|
return resolved && resolved.replace(EXT, '') === importedFile.replace(EXT, '');
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,9 +16,3 @@ export var ReflectionCapabilities: typeof r.ReflectionCapabilities = r.Reflectio
|
||||||
|
|
||||||
export type Console = typeof r._Console;
|
export type Console = typeof r._Console;
|
||||||
export var Console: typeof r.Console = r.Console;
|
export var Console: typeof r.Console = r.Console;
|
||||||
|
|
||||||
export var reflector: typeof r.reflector = r.reflector;
|
|
||||||
|
|
||||||
export type SetterFn = typeof r._SetterFn;
|
|
||||||
export type GetterFn = typeof r._GetterFn;
|
|
||||||
export type MethodFn = typeof r._MethodFn;
|
|
||||||
|
|
|
@ -6,14 +6,14 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ReflectorHostContext} from '@angular/compiler-cli/src/reflector_host';
|
import {NgHostContext} from '@angular/compiler-cli/src/ng_host';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
export type Entry = string | Directory;
|
export type Entry = string | Directory;
|
||||||
|
|
||||||
export interface Directory { [name: string]: Entry; }
|
export interface Directory { [name: string]: Entry; }
|
||||||
|
|
||||||
export class MockContext implements ReflectorHostContext {
|
export class MockContext implements NgHostContext {
|
||||||
constructor(public currentDirectory: string, private files: Entry) {}
|
constructor(public currentDirectory: string, private files: Entry) {}
|
||||||
|
|
||||||
fileExists(fileName: string): boolean { return typeof this.getEntry(fileName) === 'string'; }
|
fileExists(fileName: string): boolean { return typeof this.getEntry(fileName) === 'string'; }
|
||||||
|
|
|
@ -0,0 +1,204 @@
|
||||||
|
/**
|
||||||
|
* @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 {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
|
||||||
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
|
import {NgHost} from '../src/ng_host';
|
||||||
|
|
||||||
|
import {Directory, Entry, MockCompilerHost, MockContext} from './mocks';
|
||||||
|
|
||||||
|
describe('NgHost', () => {
|
||||||
|
let context: MockContext;
|
||||||
|
let host: ts.CompilerHost;
|
||||||
|
let program: ts.Program;
|
||||||
|
let hostNestedGenDir: NgHost;
|
||||||
|
let hostSiblingGenDir: NgHost;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
context = new MockContext('/tmp/src', clone(FILES));
|
||||||
|
host = new MockCompilerHost(context);
|
||||||
|
program = ts.createProgram(
|
||||||
|
['main.ts'], {
|
||||||
|
module: ts.ModuleKind.CommonJS,
|
||||||
|
},
|
||||||
|
host);
|
||||||
|
// Force a typecheck
|
||||||
|
const errors = program.getSemanticDiagnostics();
|
||||||
|
if (errors && errors.length) {
|
||||||
|
throw new Error('Expected no errors');
|
||||||
|
}
|
||||||
|
hostNestedGenDir = new NgHost(
|
||||||
|
program, host, {
|
||||||
|
genDir: '/tmp/project/src/gen/',
|
||||||
|
basePath: '/tmp/project/src',
|
||||||
|
skipMetadataEmit: false,
|
||||||
|
strictMetadataEmit: false,
|
||||||
|
skipTemplateCodegen: false,
|
||||||
|
trace: false
|
||||||
|
},
|
||||||
|
context);
|
||||||
|
hostSiblingGenDir = new NgHost(
|
||||||
|
program, host, {
|
||||||
|
genDir: '/tmp/project/gen',
|
||||||
|
basePath: '/tmp/project/src/',
|
||||||
|
skipMetadataEmit: false,
|
||||||
|
strictMetadataEmit: false,
|
||||||
|
skipTemplateCodegen: false,
|
||||||
|
trace: false
|
||||||
|
},
|
||||||
|
context);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('nestedGenDir', () => {
|
||||||
|
it('should import node_module from factory', () => {
|
||||||
|
expect(hostNestedGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/gen/my.ngfactory.ts',
|
||||||
|
'/tmp/project/node_modules/@angular/core.d.ts'))
|
||||||
|
.toEqual('@angular/core');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should import factory from factory', () => {
|
||||||
|
expect(hostNestedGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ngfactory.ts'))
|
||||||
|
.toEqual('./my.other.ngfactory');
|
||||||
|
expect(hostNestedGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.css.ts'))
|
||||||
|
.toEqual('../my.other.css');
|
||||||
|
expect(hostNestedGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.css.shim.ts'))
|
||||||
|
.toEqual('./a/my.other.css.shim');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should import application from factory', () => {
|
||||||
|
expect(hostNestedGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
|
||||||
|
.toEqual('../my.other');
|
||||||
|
expect(hostNestedGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
|
||||||
|
.toEqual('../../my.other');
|
||||||
|
expect(hostNestedGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.ts'))
|
||||||
|
.toEqual('../a/my.other');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('nestedGenDir', () => {
|
||||||
|
it('should import node_module from factory', () => {
|
||||||
|
expect(hostSiblingGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/gen/my.ngfactory.ts',
|
||||||
|
'/tmp/project/node_modules/@angular/core.d.ts'))
|
||||||
|
.toEqual('@angular/core');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should import factory from factory', () => {
|
||||||
|
expect(hostSiblingGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ngfactory.ts'))
|
||||||
|
.toEqual('./my.other.ngfactory');
|
||||||
|
expect(hostSiblingGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.css.ts'))
|
||||||
|
.toEqual('../my.other.css');
|
||||||
|
expect(hostSiblingGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.css.shim.ts'))
|
||||||
|
.toEqual('./a/my.other.css.shim');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should import application from factory', () => {
|
||||||
|
expect(hostSiblingGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
|
||||||
|
.toEqual('./my.other');
|
||||||
|
expect(hostSiblingGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
|
||||||
|
.toEqual('../my.other');
|
||||||
|
expect(hostSiblingGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.ts'))
|
||||||
|
.toEqual('./a/my.other');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to produce an import from main @angular/core', () => {
|
||||||
|
expect(hostNestedGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/main.ts', '/tmp/project/node_modules/@angular/core.d.ts'))
|
||||||
|
.toEqual('@angular/core');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to produce an import from main to a sub-directory', () => {
|
||||||
|
expect(hostNestedGenDir.getImportPath('main.ts', 'lib/utils.ts')).toEqual('./lib/utils');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to produce an import from to a peer file', () => {
|
||||||
|
expect(hostNestedGenDir.getImportPath('lib/utils.ts', 'lib/collections.ts'))
|
||||||
|
.toEqual('./collections');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to produce an import from to a sibling directory', () => {
|
||||||
|
expect(hostNestedGenDir.getImportPath('lib2/utils2.ts', 'lib/utils.ts'))
|
||||||
|
.toEqual('../lib/utils');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to read a metadata file', () => {
|
||||||
|
expect(hostNestedGenDir.getMetadataFor('node_modules/@angular/core.d.ts'))
|
||||||
|
.toEqual({__symbolic: 'module', version: 1, metadata: {foo: {__symbolic: 'class'}}});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to read metadata from an otherwise unused .d.ts file ', () => {
|
||||||
|
expect(hostNestedGenDir.getMetadataFor('node_modules/@angular/unused.d.ts')).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to read empty metadata ', () => {
|
||||||
|
expect(hostNestedGenDir.getMetadataFor('node_modules/@angular/empty.d.ts')).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined for missing modules', () => {
|
||||||
|
expect(hostNestedGenDir.getMetadataFor('node_modules/@angular/missing.d.ts')).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const dummyModule = 'export let foo: any[];';
|
||||||
|
|
||||||
|
const FILES: Entry = {
|
||||||
|
'tmp': {
|
||||||
|
'src': {
|
||||||
|
'main.ts': `
|
||||||
|
import * as c from '@angular/core';
|
||||||
|
import * as r from '@angular/router';
|
||||||
|
import * as u from './lib/utils';
|
||||||
|
import * as cs from './lib/collections';
|
||||||
|
import * as u2 from './lib2/utils2';
|
||||||
|
`,
|
||||||
|
'lib': {
|
||||||
|
'utils.ts': dummyModule,
|
||||||
|
'collections.ts': dummyModule,
|
||||||
|
},
|
||||||
|
'lib2': {'utils2.ts': dummyModule},
|
||||||
|
'node_modules': {
|
||||||
|
'@angular': {
|
||||||
|
'core.d.ts': dummyModule,
|
||||||
|
'core.metadata.json':
|
||||||
|
`{"__symbolic":"module", "version": 1, "metadata": {"foo": {"__symbolic": "class"}}}`,
|
||||||
|
'router': {'index.d.ts': dummyModule, 'src': {'providers.d.ts': dummyModule}},
|
||||||
|
'unused.d.ts': dummyModule,
|
||||||
|
'empty.d.ts': 'export declare var a: string;',
|
||||||
|
'empty.metadata.json': '[]',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function clone(entry: Entry): Entry {
|
||||||
|
if (typeof entry === 'string') {
|
||||||
|
return entry;
|
||||||
|
} else {
|
||||||
|
const result: Directory = {};
|
||||||
|
for (const name in entry) {
|
||||||
|
result[name] = clone(entry[name]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,329 +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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
|
|
||||||
import * as ts from 'typescript';
|
|
||||||
|
|
||||||
import {ReflectorHost} from '../src/reflector_host';
|
|
||||||
|
|
||||||
import {Directory, Entry, MockCompilerHost, MockContext} from './mocks';
|
|
||||||
|
|
||||||
describe('reflector_host', () => {
|
|
||||||
let context: MockContext;
|
|
||||||
let host: ts.CompilerHost;
|
|
||||||
let program: ts.Program;
|
|
||||||
let reflectorNestedGenDir: ReflectorHost;
|
|
||||||
let reflectorSiblingGenDir: ReflectorHost;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
context = new MockContext('/tmp/src', clone(FILES));
|
|
||||||
host = new MockCompilerHost(context);
|
|
||||||
program = ts.createProgram(
|
|
||||||
['main.ts'], {
|
|
||||||
module: ts.ModuleKind.CommonJS,
|
|
||||||
},
|
|
||||||
host);
|
|
||||||
// Force a typecheck
|
|
||||||
const errors = program.getSemanticDiagnostics();
|
|
||||||
if (errors && errors.length) {
|
|
||||||
throw new Error('Expected no errors');
|
|
||||||
}
|
|
||||||
reflectorNestedGenDir = new ReflectorHost(
|
|
||||||
program, host, {
|
|
||||||
genDir: '/tmp/project/src/gen/',
|
|
||||||
basePath: '/tmp/project/src',
|
|
||||||
skipMetadataEmit: false,
|
|
||||||
strictMetadataEmit: false,
|
|
||||||
skipTemplateCodegen: false,
|
|
||||||
trace: false
|
|
||||||
},
|
|
||||||
context);
|
|
||||||
reflectorSiblingGenDir = new ReflectorHost(
|
|
||||||
program, host, {
|
|
||||||
genDir: '/tmp/project/gen',
|
|
||||||
basePath: '/tmp/project/src/',
|
|
||||||
skipMetadataEmit: false,
|
|
||||||
strictMetadataEmit: false,
|
|
||||||
skipTemplateCodegen: false,
|
|
||||||
trace: false
|
|
||||||
},
|
|
||||||
context);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('nestedGenDir', () => {
|
|
||||||
it('should import node_module from factory', () => {
|
|
||||||
expect(reflectorNestedGenDir.getImportPath(
|
|
||||||
'/tmp/project/src/gen/my.ngfactory.ts',
|
|
||||||
'/tmp/project/node_modules/@angular/core.d.ts'))
|
|
||||||
.toEqual('@angular/core');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should import factory from factory', () => {
|
|
||||||
expect(reflectorNestedGenDir.getImportPath(
|
|
||||||
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ngfactory.ts'))
|
|
||||||
.toEqual('./my.other.ngfactory');
|
|
||||||
expect(reflectorNestedGenDir.getImportPath(
|
|
||||||
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.css.ts'))
|
|
||||||
.toEqual('../my.other.css');
|
|
||||||
expect(reflectorNestedGenDir.getImportPath(
|
|
||||||
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.css.shim.ts'))
|
|
||||||
.toEqual('./a/my.other.css.shim');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should import application from factory', () => {
|
|
||||||
expect(reflectorNestedGenDir.getImportPath(
|
|
||||||
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
|
|
||||||
.toEqual('../my.other');
|
|
||||||
expect(reflectorNestedGenDir.getImportPath(
|
|
||||||
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
|
|
||||||
.toEqual('../../my.other');
|
|
||||||
expect(reflectorNestedGenDir.getImportPath(
|
|
||||||
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.ts'))
|
|
||||||
.toEqual('../a/my.other');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('nestedGenDir', () => {
|
|
||||||
it('should import node_module from factory', () => {
|
|
||||||
expect(reflectorSiblingGenDir.getImportPath(
|
|
||||||
'/tmp/project/src/gen/my.ngfactory.ts',
|
|
||||||
'/tmp/project/node_modules/@angular/core.d.ts'))
|
|
||||||
.toEqual('@angular/core');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should import factory from factory', () => {
|
|
||||||
expect(reflectorSiblingGenDir.getImportPath(
|
|
||||||
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ngfactory.ts'))
|
|
||||||
.toEqual('./my.other.ngfactory');
|
|
||||||
expect(reflectorSiblingGenDir.getImportPath(
|
|
||||||
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.css.ts'))
|
|
||||||
.toEqual('../my.other.css');
|
|
||||||
expect(reflectorSiblingGenDir.getImportPath(
|
|
||||||
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.css.shim.ts'))
|
|
||||||
.toEqual('./a/my.other.css.shim');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should import application from factory', () => {
|
|
||||||
expect(reflectorSiblingGenDir.getImportPath(
|
|
||||||
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
|
|
||||||
.toEqual('./my.other');
|
|
||||||
expect(reflectorSiblingGenDir.getImportPath(
|
|
||||||
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
|
|
||||||
.toEqual('../my.other');
|
|
||||||
expect(reflectorSiblingGenDir.getImportPath(
|
|
||||||
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.ts'))
|
|
||||||
.toEqual('./a/my.other');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should provide the import locations for angular', () => {
|
|
||||||
const {coreDecorators, diDecorators, diMetadata, animationMetadata, provider} =
|
|
||||||
reflectorNestedGenDir.angularImportLocations();
|
|
||||||
expect(coreDecorators).toEqual('@angular/core/src/metadata');
|
|
||||||
expect(diDecorators).toEqual('@angular/core/src/di/metadata');
|
|
||||||
expect(diMetadata).toEqual('@angular/core/src/di/metadata');
|
|
||||||
expect(animationMetadata).toEqual('@angular/core/src/animation/metadata');
|
|
||||||
expect(provider).toEqual('@angular/core/src/di/provider');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to produce an import from main @angular/core', () => {
|
|
||||||
expect(reflectorNestedGenDir.getImportPath(
|
|
||||||
'/tmp/project/src/main.ts', '/tmp/project/node_modules/@angular/core.d.ts'))
|
|
||||||
.toEqual('@angular/core');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to produce an import from main to a sub-directory', () => {
|
|
||||||
expect(reflectorNestedGenDir.getImportPath('main.ts', 'lib/utils.ts')).toEqual('./lib/utils');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to produce an import from to a peer file', () => {
|
|
||||||
expect(reflectorNestedGenDir.getImportPath('lib/utils.ts', 'lib/collections.ts'))
|
|
||||||
.toEqual('./collections');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to produce an import from to a sibling directory', () => {
|
|
||||||
expect(reflectorNestedGenDir.getImportPath('lib2/utils2.ts', 'lib/utils.ts'))
|
|
||||||
.toEqual('../lib/utils');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to produce a symbol for an exported symbol', () => {
|
|
||||||
expect(reflectorNestedGenDir.findDeclaration('@angular/router', 'foo', 'main.ts'))
|
|
||||||
.toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to produce a symbol for values space only reference', () => {
|
|
||||||
expect(reflectorNestedGenDir.findDeclaration('@angular/router/src/providers', 'foo', 'main.ts'))
|
|
||||||
.toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should be produce the same symbol if asked twice', () => {
|
|
||||||
const foo1 = reflectorNestedGenDir.getStaticSymbol('main.ts', 'foo');
|
|
||||||
const foo2 = reflectorNestedGenDir.getStaticSymbol('main.ts', 'foo');
|
|
||||||
expect(foo1).toBe(foo2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to produce a symbol for a module with no file', () => {
|
|
||||||
expect(reflectorNestedGenDir.getStaticSymbol('angularjs', 'SomeAngularSymbol')).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to read a metadata file', () => {
|
|
||||||
expect(reflectorNestedGenDir.getMetadataFor('node_modules/@angular/core.d.ts'))
|
|
||||||
.toEqual({__symbolic: 'module', version: 1, metadata: {foo: {__symbolic: 'class'}}});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to read metadata from an otherwise unused .d.ts file ', () => {
|
|
||||||
expect(reflectorNestedGenDir.getMetadataFor('node_modules/@angular/unused.d.ts'))
|
|
||||||
.toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to read empty metadata ', () => {
|
|
||||||
expect(reflectorNestedGenDir.getMetadataFor('node_modules/@angular/empty.d.ts'))
|
|
||||||
.toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return undefined for missing modules', () => {
|
|
||||||
expect(reflectorNestedGenDir.getMetadataFor('node_modules/@angular/missing.d.ts'))
|
|
||||||
.toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to trace a named export', () => {
|
|
||||||
const symbol = reflectorNestedGenDir.findDeclaration(
|
|
||||||
'./reexport/reexport.d.ts', 'One', '/tmp/src/main.ts');
|
|
||||||
expect(symbol.name).toEqual('One');
|
|
||||||
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin1.d.ts');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to trace a renamed export', () => {
|
|
||||||
const symbol = reflectorNestedGenDir.findDeclaration(
|
|
||||||
'./reexport/reexport.d.ts', 'Four', '/tmp/src/main.ts');
|
|
||||||
expect(symbol.name).toEqual('Three');
|
|
||||||
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin1.d.ts');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to trace an export * export', () => {
|
|
||||||
const symbol = reflectorNestedGenDir.findDeclaration(
|
|
||||||
'./reexport/reexport.d.ts', 'Five', '/tmp/src/main.ts');
|
|
||||||
expect(symbol.name).toEqual('Five');
|
|
||||||
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin5.d.ts');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to trace a multi-level re-export', () => {
|
|
||||||
const symbol = reflectorNestedGenDir.findDeclaration(
|
|
||||||
'./reexport/reexport.d.ts', 'Thirty', '/tmp/src/main.ts');
|
|
||||||
expect(symbol.name).toEqual('Thirty');
|
|
||||||
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin30.d.ts');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const dummyModule = 'export let foo: any[];';
|
|
||||||
|
|
||||||
const FILES: Entry = {
|
|
||||||
'tmp': {
|
|
||||||
'src': {
|
|
||||||
'main.ts': `
|
|
||||||
import * as c from '@angular/core';
|
|
||||||
import * as r from '@angular/router';
|
|
||||||
import * as u from './lib/utils';
|
|
||||||
import * as cs from './lib/collections';
|
|
||||||
import * as u2 from './lib2/utils2';
|
|
||||||
`,
|
|
||||||
'lib': {
|
|
||||||
'utils.ts': dummyModule,
|
|
||||||
'collections.ts': dummyModule,
|
|
||||||
},
|
|
||||||
'lib2': {'utils2.ts': dummyModule},
|
|
||||||
'reexport': {
|
|
||||||
'reexport.d.ts': `
|
|
||||||
import * as c from '@angular/core';
|
|
||||||
`,
|
|
||||||
'reexport.metadata.json': JSON.stringify({
|
|
||||||
__symbolic: 'module',
|
|
||||||
version: 1,
|
|
||||||
metadata: {},
|
|
||||||
exports: [
|
|
||||||
{from: './src/origin1', export: ['One', 'Two', {name: 'Three', as: 'Four'}]},
|
|
||||||
{from: './src/origin5'}, {from: './src/reexport2'}
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
'src': {
|
|
||||||
'origin1.d.ts': `
|
|
||||||
export class One {}
|
|
||||||
export class Two {}
|
|
||||||
export class Three {}
|
|
||||||
`,
|
|
||||||
'origin1.metadata.json': JSON.stringify({
|
|
||||||
__symbolic: 'module',
|
|
||||||
version: 1,
|
|
||||||
metadata: {
|
|
||||||
One: {__symbolic: 'class'},
|
|
||||||
Two: {__symbolic: 'class'},
|
|
||||||
Three: {__symbolic: 'class'},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
'origin5.d.ts': `
|
|
||||||
export class Five {}
|
|
||||||
`,
|
|
||||||
'origin5.metadata.json': JSON.stringify({
|
|
||||||
__symbolic: 'module',
|
|
||||||
version: 1,
|
|
||||||
metadata: {
|
|
||||||
Five: {__symbolic: 'class'},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
'origin30.d.ts': `
|
|
||||||
export class Thirty {}
|
|
||||||
`,
|
|
||||||
'origin30.metadata.json': JSON.stringify({
|
|
||||||
__symbolic: 'module',
|
|
||||||
version: 1,
|
|
||||||
metadata: {
|
|
||||||
Thirty: {__symbolic: 'class'},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
'originNone.d.ts': dummyModule,
|
|
||||||
'originNone.metadata.json': JSON.stringify({
|
|
||||||
__symbolic: 'module',
|
|
||||||
version: 1,
|
|
||||||
metadata: {},
|
|
||||||
}),
|
|
||||||
'reexport2.d.ts': dummyModule,
|
|
||||||
'reexport2.metadata.json': JSON.stringify({
|
|
||||||
__symbolic: 'module',
|
|
||||||
version: 1,
|
|
||||||
metadata: {},
|
|
||||||
exports: [{from: './originNone'}, {from: './origin30'}]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'node_modules': {
|
|
||||||
'@angular': {
|
|
||||||
'core.d.ts': dummyModule,
|
|
||||||
'core.metadata.json':
|
|
||||||
`{"__symbolic":"module", "version": 1, "metadata": {"foo": {"__symbolic": "class"}}}`,
|
|
||||||
'router': {'index.d.ts': dummyModule, 'src': {'providers.d.ts': dummyModule}},
|
|
||||||
'unused.d.ts': dummyModule,
|
|
||||||
'empty.d.ts': 'export declare var a: string;',
|
|
||||||
'empty.metadata.json': '[]',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function clone(entry: Entry): Entry {
|
|
||||||
if (typeof entry === 'string') {
|
|
||||||
return entry;
|
|
||||||
} else {
|
|
||||||
const result: Directory = {};
|
|
||||||
for (const name in entry) {
|
|
||||||
result[name] = clone(entry[name]);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -26,6 +26,7 @@ export {TEMPLATE_TRANSFORMS} from './src/template_parser/template_parser';
|
||||||
export {CompilerConfig, RenderTypes} from './src/config';
|
export {CompilerConfig, RenderTypes} from './src/config';
|
||||||
export * from './src/compile_metadata';
|
export * from './src/compile_metadata';
|
||||||
export * from './src/aot/compiler';
|
export * from './src/aot/compiler';
|
||||||
|
export * from './src/aot/compiler_host';
|
||||||
export * from './src/aot/static_reflector';
|
export * from './src/aot/static_reflector';
|
||||||
export * from './src/aot/static_reflection_capabilities';
|
export * from './src/aot/static_reflection_capabilities';
|
||||||
export * from './src/aot/static_symbol';
|
export * from './src/aot/static_symbol';
|
||||||
|
|
|
@ -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 {StaticSymbol} from './static_symbol';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The host of the AotCompiler disconnects the implementation from TypeScript / other language
|
||||||
|
* services and from underlying file systems.
|
||||||
|
*/
|
||||||
|
export interface AotCompilerHost {
|
||||||
|
/**
|
||||||
|
* Return a ModuleMetadata for the given module.
|
||||||
|
* Angular 2 CLI will produce this metadata for a module whenever a .d.ts files is
|
||||||
|
* produced and the module has exported variables or classes with decorators. Module metadata can
|
||||||
|
* also be produced directly from TypeScript sources by using MetadataCollector in tools/metadata.
|
||||||
|
*
|
||||||
|
* @param modulePath is a string identifier for a module as an absolute path.
|
||||||
|
* @returns the metadata for the given module.
|
||||||
|
*/
|
||||||
|
getMetadataFor(modulePath: string): {[key: string]: any}|{[key: string]: any}[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a module name into a file path.
|
||||||
|
*/
|
||||||
|
resolveImportToFile(moduleName: string, containingFile: string): string;
|
||||||
|
}
|
|
@ -7,75 +7,49 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Attribute, Component, ContentChild, ContentChildren, Directive, Host, HostBinding, HostListener, Inject, Injectable, Input, NgModule, Optional, Output, Pipe, Self, SkipSelf, ViewChild, ViewChildren, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
|
import {Attribute, Component, ContentChild, ContentChildren, Directive, Host, HostBinding, HostListener, Inject, Injectable, Input, NgModule, Optional, Output, Pipe, Self, SkipSelf, ViewChild, ViewChildren, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
|
||||||
|
import {AssetUrl} from '../output/path_util';
|
||||||
import {ReflectorReader} from '../private_import_core';
|
import {ReflectorReader} from '../private_import_core';
|
||||||
|
import {AotCompilerHost} from './compiler_host';
|
||||||
import {StaticSymbol} from './static_symbol';
|
import {StaticSymbol} from './static_symbol';
|
||||||
|
|
||||||
const SUPPORTED_SCHEMA_VERSION = 1;
|
const SUPPORTED_SCHEMA_VERSION = 1;
|
||||||
|
const ANGULAR_IMPORT_LOCATIONS = {
|
||||||
/**
|
coreDecorators: '@angular/core/src/metadata',
|
||||||
* The host of the static resolver is expected to be able to provide module metadata in the form of
|
diDecorators: '@angular/core/src/di/metadata',
|
||||||
* ModuleMetadata. Angular 2 CLI will produce this metadata for a module whenever a .d.ts files is
|
diMetadata: '@angular/core/src/di/metadata',
|
||||||
* produced and the module has exported variables or classes with decorators. Module metadata can
|
diOpaqueToken: '@angular/core/src/di/opaque_token',
|
||||||
* also be produced directly from TypeScript sources by using MetadataCollector in tools/metadata.
|
animationMetadata: '@angular/core/src/animation/metadata',
|
||||||
*/
|
provider: '@angular/core/src/di/provider'
|
||||||
export interface StaticReflectorHost {
|
};
|
||||||
/**
|
|
||||||
* Return a ModuleMetadata for the given module.
|
|
||||||
*
|
|
||||||
* @param modulePath is a string identifier for a module as an absolute path.
|
|
||||||
* @returns the metadata for the given module.
|
|
||||||
*/
|
|
||||||
getMetadataFor(modulePath: string): {[key: string]: any}|{[key: string]: any}[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve a symbol from an import statement form, to the file where it is declared.
|
|
||||||
* @param module the location imported from
|
|
||||||
* @param containingFile for relative imports, the path of the file containing the import
|
|
||||||
*/
|
|
||||||
findDeclaration(modulePath: string, symbolName: string, containingFile?: string): StaticSymbol;
|
|
||||||
|
|
||||||
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol;
|
|
||||||
|
|
||||||
angularImportLocations(): {
|
|
||||||
coreDecorators: string,
|
|
||||||
diDecorators: string,
|
|
||||||
diMetadata: string,
|
|
||||||
diOpaqueToken: string,
|
|
||||||
animationMetadata: string,
|
|
||||||
provider: string
|
|
||||||
};
|
|
||||||
|
|
||||||
getCanonicalFileName(fileName: string): string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A static reflector implements enough of the Reflector API that is necessary to compile
|
* A static reflector implements enough of the Reflector API that is necessary to compile
|
||||||
* templates statically.
|
* templates statically.
|
||||||
*/
|
*/
|
||||||
export class StaticReflector implements ReflectorReader {
|
export class StaticReflector implements ReflectorReader {
|
||||||
|
private typeCache = new Map<string, StaticSymbol>();
|
||||||
private annotationCache = new Map<StaticSymbol, any[]>();
|
private annotationCache = new Map<StaticSymbol, any[]>();
|
||||||
private propertyCache = new Map<StaticSymbol, {[key: string]: any}>();
|
private propertyCache = new Map<StaticSymbol, {[key: string]: any}>();
|
||||||
private parameterCache = new Map<StaticSymbol, any[]>();
|
private parameterCache = new Map<StaticSymbol, any[]>();
|
||||||
private metadataCache = new Map<string, {[key: string]: any}>();
|
private metadataCache = new Map<string, {[key: string]: any}>();
|
||||||
private conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>();
|
private conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>();
|
||||||
|
private declarationMap = new Map<string, StaticSymbol>();
|
||||||
private opaqueToken: StaticSymbol;
|
private opaqueToken: StaticSymbol;
|
||||||
|
|
||||||
constructor(private host: StaticReflectorHost) { this.initializeConversionMap(); }
|
constructor(private host: AotCompilerHost) { this.initializeConversionMap(); }
|
||||||
|
|
||||||
importUri(typeOrFunc: StaticSymbol): string {
|
importUri(typeOrFunc: StaticSymbol): string {
|
||||||
const staticSymbol = this.host.findDeclaration(typeOrFunc.filePath, typeOrFunc.name, '');
|
const staticSymbol = this.findDeclaration(typeOrFunc.filePath, typeOrFunc.name, '');
|
||||||
return staticSymbol ? staticSymbol.filePath : null;
|
return staticSymbol ? staticSymbol.filePath : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveIdentifier(name: string, moduleUrl: string, runtime: any): any {
|
resolveIdentifier(name: string, moduleUrl: string, runtime: any): any {
|
||||||
return this.host.findDeclaration(moduleUrl, name, '');
|
return this.findDeclaration(moduleUrl, name, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveEnum(enumIdentifier: any, name: string): any {
|
resolveEnum(enumIdentifier: any, name: string): any {
|
||||||
const staticSymbol: StaticSymbol = enumIdentifier;
|
const staticSymbol: StaticSymbol = enumIdentifier;
|
||||||
return this.host.getStaticSymbol(staticSymbol.filePath, staticSymbol.name, [name]);
|
return this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name, [name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public annotations(type: StaticSymbol): any[] {
|
public annotations(type: StaticSymbol): any[] {
|
||||||
|
@ -172,59 +146,156 @@ export class StaticReflector implements ReflectorReader {
|
||||||
|
|
||||||
private initializeConversionMap(): void {
|
private initializeConversionMap(): void {
|
||||||
const {coreDecorators, diDecorators, diMetadata, diOpaqueToken, animationMetadata, provider} =
|
const {coreDecorators, diDecorators, diMetadata, diOpaqueToken, animationMetadata, provider} =
|
||||||
this.host.angularImportLocations();
|
ANGULAR_IMPORT_LOCATIONS;
|
||||||
this.opaqueToken = this.host.findDeclaration(diOpaqueToken, 'OpaqueToken');
|
this.opaqueToken = this.findDeclaration(diOpaqueToken, 'OpaqueToken');
|
||||||
|
|
||||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Host'), Host);
|
this.registerDecoratorOrConstructor(this.findDeclaration(diDecorators, 'Host'), Host);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.host.findDeclaration(diDecorators, 'Injectable'), Injectable);
|
this.findDeclaration(diDecorators, 'Injectable'), Injectable);
|
||||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Self'), Self);
|
this.registerDecoratorOrConstructor(this.findDeclaration(diDecorators, 'Self'), Self);
|
||||||
|
this.registerDecoratorOrConstructor(this.findDeclaration(diDecorators, 'SkipSelf'), SkipSelf);
|
||||||
|
this.registerDecoratorOrConstructor(this.findDeclaration(diDecorators, 'Inject'), Inject);
|
||||||
|
this.registerDecoratorOrConstructor(this.findDeclaration(diDecorators, 'Optional'), Optional);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.host.findDeclaration(diDecorators, 'SkipSelf'), SkipSelf);
|
this.findDeclaration(coreDecorators, 'Attribute'), Attribute);
|
||||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Inject'), Inject);
|
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.host.findDeclaration(diDecorators, 'Optional'), Optional);
|
this.findDeclaration(coreDecorators, 'ContentChild'), ContentChild);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.host.findDeclaration(coreDecorators, 'Attribute'), Attribute);
|
this.findDeclaration(coreDecorators, 'ContentChildren'), ContentChildren);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.host.findDeclaration(coreDecorators, 'ContentChild'), ContentChild);
|
this.findDeclaration(coreDecorators, 'ViewChild'), ViewChild);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.host.findDeclaration(coreDecorators, 'ContentChildren'), ContentChildren);
|
this.findDeclaration(coreDecorators, 'ViewChildren'), ViewChildren);
|
||||||
|
this.registerDecoratorOrConstructor(this.findDeclaration(coreDecorators, 'Input'), Input);
|
||||||
|
this.registerDecoratorOrConstructor(this.findDeclaration(coreDecorators, 'Output'), Output);
|
||||||
|
this.registerDecoratorOrConstructor(this.findDeclaration(coreDecorators, 'Pipe'), Pipe);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.host.findDeclaration(coreDecorators, 'ViewChild'), ViewChild);
|
this.findDeclaration(coreDecorators, 'HostBinding'), HostBinding);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.host.findDeclaration(coreDecorators, 'ViewChildren'), ViewChildren);
|
this.findDeclaration(coreDecorators, 'HostListener'), HostListener);
|
||||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Input'), Input);
|
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.host.findDeclaration(coreDecorators, 'Output'), Output);
|
this.findDeclaration(coreDecorators, 'Directive'), Directive);
|
||||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Pipe'), Pipe);
|
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.host.findDeclaration(coreDecorators, 'HostBinding'), HostBinding);
|
this.findDeclaration(coreDecorators, 'Component'), Component);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(this.findDeclaration(coreDecorators, 'NgModule'), NgModule);
|
||||||
this.host.findDeclaration(coreDecorators, 'HostListener'), HostListener);
|
|
||||||
this.registerDecoratorOrConstructor(
|
|
||||||
this.host.findDeclaration(coreDecorators, 'Directive'), Directive);
|
|
||||||
this.registerDecoratorOrConstructor(
|
|
||||||
this.host.findDeclaration(coreDecorators, 'Component'), Component);
|
|
||||||
this.registerDecoratorOrConstructor(
|
|
||||||
this.host.findDeclaration(coreDecorators, 'NgModule'), NgModule);
|
|
||||||
|
|
||||||
// Note: Some metadata classes can be used directly with Provider.deps.
|
// Note: Some metadata classes can be used directly with Provider.deps.
|
||||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'Host'), Host);
|
this.registerDecoratorOrConstructor(this.findDeclaration(diMetadata, 'Host'), Host);
|
||||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'Self'), Self);
|
this.registerDecoratorOrConstructor(this.findDeclaration(diMetadata, 'Self'), Self);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(this.findDeclaration(diMetadata, 'SkipSelf'), SkipSelf);
|
||||||
this.host.findDeclaration(diMetadata, 'SkipSelf'), SkipSelf);
|
this.registerDecoratorOrConstructor(this.findDeclaration(diMetadata, 'Optional'), Optional);
|
||||||
this.registerDecoratorOrConstructor(
|
|
||||||
this.host.findDeclaration(diMetadata, 'Optional'), Optional);
|
|
||||||
|
|
||||||
this.registerFunction(this.host.findDeclaration(animationMetadata, 'trigger'), trigger);
|
this.registerFunction(this.findDeclaration(animationMetadata, 'trigger'), trigger);
|
||||||
this.registerFunction(this.host.findDeclaration(animationMetadata, 'state'), state);
|
this.registerFunction(this.findDeclaration(animationMetadata, 'state'), state);
|
||||||
this.registerFunction(this.host.findDeclaration(animationMetadata, 'transition'), transition);
|
this.registerFunction(this.findDeclaration(animationMetadata, 'transition'), transition);
|
||||||
this.registerFunction(this.host.findDeclaration(animationMetadata, 'style'), style);
|
this.registerFunction(this.findDeclaration(animationMetadata, 'style'), style);
|
||||||
this.registerFunction(this.host.findDeclaration(animationMetadata, 'animate'), animate);
|
this.registerFunction(this.findDeclaration(animationMetadata, 'animate'), animate);
|
||||||
this.registerFunction(this.host.findDeclaration(animationMetadata, 'keyframes'), keyframes);
|
this.registerFunction(this.findDeclaration(animationMetadata, 'keyframes'), keyframes);
|
||||||
this.registerFunction(this.host.findDeclaration(animationMetadata, 'sequence'), sequence);
|
this.registerFunction(this.findDeclaration(animationMetadata, 'sequence'), sequence);
|
||||||
this.registerFunction(this.host.findDeclaration(animationMetadata, 'group'), group);
|
this.registerFunction(this.findDeclaration(animationMetadata, 'group'), group);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getStaticSymbol produces a Type whose metadata is known but whose implementation is not loaded.
|
||||||
|
* All types passed to the StaticResolver should be pseudo-types returned by this method.
|
||||||
|
*
|
||||||
|
* @param declarationFile the absolute path of the file where the symbol is declared
|
||||||
|
* @param name the name of the type.
|
||||||
|
*/
|
||||||
|
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol {
|
||||||
|
const memberSuffix = members ? `.${ members.join('.')}` : '';
|
||||||
|
const key = `"${declarationFile}".${name}${memberSuffix}`;
|
||||||
|
let result = this.typeCache.get(key);
|
||||||
|
if (!result) {
|
||||||
|
result = new StaticSymbol(declarationFile, name, members);
|
||||||
|
this.typeCache.set(key, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private normalizeAssetUrl(url: string): string {
|
||||||
|
const assetUrl = AssetUrl.parse(url);
|
||||||
|
return assetUrl ? `${assetUrl.packageName}@${assetUrl.modulePath}` : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private resolveExportedSymbol(filePath: string, symbolName: string): StaticSymbol {
|
||||||
|
const resolveModule = (moduleName: string): string => {
|
||||||
|
const resolvedModulePath = this.host.resolveImportToFile(moduleName, filePath);
|
||||||
|
if (!resolvedModulePath) {
|
||||||
|
throw new Error(`Could not resolve module '${moduleName}' relative to file ${filePath}`);
|
||||||
|
}
|
||||||
|
return resolvedModulePath;
|
||||||
|
};
|
||||||
|
const metadata = this.getModuleMetadata(filePath);
|
||||||
|
if (metadata) {
|
||||||
|
// If we have metadata for the symbol, this is the original exporting location.
|
||||||
|
if (metadata['metadata'][symbolName]) {
|
||||||
|
return this.getStaticSymbol(filePath, symbolName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no, try to find the symbol in one of the re-export location
|
||||||
|
if (metadata['exports']) {
|
||||||
|
// Try and find the symbol in the list of explicitly re-exported symbols.
|
||||||
|
for (const moduleExport of metadata['exports']) {
|
||||||
|
if (moduleExport.export) {
|
||||||
|
const exportSymbol = moduleExport.export.find((symbol: any) => {
|
||||||
|
if (typeof symbol === 'string') {
|
||||||
|
return symbol == symbolName;
|
||||||
|
} else {
|
||||||
|
return symbol.as == symbolName;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (exportSymbol) {
|
||||||
|
let symName = symbolName;
|
||||||
|
if (typeof exportSymbol !== 'string') {
|
||||||
|
symName = exportSymbol.name;
|
||||||
|
}
|
||||||
|
return this.resolveExportedSymbol(resolveModule(moduleExport.from), symName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find the symbol via export * directives.
|
||||||
|
for (const moduleExport of metadata['exports']) {
|
||||||
|
if (!moduleExport.export) {
|
||||||
|
const resolvedModule = resolveModule(moduleExport.from);
|
||||||
|
const candidateSymbol = this.resolveExportedSymbol(resolvedModule, symbolName);
|
||||||
|
if (candidateSymbol) return candidateSymbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
findDeclaration(module: string, symbolName: string, containingFile?: string): StaticSymbol {
|
||||||
|
const cacheKey = `${module}|${symbolName}|${containingFile}`;
|
||||||
|
let symbol = this.declarationMap.get(cacheKey);
|
||||||
|
if (symbol) {
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const assetUrl = this.normalizeAssetUrl(module);
|
||||||
|
if (assetUrl) {
|
||||||
|
module = assetUrl;
|
||||||
|
}
|
||||||
|
const filePath = this.host.resolveImportToFile(module, containingFile);
|
||||||
|
|
||||||
|
if (!filePath) {
|
||||||
|
// If the file cannot be found the module is probably referencing a declared module
|
||||||
|
// for which there is no disambiguating file and we also don't need to track
|
||||||
|
// re-exports. Just use the module name.
|
||||||
|
return this.getStaticSymbol(module, symbolName);
|
||||||
|
}
|
||||||
|
|
||||||
|
let symbol = this.resolveExportedSymbol(filePath, symbolName) ||
|
||||||
|
this.getStaticSymbol(filePath, symbolName);
|
||||||
|
this.declarationMap.set(cacheKey, symbol);
|
||||||
|
return symbol;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`can't resolve module ${module} from ${containingFile}`);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
|
@ -237,10 +308,10 @@ export class StaticReflector implements ReflectorReader {
|
||||||
function resolveReference(context: StaticSymbol, expression: any): StaticSymbol {
|
function resolveReference(context: StaticSymbol, expression: any): StaticSymbol {
|
||||||
let staticSymbol: StaticSymbol;
|
let staticSymbol: StaticSymbol;
|
||||||
if (expression['module']) {
|
if (expression['module']) {
|
||||||
staticSymbol = _this.host.findDeclaration(
|
staticSymbol =
|
||||||
expression['module'], expression['name'], context.filePath);
|
_this.findDeclaration(expression['module'], expression['name'], context.filePath);
|
||||||
} else {
|
} else {
|
||||||
staticSymbol = _this.host.getStaticSymbol(context.filePath, expression['name']);
|
staticSymbol = _this.getStaticSymbol(context.filePath, expression['name']);
|
||||||
}
|
}
|
||||||
return staticSymbol;
|
return staticSymbol;
|
||||||
}
|
}
|
||||||
|
@ -449,8 +520,7 @@ export class StaticReflector implements ReflectorReader {
|
||||||
const members = selectTarget.members ?
|
const members = selectTarget.members ?
|
||||||
(selectTarget.members as string[]).concat(member) :
|
(selectTarget.members as string[]).concat(member) :
|
||||||
[member];
|
[member];
|
||||||
return _this.host.getStaticSymbol(
|
return _this.getStaticSymbol(selectTarget.filePath, selectTarget.name, members);
|
||||||
selectTarget.filePath, selectTarget.name, members);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const member = simplify(expression['member']);
|
const member = simplify(expression['member']);
|
||||||
|
@ -485,10 +555,10 @@ export class StaticReflector implements ReflectorReader {
|
||||||
// Determine if the function is a built-in conversion
|
// Determine if the function is a built-in conversion
|
||||||
let target = expression['expression'];
|
let target = expression['expression'];
|
||||||
if (target['module']) {
|
if (target['module']) {
|
||||||
staticSymbol = _this.host.findDeclaration(
|
staticSymbol =
|
||||||
target['module'], target['name'], context.filePath);
|
_this.findDeclaration(target['module'], target['name'], context.filePath);
|
||||||
} else {
|
} else {
|
||||||
staticSymbol = _this.host.getStaticSymbol(context.filePath, target['name']);
|
staticSymbol = _this.getStaticSymbol(context.filePath, target['name']);
|
||||||
}
|
}
|
||||||
let converter = _this.conversionMap.get(staticSymbol);
|
let converter = _this.conversionMap.get(staticSymbol);
|
||||||
if (converter) {
|
if (converter) {
|
||||||
|
|
|
@ -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 {StaticReflector, StaticReflectorHost, StaticSymbol} from '@angular/compiler';
|
import {AotCompilerHost, StaticReflector, StaticSymbol} from '@angular/compiler';
|
||||||
import {HostListener, Inject, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
|
import {HostListener, Inject, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
|
||||||
import {MetadataCollector} from '@angular/tsc-wrapped';
|
import {MetadataCollector} from '@angular/tsc-wrapped';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
@ -18,11 +18,11 @@ const TS_EXT = /(^.|(?!\.d)..)\.ts$/;
|
||||||
|
|
||||||
describe('StaticReflector', () => {
|
describe('StaticReflector', () => {
|
||||||
const noContext = new StaticSymbol('', '');
|
const noContext = new StaticSymbol('', '');
|
||||||
let host: StaticReflectorHost;
|
let host: AotCompilerHost;
|
||||||
let reflector: StaticReflector;
|
let reflector: StaticReflector;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
host = new MockReflectorHost();
|
host = new MockAotCompilerHost();
|
||||||
reflector = new StaticReflector(host);
|
reflector = new StaticReflector(host);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ describe('StaticReflector', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
it('should get annotations for NgFor', () => {
|
it('should get annotations for NgFor', () => {
|
||||||
const NgFor = host.findDeclaration('angular2/src/common/directives/ng_for', 'NgFor');
|
const NgFor = reflector.findDeclaration('@angular/common/src/directives/ng_for', 'NgFor');
|
||||||
const annotations = reflector.annotations(NgFor);
|
const annotations = reflector.annotations(NgFor);
|
||||||
expect(annotations.length).toEqual(1);
|
expect(annotations.length).toEqual(1);
|
||||||
const annotation = annotations[0];
|
const annotation = annotations[0];
|
||||||
|
@ -40,15 +40,15 @@ describe('StaticReflector', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get constructor for NgFor', () => {
|
it('should get constructor for NgFor', () => {
|
||||||
const NgFor = host.findDeclaration('angular2/src/common/directives/ng_for', 'NgFor');
|
const NgFor = reflector.findDeclaration('@angular/common/src/directives/ng_for', 'NgFor');
|
||||||
const ViewContainerRef =
|
const ViewContainerRef = reflector.findDeclaration(
|
||||||
host.findDeclaration('angular2/src/core/linker/view_container_ref', 'ViewContainerRef');
|
'@angular/core/src/linker/view_container_ref', 'ViewContainerRef');
|
||||||
const TemplateRef =
|
const TemplateRef =
|
||||||
host.findDeclaration('angular2/src/core/linker/template_ref', 'TemplateRef');
|
reflector.findDeclaration('@angular/core/src/linker/template_ref', 'TemplateRef');
|
||||||
const IterableDiffers = host.findDeclaration(
|
const IterableDiffers = reflector.findDeclaration(
|
||||||
'angular2/src/core/change_detection/differs/iterable_differs', 'IterableDiffers');
|
'@angular/core/src/change_detection/differs/iterable_differs', 'IterableDiffers');
|
||||||
const ChangeDetectorRef = host.findDeclaration(
|
const ChangeDetectorRef = reflector.findDeclaration(
|
||||||
'angular2/src/core/change_detection/change_detector_ref', 'ChangeDetectorRef');
|
'@angular/core/src/change_detection/change_detector_ref', 'ChangeDetectorRef');
|
||||||
|
|
||||||
const parameters = reflector.parameters(NgFor);
|
const parameters = reflector.parameters(NgFor);
|
||||||
expect(parameters).toEqual([
|
expect(parameters).toEqual([
|
||||||
|
@ -58,7 +58,7 @@ describe('StaticReflector', () => {
|
||||||
|
|
||||||
it('should get annotations for HeroDetailComponent', () => {
|
it('should get annotations for HeroDetailComponent', () => {
|
||||||
const HeroDetailComponent =
|
const HeroDetailComponent =
|
||||||
host.findDeclaration('src/app/hero-detail.component', 'HeroDetailComponent');
|
reflector.findDeclaration('src/app/hero-detail.component', 'HeroDetailComponent');
|
||||||
const annotations = reflector.annotations(HeroDetailComponent);
|
const annotations = reflector.annotations(HeroDetailComponent);
|
||||||
expect(annotations.length).toEqual(1);
|
expect(annotations.length).toEqual(1);
|
||||||
const annotation = annotations[0];
|
const annotation = annotations[0];
|
||||||
|
@ -74,40 +74,39 @@ describe('StaticReflector', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw and exception for unsupported metadata versions', () => {
|
it('should throw and exception for unsupported metadata versions', () => {
|
||||||
const e = host.findDeclaration('src/version-error', 'e');
|
expect(() => reflector.findDeclaration('src/version-error', 'e'))
|
||||||
expect(() => reflector.annotations(e))
|
|
||||||
.toThrow(new Error(
|
.toThrow(new Error(
|
||||||
'Metadata version mismatch for module /tmp/src/version-error.d.ts, found version 100, expected 1'));
|
'Metadata version mismatch for module /tmp/src/version-error.d.ts, found version 100, expected 1'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get and empty annotation list for an unknown class', () => {
|
it('should get and empty annotation list for an unknown class', () => {
|
||||||
const UnknownClass = host.findDeclaration('src/app/app.component', 'UnknownClass');
|
const UnknownClass = reflector.findDeclaration('src/app/app.component', 'UnknownClass');
|
||||||
const annotations = reflector.annotations(UnknownClass);
|
const annotations = reflector.annotations(UnknownClass);
|
||||||
expect(annotations).toEqual([]);
|
expect(annotations).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get propMetadata for HeroDetailComponent', () => {
|
it('should get propMetadata for HeroDetailComponent', () => {
|
||||||
const HeroDetailComponent =
|
const HeroDetailComponent =
|
||||||
host.findDeclaration('src/app/hero-detail.component', 'HeroDetailComponent');
|
reflector.findDeclaration('src/app/hero-detail.component', 'HeroDetailComponent');
|
||||||
const props = reflector.propMetadata(HeroDetailComponent);
|
const props = reflector.propMetadata(HeroDetailComponent);
|
||||||
expect(props['hero']).toBeTruthy();
|
expect(props['hero']).toBeTruthy();
|
||||||
expect(props['onMouseOver']).toEqual([new HostListener('mouseover', ['$event'])]);
|
expect(props['onMouseOver']).toEqual([new HostListener('mouseover', ['$event'])]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get an empty object from propMetadata for an unknown class', () => {
|
it('should get an empty object from propMetadata for an unknown class', () => {
|
||||||
const UnknownClass = host.findDeclaration('src/app/app.component', 'UnknownClass');
|
const UnknownClass = reflector.findDeclaration('src/app/app.component', 'UnknownClass');
|
||||||
const properties = reflector.propMetadata(UnknownClass);
|
const properties = reflector.propMetadata(UnknownClass);
|
||||||
expect(properties).toEqual({});
|
expect(properties).toEqual({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get empty parameters list for an unknown class ', () => {
|
it('should get empty parameters list for an unknown class ', () => {
|
||||||
const UnknownClass = host.findDeclaration('src/app/app.component', 'UnknownClass');
|
const UnknownClass = reflector.findDeclaration('src/app/app.component', 'UnknownClass');
|
||||||
const parameters = reflector.parameters(UnknownClass);
|
const parameters = reflector.parameters(UnknownClass);
|
||||||
expect(parameters).toEqual([]);
|
expect(parameters).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should provide context for errors reported by the collector', () => {
|
it('should provide context for errors reported by the collector', () => {
|
||||||
const SomeClass = host.findDeclaration('src/error-reporting', 'SomeClass');
|
const SomeClass = reflector.findDeclaration('src/error-reporting', 'SomeClass');
|
||||||
expect(() => reflector.annotations(SomeClass))
|
expect(() => reflector.annotations(SomeClass))
|
||||||
.toThrow(new Error(
|
.toThrow(new Error(
|
||||||
'Error encountered resolving symbol values statically. A reasonable error message (position 13:34 in the original .ts file), resolving symbol ErrorSym in /tmp/src/error-references.d.ts, resolving symbol Link2 in /tmp/src/error-references.d.ts, resolving symbol Link1 in /tmp/src/error-references.d.ts, resolving symbol SomeClass in /tmp/src/error-reporting.d.ts, resolving symbol SomeClass in /tmp/src/error-reporting.d.ts'));
|
'Error encountered resolving symbol values statically. A reasonable error message (position 13:34 in the original .ts file), resolving symbol ErrorSym in /tmp/src/error-references.d.ts, resolving symbol Link2 in /tmp/src/error-references.d.ts, resolving symbol Link1 in /tmp/src/error-references.d.ts, resolving symbol SomeClass in /tmp/src/error-reporting.d.ts, resolving symbol SomeClass in /tmp/src/error-reporting.d.ts'));
|
||||||
|
@ -308,14 +307,14 @@ describe('StaticReflector', () => {
|
||||||
expect(simplify(
|
expect(simplify(
|
||||||
new StaticSymbol('/src/cases', ''),
|
new StaticSymbol('/src/cases', ''),
|
||||||
({__symbolic: 'reference', module: './extern', name: 'nonExisting'})))
|
({__symbolic: 'reference', module: './extern', name: 'nonExisting'})))
|
||||||
.toEqual(host.getStaticSymbol('/src/extern.d.ts', 'nonExisting'));
|
.toEqual(reflector.getStaticSymbol('/src/extern.d.ts', 'nonExisting'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should simplify a function reference as a static symbol', () => {
|
it('should simplify a function reference as a static symbol', () => {
|
||||||
expect(simplify(
|
expect(simplify(
|
||||||
new StaticSymbol('/src/cases', 'myFunction'),
|
new StaticSymbol('/src/cases', 'myFunction'),
|
||||||
({__symbolic: 'function', parameters: ['a'], value: []})))
|
({__symbolic: 'function', parameters: ['a'], value: []})))
|
||||||
.toEqual(host.getStaticSymbol('/src/cases', 'myFunction'));
|
.toEqual(reflector.getStaticSymbol('/src/cases', 'myFunction'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should simplify values initialized with a function call', () => {
|
it('should simplify values initialized with a function call', () => {
|
||||||
|
@ -406,35 +405,35 @@ describe('StaticReflector', () => {
|
||||||
|
|
||||||
it('should be able to get metadata for a class containing a custom decorator', () => {
|
it('should be able to get metadata for a class containing a custom decorator', () => {
|
||||||
const props = reflector.propMetadata(
|
const props = reflector.propMetadata(
|
||||||
host.getStaticSymbol('/tmp/src/custom-decorator-reference.ts', 'Foo'));
|
reflector.getStaticSymbol('/tmp/src/custom-decorator-reference.ts', 'Foo'));
|
||||||
expect(props).toEqual({foo: []});
|
expect(props).toEqual({foo: []});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should read ctor parameters with forwardRef', () => {
|
it('should read ctor parameters with forwardRef', () => {
|
||||||
const src = '/tmp/src/forward-ref.ts';
|
const src = '/tmp/src/forward-ref.ts';
|
||||||
const dep = host.getStaticSymbol(src, 'Dep');
|
const dep = reflector.getStaticSymbol(src, 'Dep');
|
||||||
const props = reflector.parameters(host.getStaticSymbol(src, 'Forward'));
|
const props = reflector.parameters(reflector.getStaticSymbol(src, 'Forward'));
|
||||||
expect(props).toEqual([[dep, new Inject(dep)]]);
|
expect(props).toEqual([[dep, new Inject(dep)]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should report an error for invalid function calls', () => {
|
it('should report an error for invalid function calls', () => {
|
||||||
expect(
|
expect(
|
||||||
() =>
|
() => reflector.annotations(
|
||||||
reflector.annotations(host.getStaticSymbol('/tmp/src/invalid-calls.ts', 'MyComponent')))
|
reflector.getStaticSymbol('/tmp/src/invalid-calls.ts', 'MyComponent')))
|
||||||
.toThrow(new Error(
|
.toThrow(new Error(
|
||||||
`Error encountered resolving symbol values statically. Calling function 'someFunction', function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol MyComponent in /tmp/src/invalid-calls.ts, resolving symbol MyComponent in /tmp/src/invalid-calls.ts`));
|
`Error encountered resolving symbol values statically. Calling function 'someFunction', function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol MyComponent in /tmp/src/invalid-calls.ts, resolving symbol MyComponent in /tmp/src/invalid-calls.ts`));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to get metadata for a class containing a static method call', () => {
|
it('should be able to get metadata for a class containing a static method call', () => {
|
||||||
const annotations = reflector.annotations(
|
const annotations = reflector.annotations(
|
||||||
host.getStaticSymbol('/tmp/src/static-method-call.ts', 'MyComponent'));
|
reflector.getStaticSymbol('/tmp/src/static-method-call.ts', 'MyComponent'));
|
||||||
expect(annotations.length).toBe(1);
|
expect(annotations.length).toBe(1);
|
||||||
expect(annotations[0].providers).toEqual({provider: 'a', useValue: 100});
|
expect(annotations[0].providers).toEqual({provider: 'a', useValue: 100});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to get metadata for a class containing a static field reference', () => {
|
it('should be able to get metadata for a class containing a static field reference', () => {
|
||||||
const annotations =
|
const annotations = reflector.annotations(
|
||||||
reflector.annotations(host.getStaticSymbol('/tmp/src/static-field-reference.ts', 'Foo'));
|
reflector.getStaticSymbol('/tmp/src/static-field-reference.ts', 'Foo'));
|
||||||
expect(annotations.length).toBe(1);
|
expect(annotations.length).toBe(1);
|
||||||
expect(annotations[0].providers).toEqual([{provider: 'a', useValue: 'Some string'}]);
|
expect(annotations[0].providers).toEqual([{provider: 'a', useValue: 'Some string'}]);
|
||||||
});
|
});
|
||||||
|
@ -442,7 +441,7 @@ describe('StaticReflector', () => {
|
||||||
it('should be able to get the metadata for a class calling a method with a conditional expression',
|
it('should be able to get the metadata for a class calling a method with a conditional expression',
|
||||||
() => {
|
() => {
|
||||||
const annotations = reflector.annotations(
|
const annotations = reflector.annotations(
|
||||||
host.getStaticSymbol('/tmp/src/static-method-call.ts', 'MyCondComponent'));
|
reflector.getStaticSymbol('/tmp/src/static-method-call.ts', 'MyCondComponent'));
|
||||||
expect(annotations.length).toBe(1);
|
expect(annotations.length).toBe(1);
|
||||||
expect(annotations[0].providers).toEqual([
|
expect(annotations[0].providers).toEqual([
|
||||||
[{provider: 'a', useValue: '1'}], [{provider: 'a', useValue: '2'}]
|
[{provider: 'a', useValue: '1'}], [{provider: 'a', useValue: '2'}]
|
||||||
|
@ -452,50 +451,68 @@ describe('StaticReflector', () => {
|
||||||
it('should be able to get the metadata for a class calling a method with default parameters',
|
it('should be able to get the metadata for a class calling a method with default parameters',
|
||||||
() => {
|
() => {
|
||||||
const annotations = reflector.annotations(
|
const annotations = reflector.annotations(
|
||||||
host.getStaticSymbol('/tmp/src/static-method-call.ts', 'MyDefaultsComponent'));
|
reflector.getStaticSymbol('/tmp/src/static-method-call.ts', 'MyDefaultsComponent'));
|
||||||
expect(annotations.length).toBe(1);
|
expect(annotations.length).toBe(1);
|
||||||
expect(annotations[0].providers).toEqual([['a', true, false]]);
|
expect(annotations[0].providers).toEqual([['a', true, false]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to get metadata with a reference to a static method', () => {
|
it('should be able to get metadata with a reference to a static method', () => {
|
||||||
const annotations = reflector.annotations(
|
const annotations = reflector.annotations(
|
||||||
host.getStaticSymbol('/tmp/src/static-method-ref.ts', 'MethodReference'));
|
reflector.getStaticSymbol('/tmp/src/static-method-ref.ts', 'MethodReference'));
|
||||||
expect(annotations.length).toBe(1);
|
expect(annotations.length).toBe(1);
|
||||||
expect(annotations[0].providers[0].useValue.members[0]).toEqual('staticMethod');
|
expect(annotations[0].providers[0].useValue.members[0]).toEqual('staticMethod');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should be able to produce a symbol for an exported symbol', () => {
|
||||||
|
expect(reflector.findDeclaration('@angular/router', 'foo', 'main.ts')).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to produce a symbol for values space only reference', () => {
|
||||||
|
expect(reflector.findDeclaration('@angular/router/src/providers', 'foo', 'main.ts'))
|
||||||
|
.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be produce the same symbol if asked twice', () => {
|
||||||
|
const foo1 = reflector.getStaticSymbol('main.ts', 'foo');
|
||||||
|
const foo2 = reflector.getStaticSymbol('main.ts', 'foo');
|
||||||
|
expect(foo1).toBe(foo2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to produce a symbol for a module with no file',
|
||||||
|
() => { expect(reflector.getStaticSymbol('angularjs', 'SomeAngularSymbol')).toBeDefined(); });
|
||||||
|
|
||||||
|
it('should be able to trace a named export', () => {
|
||||||
|
const symbol = reflector.findDeclaration('./reexport/reexport', 'One', '/tmp/src/main.ts');
|
||||||
|
expect(symbol.name).toEqual('One');
|
||||||
|
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin1.d.ts');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to trace a renamed export', () => {
|
||||||
|
const symbol = reflector.findDeclaration('./reexport/reexport', 'Four', '/tmp/src/main.ts');
|
||||||
|
expect(symbol.name).toEqual('Three');
|
||||||
|
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin1.d.ts');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to trace an export * export', () => {
|
||||||
|
const symbol = reflector.findDeclaration('./reexport/reexport', 'Five', '/tmp/src/main.ts');
|
||||||
|
expect(symbol.name).toEqual('Five');
|
||||||
|
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin5.d.ts');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to trace a multi-level re-export', () => {
|
||||||
|
const symbol = reflector.findDeclaration('./reexport/reexport', 'Thirty', '/tmp/src/main.ts');
|
||||||
|
expect(symbol.name).toEqual('Thirty');
|
||||||
|
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin30.d.ts');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
class MockReflectorHost implements StaticReflectorHost {
|
class MockAotCompilerHost implements AotCompilerHost {
|
||||||
private staticTypeCache = new Map<string, StaticSymbol>();
|
|
||||||
private collector = new MetadataCollector();
|
private collector = new MetadataCollector();
|
||||||
|
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
angularImportLocations() {
|
|
||||||
return {
|
|
||||||
coreDecorators: 'angular2/src/core/metadata',
|
|
||||||
diDecorators: 'angular2/src/core/di/metadata',
|
|
||||||
diMetadata: 'angular2/src/core/di/metadata',
|
|
||||||
diOpaqueToken: 'angular2/src/core/di/opaque_token',
|
|
||||||
animationMetadata: 'angular2/src/core/animation/metadata',
|
|
||||||
provider: 'angular2/src/core/di/provider'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
getCanonicalFileName(fileName: string): string { return fileName; }
|
|
||||||
|
|
||||||
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol {
|
|
||||||
const cacheKey = `${declarationFile}:${name}${members?'.'+members.join('.'):''}`;
|
|
||||||
let result = this.staticTypeCache.get(cacheKey);
|
|
||||||
if (!result) {
|
|
||||||
result = new StaticSymbol(declarationFile, name, members);
|
|
||||||
this.staticTypeCache.set(cacheKey, result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// In tests, assume that symbols are not re-exported
|
// In tests, assume that symbols are not re-exported
|
||||||
findDeclaration(modulePath: string, symbolName: string, containingFile?: string): StaticSymbol {
|
resolveImportToFile(modulePath: string, containingFile?: string): string {
|
||||||
function splitPath(path: string): string[] { return path.split(/\/|\\/g); }
|
function splitPath(path: string): string[] { return path.split(/\/|\\/g); }
|
||||||
|
|
||||||
function resolvePath(pathParts: string[]): string {
|
function resolvePath(pathParts: string[]): string {
|
||||||
|
@ -530,16 +547,16 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
const baseName = pathTo(containingFile, modulePath);
|
const baseName = pathTo(containingFile, modulePath);
|
||||||
const tsName = baseName + '.ts';
|
const tsName = baseName + '.ts';
|
||||||
if (this.getMetadataFor(tsName)) {
|
if (this.getMetadataFor(tsName)) {
|
||||||
return this.getStaticSymbol(tsName, symbolName);
|
return tsName;
|
||||||
}
|
}
|
||||||
return this.getStaticSymbol(baseName + '.d.ts', symbolName);
|
return baseName + '.d.ts';
|
||||||
}
|
}
|
||||||
return this.getStaticSymbol('/tmp/' + modulePath + '.d.ts', symbolName);
|
return '/tmp/' + modulePath + '.d.ts';
|
||||||
}
|
}
|
||||||
|
|
||||||
getMetadataFor(moduleId: string): any {
|
getMetadataFor(moduleId: string): any {
|
||||||
const data: {[key: string]: any} = {
|
const data: {[key: string]: any} = {
|
||||||
'/tmp/angular2/src/common/forms-deprecated/directives.d.ts': [{
|
'/tmp/@angular/common/src/forms-deprecated/directives.d.ts': [{
|
||||||
'__symbolic': 'module',
|
'__symbolic': 'module',
|
||||||
'version': 1,
|
'version': 1,
|
||||||
'metadata': {
|
'metadata': {
|
||||||
|
@ -547,12 +564,12 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
{
|
{
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'name': 'NgFor',
|
'name': 'NgFor',
|
||||||
'module': 'angular2/src/common/directives/ng_for'
|
'module': '@angular/common/src/directives/ng_for'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
'/tmp/angular2/src/common/directives/ng_for.d.ts': {
|
'/tmp/@angular/common/src/directives/ng_for.d.ts': {
|
||||||
'__symbolic': 'module',
|
'__symbolic': 'module',
|
||||||
'version': 1,
|
'version': 1,
|
||||||
'metadata': {
|
'metadata': {
|
||||||
|
@ -564,7 +581,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'name': 'Directive',
|
'name': 'Directive',
|
||||||
'module': '../../core/metadata'
|
'module': '@angular/core/src/metadata'
|
||||||
},
|
},
|
||||||
'arguments': [
|
'arguments': [
|
||||||
{
|
{
|
||||||
|
@ -581,22 +598,22 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
'parameters': [
|
'parameters': [
|
||||||
{
|
{
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'module': '../../core/linker/view_container_ref',
|
'module': '@angular/core/src/linker/view_container_ref',
|
||||||
'name': 'ViewContainerRef'
|
'name': 'ViewContainerRef'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'module': '../../core/linker/template_ref',
|
'module': '@angular/core/src/linker/template_ref',
|
||||||
'name': 'TemplateRef'
|
'name': 'TemplateRef'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'module': '../../core/change_detection/differs/iterable_differs',
|
'module': '@angular/core/src/change_detection/differs/iterable_differs',
|
||||||
'name': 'IterableDiffers'
|
'name': 'IterableDiffers'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'module': '../../core/change_detection/change_detector_ref',
|
'module': '@angular/core/src/change_detection/change_detector_ref',
|
||||||
'name': 'ChangeDetectorRef'
|
'name': 'ChangeDetectorRef'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -606,13 +623,13 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'/tmp/angular2/src/core/linker/view_container_ref.d.ts':
|
'/tmp/@angular/core/src/linker/view_container_ref.d.ts':
|
||||||
{version: 1, 'metadata': {'ViewContainerRef': {'__symbolic': 'class'}}},
|
{version: 1, 'metadata': {'ViewContainerRef': {'__symbolic': 'class'}}},
|
||||||
'/tmp/angular2/src/core/linker/template_ref.d.ts':
|
'/tmp/@angular/core/src/linker/template_ref.d.ts':
|
||||||
{version: 1, 'module': './template_ref', 'metadata': {'TemplateRef': {'__symbolic': 'class'}}},
|
{version: 1, 'module': './template_ref', 'metadata': {'TemplateRef': {'__symbolic': 'class'}}},
|
||||||
'/tmp/angular2/src/core/change_detection/differs/iterable_differs.d.ts':
|
'/tmp/@angular/core/src/change_detection/differs/iterable_differs.d.ts':
|
||||||
{version: 1, 'metadata': {'IterableDiffers': {'__symbolic': 'class'}}},
|
{version: 1, 'metadata': {'IterableDiffers': {'__symbolic': 'class'}}},
|
||||||
'/tmp/angular2/src/core/change_detection/change_detector_ref.d.ts':
|
'/tmp/@angular/core/src/change_detection/change_detector_ref.d.ts':
|
||||||
{version: 1, 'metadata': {'ChangeDetectorRef': {'__symbolic': 'class'}}},
|
{version: 1, 'metadata': {'ChangeDetectorRef': {'__symbolic': 'class'}}},
|
||||||
'/tmp/src/app/hero-detail.component.d.ts': {
|
'/tmp/src/app/hero-detail.component.d.ts': {
|
||||||
'__symbolic': 'module',
|
'__symbolic': 'module',
|
||||||
|
@ -626,7 +643,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'name': 'Component',
|
'name': 'Component',
|
||||||
'module': 'angular2/src/core/metadata'
|
'module': '@angular/core/src/metadata'
|
||||||
},
|
},
|
||||||
'arguments': [
|
'arguments': [
|
||||||
{
|
{
|
||||||
|
@ -638,7 +655,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'name': 'trigger',
|
'name': 'trigger',
|
||||||
'module': 'angular2/src/core/animation/metadata'
|
'module': '@angular/core/src/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments': [
|
'arguments': [
|
||||||
'myAnimation',
|
'myAnimation',
|
||||||
|
@ -646,7 +663,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'name': 'state',
|
'name': 'state',
|
||||||
'module': 'angular2/src/core/animation/metadata'
|
'module': '@angular/core/src/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments': [
|
'arguments': [
|
||||||
'state1',
|
'state1',
|
||||||
|
@ -654,7 +671,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'name': 'style',
|
'name': 'style',
|
||||||
'module': 'angular2/src/core/animation/metadata'
|
'module': '@angular/core/src/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments': [
|
'arguments': [
|
||||||
{ 'background':'white' }
|
{ 'background':'white' }
|
||||||
|
@ -666,7 +683,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic':'reference',
|
'__symbolic':'reference',
|
||||||
'name':'transition',
|
'name':'transition',
|
||||||
'module': 'angular2/src/core/animation/metadata'
|
'module': '@angular/core/src/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments': [
|
'arguments': [
|
||||||
'* => *',
|
'* => *',
|
||||||
|
@ -675,20 +692,20 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
'expression':{
|
'expression':{
|
||||||
'__symbolic':'reference',
|
'__symbolic':'reference',
|
||||||
'name':'sequence',
|
'name':'sequence',
|
||||||
'module': 'angular2/src/core/animation/metadata'
|
'module': '@angular/core/src/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments':[[{ '__symbolic': 'call',
|
'arguments':[[{ '__symbolic': 'call',
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic':'reference',
|
'__symbolic':'reference',
|
||||||
'name':'group',
|
'name':'group',
|
||||||
'module': 'angular2/src/core/animation/metadata'
|
'module': '@angular/core/src/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments':[[{
|
'arguments':[[{
|
||||||
'__symbolic': 'call',
|
'__symbolic': 'call',
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic':'reference',
|
'__symbolic':'reference',
|
||||||
'name':'animate',
|
'name':'animate',
|
||||||
'module': 'angular2/src/core/animation/metadata'
|
'module': '@angular/core/src/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments':[
|
'arguments':[
|
||||||
'1s 0.5s',
|
'1s 0.5s',
|
||||||
|
@ -696,13 +713,13 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic':'reference',
|
'__symbolic':'reference',
|
||||||
'name':'keyframes',
|
'name':'keyframes',
|
||||||
'module': 'angular2/src/core/animation/metadata'
|
'module': '@angular/core/src/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments':[[{ '__symbolic': 'call',
|
'arguments':[[{ '__symbolic': 'call',
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic':'reference',
|
'__symbolic':'reference',
|
||||||
'name':'style',
|
'name':'style',
|
||||||
'module': 'angular2/src/core/animation/metadata'
|
'module': '@angular/core/src/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments':[ { 'background': 'blue'} ]
|
'arguments':[ { 'background': 'blue'} ]
|
||||||
}, {
|
}, {
|
||||||
|
@ -710,7 +727,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic':'reference',
|
'__symbolic':'reference',
|
||||||
'name':'style',
|
'name':'style',
|
||||||
'module': 'angular2/src/core/animation/metadata'
|
'module': '@angular/core/src/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments':[ { 'background': 'red'} ]
|
'arguments':[ { 'background': 'red'} ]
|
||||||
}]]
|
}]]
|
||||||
|
@ -736,7 +753,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'name': 'Input',
|
'name': 'Input',
|
||||||
'module': 'angular2/src/core/metadata'
|
'module': '@angular/core/src/metadata'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -750,7 +767,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
'__symbolic': 'call',
|
'__symbolic': 'call',
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'module': 'angular2/src/core/metadata',
|
'module': '@angular/core/src/metadata',
|
||||||
'name': 'HostListener'
|
'name': 'HostListener'
|
||||||
},
|
},
|
||||||
'arguments': [
|
'arguments': [
|
||||||
|
@ -781,7 +798,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
expression: {
|
expression: {
|
||||||
__symbolic: 'reference',
|
__symbolic: 'reference',
|
||||||
name: 'Component',
|
name: 'Component',
|
||||||
module: 'angular2/src/core/metadata'
|
module: '@angular/core/src/metadata'
|
||||||
},
|
},
|
||||||
arguments: [
|
arguments: [
|
||||||
{
|
{
|
||||||
|
@ -982,8 +999,8 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
`,
|
`,
|
||||||
'/tmp/src/invalid-calls.ts': `
|
'/tmp/src/invalid-calls.ts': `
|
||||||
import {someFunction} from './nvalid-calll-definitions.ts';
|
import {someFunction} from './nvalid-calll-definitions.ts';
|
||||||
import {Component} from 'angular2/src/core/metadata';
|
import {Component} from '@angular/core/src/metadata';
|
||||||
import {NgIf} from 'angular2/common';
|
import {NgIf} from '@angular/common';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-component',
|
selector: 'my-component',
|
||||||
|
@ -999,7 +1016,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
export class MyOtherComponent { }
|
export class MyOtherComponent { }
|
||||||
`,
|
`,
|
||||||
'/tmp/src/static-method.ts': `
|
'/tmp/src/static-method.ts': `
|
||||||
import {Component} from 'angular2/src/core/metadata';
|
import {Component} from '@angular/core/src/metadata';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'stub'
|
selector: 'stub'
|
||||||
|
@ -1017,7 +1034,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
'/tmp/src/static-method-call.ts': `
|
'/tmp/src/static-method-call.ts': `
|
||||||
import {Component} from 'angular2/src/core/metadata';
|
import {Component} from '@angular/core/src/metadata';
|
||||||
import {MyModule} from './static-method';
|
import {MyModule} from './static-method';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -1036,7 +1053,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
export class MyDefaultsComponent { }
|
export class MyDefaultsComponent { }
|
||||||
`,
|
`,
|
||||||
'/tmp/src/static-field.ts': `
|
'/tmp/src/static-field.ts': `
|
||||||
import {Injectable} from 'angular2/core';
|
import {Injectable} from '@angular/core';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MyModule {
|
export class MyModule {
|
||||||
|
@ -1044,7 +1061,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
'/tmp/src/static-field-reference.ts': `
|
'/tmp/src/static-field-reference.ts': `
|
||||||
import {Component} from 'angular2/src/core/metadata';
|
import {Component} from '@angular/core/src/metadata';
|
||||||
import {MyModule} from './static-field';
|
import {MyModule} from './static-field';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -1058,7 +1075,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
'/tmp/src/static-method-ref.ts': `
|
'/tmp/src/static-method-ref.ts': `
|
||||||
import {Component} from 'angular2/src/core/metadata';
|
import {Component} from '@angular/core/src/metadata';
|
||||||
import {ClassWithStatics} from './static-method-def';
|
import {ClassWithStatics} from './static-method-def';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -1069,7 +1086,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
'/tmp/src/invalid-metadata.ts': `
|
'/tmp/src/invalid-metadata.ts': `
|
||||||
import {Component} from 'angular2/src/core/metadata';
|
import {Component} from '@angular/core/src/metadata';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
providers: [ { provider: 'a', useValue: (() => 1)() }]
|
providers: [ { provider: 'a', useValue: (() => 1)() }]
|
||||||
|
@ -1077,9 +1094,9 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
export class InvalidMetadata {}
|
export class InvalidMetadata {}
|
||||||
`,
|
`,
|
||||||
'/tmp/src/forward-ref.ts': `
|
'/tmp/src/forward-ref.ts': `
|
||||||
import {forwardRef} from 'angular2/core';
|
import {forwardRef} from '@angular/core';
|
||||||
import {Component} from 'angular2/src/core/metadata';
|
import {Component} from '@angular/core/src/metadata';
|
||||||
import {Inject} from 'angular2/src/core/di/metadata';
|
import {Inject} from '@angular/core/src/di/metadata';
|
||||||
@Component({})
|
@Component({})
|
||||||
export class Forward {
|
export class Forward {
|
||||||
constructor(@Inject(forwardRef(() => Dep)) d: Dep) {}
|
constructor(@Inject(forwardRef(() => Dep)) d: Dep) {}
|
||||||
|
@ -1087,7 +1104,50 @@ class MockReflectorHost implements StaticReflectorHost {
|
||||||
export class Dep {
|
export class Dep {
|
||||||
@Input f: Forward;
|
@Input f: Forward;
|
||||||
}
|
}
|
||||||
`
|
`,
|
||||||
|
'/tmp/src/reexport/reexport.d.ts': {
|
||||||
|
__symbolic: 'module',
|
||||||
|
version: 1,
|
||||||
|
metadata: {},
|
||||||
|
exports: [
|
||||||
|
{from: './src/origin1', export: ['One', 'Two', {name: 'Three', as: 'Four'}]},
|
||||||
|
{from: './src/origin5'}, {from: './src/reexport2'}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'/tmp/src/reexport/src/origin1.d.ts': {
|
||||||
|
__symbolic: 'module',
|
||||||
|
version: 1,
|
||||||
|
metadata: {
|
||||||
|
One: {__symbolic: 'class'},
|
||||||
|
Two: {__symbolic: 'class'},
|
||||||
|
Three: {__symbolic: 'class'},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'/tmp/src/reexport/src/origin5.d.ts': {
|
||||||
|
__symbolic: 'module',
|
||||||
|
version: 1,
|
||||||
|
metadata: {
|
||||||
|
Five: {__symbolic: 'class'},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'/tmp/src/reexport/src/origin30.d.ts': {
|
||||||
|
__symbolic: 'module',
|
||||||
|
version: 1,
|
||||||
|
metadata: {
|
||||||
|
Thirty: {__symbolic: 'class'},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'/tmp/src/reexport/src/originNone.d.ts': {
|
||||||
|
__symbolic: 'module',
|
||||||
|
version: 1,
|
||||||
|
metadata: {},
|
||||||
|
},
|
||||||
|
'/tmp/src/reexport/src/reexport2.d.ts': {
|
||||||
|
__symbolic: 'module',
|
||||||
|
version: 1,
|
||||||
|
metadata: {},
|
||||||
|
exports: [{from: './originNone'}, {from: './origin30'}]
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue