diff --git a/tools/broccoli/broccoli-typescript.ts b/tools/broccoli/broccoli-typescript.ts index 637b519a05..9d4ff9f4de 100644 --- a/tools/broccoli/broccoli-typescript.ts +++ b/tools/broccoli/broccoli-typescript.ts @@ -88,7 +88,16 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin { this.tsServiceHost = new CustomLanguageServiceHost(this.tsOpts, this.rootFilePaths, this.fileRegistry, this.inputPath); this.tsService = ts.createLanguageService(this.tsServiceHost, ts.createDocumentRegistry()); - this.metadataCollector = new MetadataCollector(); + this.metadataCollector = new MetadataCollector({ + // Since our code isn't under a node_modules directory, we need to reverse the module + // resolution to get metadata rooted at 'angular2'. + // see https://github.com/angular/angular/issues/8144 + reverseModuleResolution(fileName: string) { + if (/\.tmp\/angular2/.test(fileName)) { + return fileName.substr(fileName.lastIndexOf('.tmp/angular2/') + 5).replace(/\.ts$/, ''); + } + } + }); } diff --git a/tools/metadata/src/collector.ts b/tools/metadata/src/collector.ts index 6e26619cdb..49a349a715 100644 --- a/tools/metadata/src/collector.ts +++ b/tools/metadata/src/collector.ts @@ -27,28 +27,32 @@ function pathTo(from: string, to: string): string { return result; } -function moduleNameFromBaseName(moduleFileName: string, baseFileName: string): string { - // Remove the extension - moduleFileName = moduleFileName.replace(EXT_REGEX, ''); - - // Check for node_modules - const nodeModulesIndex = moduleFileName.lastIndexOf(NODE_MODULES); - if (nodeModulesIndex >= 0) { - return moduleFileName.substr(nodeModulesIndex + NODE_MODULES.length); - } - if (moduleFileName.lastIndexOf(NODE_MODULES_PREFIX, NODE_MODULES_PREFIX.length) !== -1) { - return moduleFileName.substr(NODE_MODULES_PREFIX.length); - } - - // Construct a simplified path from the file to the module - return pathTo(baseFileName, moduleFileName); +export interface MetadataCollectorHost { + reverseModuleResolution: (moduleFileName: string) => string; } +const nodeModuleResolutionHost: MetadataCollectorHost = { + // Reverse moduleResolution=node for packages resolved in node_modules + reverseModuleResolution(fileName: string) { + // Remove the extension + const moduleFileName = fileName.replace(EXT_REGEX, ''); + // Check for node_modules + const nodeModulesIndex = moduleFileName.lastIndexOf(NODE_MODULES); + if (nodeModulesIndex >= 0) { + return moduleFileName.substr(nodeModulesIndex + NODE_MODULES.length); + } + if (moduleFileName.lastIndexOf(NODE_MODULES_PREFIX, NODE_MODULES_PREFIX.length) !== -1) { + return moduleFileName.substr(NODE_MODULES_PREFIX.length); + } + return null; + } +}; + /** * Collect decorator metadata from a TypeScript module. */ export class MetadataCollector { - constructor() {} + constructor(private host: MetadataCollectorHost = nodeModuleResolutionHost) {} /** * Returns a JSON.stringify friendly form describing the decorators of the exported classes from @@ -56,8 +60,16 @@ export class MetadataCollector { */ public getMetadata(sourceFile: ts.SourceFile, typeChecker: ts.TypeChecker): ModuleMetadata { const locals = new Symbols(); - const moduleNameOf = (fileName: string) => - moduleNameFromBaseName(fileName, sourceFile.fileName); + const moduleNameOf = (fileName: string) => { + // If the module was resolved with TS moduleResolution, reverse that mapping + const hostResolved = this.host.reverseModuleResolution(fileName); + if (hostResolved) { + return hostResolved; + } + // Construct a simplified path from the file to the module + return pathTo(sourceFile.fileName, fileName).replace(EXT_REGEX, ''); + }; + const evaluator = new Evaluator(typeChecker, locals, moduleNameOf); function objFromDecorator(decoratorNode: ts.Decorator): MetadataSymbolicExpression { @@ -85,15 +97,13 @@ export class MetadataCollector { } function classMetadataOf(classDeclaration: ts.ClassDeclaration): ClassMetadata { - let result: ClassMetadata = - { __symbolic: "class" } + let result: ClassMetadata = {__symbolic: "class"}; - function getDecorators(decorators: ts.Decorator[]): - MetadataSymbolicExpression[] { - if (decorators && decorators.length) - return decorators.map(decorator => objFromDecorator(decorator)); - return undefined; - } + function getDecorators(decorators: ts.Decorator[]): MetadataSymbolicExpression[] { + if (decorators && decorators.length) + return decorators.map(decorator => objFromDecorator(decorator)); + return undefined; + } // Add class decorators if (classDeclaration.decorators) { @@ -175,7 +185,7 @@ export class MetadataCollector { const classDeclaration = declaration; if (classDeclaration.decorators) { if (!metadata) metadata = {}; - metadata[classDeclaration.name.text] = classMetadataOf(classDeclaration) + metadata[classDeclaration.name.text] = classMetadataOf(classDeclaration); } break; case ts.SyntaxKind.VariableDeclaration: