fix(metadata): emit metadata rooted at 'angular2'

fixes #8144

closes #8147
This commit is contained in:
Alex Eagle 2016-04-19 19:37:57 -07:00 committed by Robert Messerle
parent e69cb40de3
commit 9889c21aaa
2 changed files with 47 additions and 28 deletions

View File

@ -88,7 +88,16 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
this.tsServiceHost = new CustomLanguageServiceHost(this.tsOpts, this.rootFilePaths, this.tsServiceHost = new CustomLanguageServiceHost(this.tsOpts, this.rootFilePaths,
this.fileRegistry, this.inputPath); this.fileRegistry, this.inputPath);
this.tsService = ts.createLanguageService(this.tsServiceHost, ts.createDocumentRegistry()); 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$/, '');
}
}
});
} }

View File

@ -27,28 +27,32 @@ function pathTo(from: string, to: string): string {
return result; return result;
} }
function moduleNameFromBaseName(moduleFileName: string, baseFileName: string): string { export interface MetadataCollectorHost {
// Remove the extension reverseModuleResolution: (moduleFileName: string) => string;
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);
} }
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. * Collect decorator metadata from a TypeScript module.
*/ */
export class MetadataCollector { export class MetadataCollector {
constructor() {} constructor(private host: MetadataCollectorHost = nodeModuleResolutionHost) {}
/** /**
* Returns a JSON.stringify friendly form describing the decorators of the exported classes from * 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 { public getMetadata(sourceFile: ts.SourceFile, typeChecker: ts.TypeChecker): ModuleMetadata {
const locals = new Symbols(); const locals = new Symbols();
const moduleNameOf = (fileName: string) => const moduleNameOf = (fileName: string) => {
moduleNameFromBaseName(fileName, sourceFile.fileName); // 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); const evaluator = new Evaluator(typeChecker, locals, moduleNameOf);
function objFromDecorator(decoratorNode: ts.Decorator): MetadataSymbolicExpression { function objFromDecorator(decoratorNode: ts.Decorator): MetadataSymbolicExpression {
@ -85,15 +97,13 @@ export class MetadataCollector {
} }
function classMetadataOf(classDeclaration: ts.ClassDeclaration): ClassMetadata { function classMetadataOf(classDeclaration: ts.ClassDeclaration): ClassMetadata {
let result: ClassMetadata = let result: ClassMetadata = {__symbolic: "class"};
{ __symbolic: "class" }
function getDecorators(decorators: ts.Decorator[]): function getDecorators(decorators: ts.Decorator[]): MetadataSymbolicExpression[] {
MetadataSymbolicExpression[] { if (decorators && decorators.length)
if (decorators && decorators.length) return decorators.map(decorator => objFromDecorator(decorator));
return decorators.map(decorator => objFromDecorator(decorator)); return undefined;
return undefined; }
}
// Add class decorators // Add class decorators
if (classDeclaration.decorators) { if (classDeclaration.decorators) {
@ -175,7 +185,7 @@ export class MetadataCollector {
const classDeclaration = <ts.ClassDeclaration>declaration; const classDeclaration = <ts.ClassDeclaration>declaration;
if (classDeclaration.decorators) { if (classDeclaration.decorators) {
if (!metadata) metadata = {}; if (!metadata) metadata = {};
metadata[classDeclaration.name.text] = classMetadataOf(classDeclaration) metadata[classDeclaration.name.text] = classMetadataOf(classDeclaration);
} }
break; break;
case ts.SyntaxKind.VariableDeclaration: case ts.SyntaxKind.VariableDeclaration: