fix(compiler): StaticReflect now resolves re-exported symbols (#10453)
Fixes: #10451
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {Evaluator, errorSymbol, isPrimitive} from './evaluator';
|
||||
import {ClassMetadata, ConstructorMetadata, FunctionMetadata, MemberMetadata, MetadataError, MetadataMap, MetadataObject, MetadataSymbolicExpression, MetadataSymbolicReferenceExpression, MetadataSymbolicSelectExpression, MetadataValue, MethodMetadata, ModuleMetadata, VERSION, isMetadataError, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSelectExpression} from './schema';
|
||||
import {ClassMetadata, ConstructorMetadata, FunctionMetadata, MemberMetadata, MetadataError, MetadataMap, MetadataObject, MetadataSymbolicExpression, MetadataSymbolicReferenceExpression, MetadataSymbolicSelectExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata, VERSION, isMetadataError, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSelectExpression} from './schema';
|
||||
import {Symbols} from './symbols';
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ export class MetadataCollector {
|
||||
const locals = new Symbols(sourceFile);
|
||||
const evaluator = new Evaluator(locals);
|
||||
let metadata: {[name: string]: MetadataValue | ClassMetadata | FunctionMetadata}|undefined;
|
||||
let exports: ModuleExportMetadata[];
|
||||
|
||||
function objFromDecorator(decoratorNode: ts.Decorator): MetadataSymbolicExpression {
|
||||
return <MetadataSymbolicExpression>evaluator.evaluateNode(decoratorNode.expression);
|
||||
@ -202,6 +203,25 @@ export class MetadataCollector {
|
||||
});
|
||||
ts.forEachChild(sourceFile, node => {
|
||||
switch (node.kind) {
|
||||
case ts.SyntaxKind.ExportDeclaration:
|
||||
// Record export declarations
|
||||
const exportDeclaration = <ts.ExportDeclaration>node;
|
||||
const moduleSpecifier = exportDeclaration.moduleSpecifier;
|
||||
if (moduleSpecifier && moduleSpecifier.kind == ts.SyntaxKind.StringLiteral) {
|
||||
// Ignore exports that don't have string literals as exports.
|
||||
// This is allowed by the syntax but will be flagged as an error by the type checker.
|
||||
const from = (<ts.StringLiteral>moduleSpecifier).text;
|
||||
const moduleExport: ModuleExportMetadata = {from};
|
||||
if (exportDeclaration.exportClause) {
|
||||
moduleExport.export = exportDeclaration.exportClause.elements.map(
|
||||
element => element.propertyName ?
|
||||
{name: element.propertyName.text, as: element.name.text} :
|
||||
element.name.text)
|
||||
}
|
||||
if (!exports) exports = [];
|
||||
exports.push(moduleExport);
|
||||
}
|
||||
break;
|
||||
case ts.SyntaxKind.ClassDeclaration:
|
||||
const classDeclaration = <ts.ClassDeclaration>node;
|
||||
const className = classDeclaration.name.text;
|
||||
@ -320,7 +340,12 @@ export class MetadataCollector {
|
||||
}
|
||||
});
|
||||
|
||||
return metadata && {__symbolic: 'module', version: VERSION, metadata};
|
||||
if (metadata || exports) {
|
||||
if (!metadata) metadata = {};
|
||||
const result: ModuleMetadata = {__symbolic: 'module', version: VERSION, metadata};
|
||||
if (exports) result.exports = exports;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,12 +12,18 @@ export const VERSION = 1;
|
||||
export interface ModuleMetadata {
|
||||
__symbolic: 'module';
|
||||
version: number;
|
||||
exports?: ModuleExportMetadata[];
|
||||
metadata: {[name: string]: (ClassMetadata | FunctionMetadata | MetadataValue)};
|
||||
}
|
||||
export function isModuleMetadata(value: any): value is ModuleMetadata {
|
||||
return value && value.__symbolic === 'module';
|
||||
}
|
||||
|
||||
export interface ModuleExportMetadata {
|
||||
export?: (string|{name: string, as: string})[];
|
||||
from: string;
|
||||
}
|
||||
|
||||
export interface ClassMetadata {
|
||||
__symbolic: 'class';
|
||||
decorators?: (MetadataSymbolicExpression|MetadataError)[];
|
||||
|
@ -24,6 +24,7 @@ describe('Collector', () => {
|
||||
'exported-functions.ts',
|
||||
'exported-enum.ts',
|
||||
'exported-consts.ts',
|
||||
're-exports.ts',
|
||||
'static-field-reference.ts',
|
||||
'static-method.ts',
|
||||
'static-method-call.ts',
|
||||
@ -475,6 +476,16 @@ describe('Collector', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to collect re-exported symbols', () => {
|
||||
let source = program.getSourceFile('/re-exports.ts');
|
||||
let metadata = collector.getMetadata(source);
|
||||
expect(metadata.exports).toEqual([
|
||||
{from: './static-field', export: ['MyModule']},
|
||||
{from: './static-field-reference.ts', export: [{name: 'Foo', as: 'OtherModule'}]},
|
||||
{from: 'angular2/core'}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: Do not use \` in a template literal as it confuses clang-format
|
||||
@ -783,6 +794,11 @@ const FILES: Directory = {
|
||||
}
|
||||
}
|
||||
`,
|
||||
're-exports.ts': `
|
||||
export {MyModule} from './static-field';
|
||||
export {Foo as OtherModule} from './static-field-reference.ts';
|
||||
export * from 'angular2/core';
|
||||
`,
|
||||
'node_modules': {
|
||||
'angular2': {
|
||||
'core.d.ts': `
|
||||
|
Reference in New Issue
Block a user