diff --git a/packages/compiler-cli/src/metadata/bundler.ts b/packages/compiler-cli/src/metadata/bundler.ts index 7eb0c56d16..6ce4ae19c3 100644 --- a/packages/compiler-cli/src/metadata/bundler.ts +++ b/packages/compiler-cli/src/metadata/bundler.ts @@ -11,7 +11,7 @@ import * as ts from 'typescript'; import {MetadataCache} from '../transformers/metadata_cache'; import {MetadataCollector} from './collector'; -import {ClassMetadata, ConstructorMetadata, FunctionMetadata, METADATA_VERSION, MemberMetadata, MetadataEntry, MetadataError, MetadataImportedSymbolReferenceExpression, MetadataMap, MetadataObject, MetadataSymbolicExpression, MetadataSymbolicReferenceExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isInterfaceMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportedSymbolReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicExpression, isMethodMetadata} from './schema'; +import {ClassMetadata, ConstructorMetadata, FunctionMetadata, METADATA_VERSION, MemberMetadata, MetadataEntry, MetadataError, MetadataMap, MetadataObject, MetadataSymbolicExpression, MetadataSymbolicReferenceExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isInterfaceMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportedSymbolReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicCallExpression, isMetadataSymbolicExpression, isMethodMetadata} from './schema'; @@ -412,7 +412,17 @@ export class MetadataBundler { let result: StaticsMetadata = {}; for (const key in statics) { const value = statics[key]; - result[key] = isFunctionMetadata(value) ? this.convertFunction(moduleName, value) : value; + + if (isFunctionMetadata(value)) { + result[key] = this.convertFunction(moduleName, value); + } else if (isMetadataSymbolicCallExpression(value)) { + // Class members can also contain static members that call a function with module + // references. e.g. "static ngInjectableDef = defineInjectable(..)". We also need to + // convert these module references because otherwise these resolve to non-existent files. + result[key] = this.convertValue(moduleName, value); + } else { + result[key] = value; + } } return result; } diff --git a/packages/compiler-cli/test/metadata/bundler_spec.ts b/packages/compiler-cli/test/metadata/bundler_spec.ts index bf51f83706..68f3ca6941 100644 --- a/packages/compiler-cli/test/metadata/bundler_spec.ts +++ b/packages/compiler-cli/test/metadata/bundler_spec.ts @@ -218,6 +218,59 @@ describe('metadata bundler', () => { ]); }); + it('should rewrite call expression references for static class members', () => { + const host = new MockStringBundlerHost('/', { + 'lib': { + 'index.ts': `export * from './deep/index';`, + 'shared.ts': ` + export function sharedFn() { + return {foo: true}; + }`, + 'deep': { + 'index.ts': ` + import {sharedFn} from '../shared'; + + export class MyClass { + static ngInjectableDef = sharedFn(); + } + `, + } + } + }); + const bundler = new MetadataBundler('/lib/index', undefined, host); + const bundledMetadata = bundler.getMetadataBundle().metadata; + const deepIndexMetadata = host.getMetadataFor('/lib/deep/index') !; + + // The unbundled metadata should reference symbols using the relative module path. + expect(deepIndexMetadata.metadata['MyClass']).toEqual(jasmine.objectContaining({ + statics: { + ngInjectableDef: { + __symbolic: 'call', + expression: { + __symbolic: 'reference', + name: 'sharedFn', + module: '../shared', + } + } + } + })); + + // For the bundled metadata, the "sharedFn" symbol should not be referenced using the + // relative module path (like for unbundled), because the metadata bundle can be stored + // anywhere and it's not guaranteed that the relatively referenced files are present. + expect(bundledMetadata.metadata['MyClass']).toEqual(jasmine.objectContaining({ + statics: { + ngInjectableDef: { + __symbolic: 'call', + expression: { + __symbolic: 'reference', + name: 'ɵa', + } + } + } + })); + }); + it('should be able to bundle an oddly constructed library', () => { const host = new MockStringBundlerHost('/', { 'lib': {