| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @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 * as path from 'path'; | 
					
						
							|  |  |  | import * as ts from 'typescript'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 10:02:08 +10:00
										 |  |  | import {CompilerHostAdapter, MetadataBundler, MetadataBundlerHost} from '../../src/metadata/bundler'; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  | import {MetadataCollector} from '../../src/metadata/collector'; | 
					
						
							| 
									
										
										
										
											2019-06-14 12:19:09 +02:00
										 |  |  | import {ClassMetadata, MetadataEntry, MetadataGlobalReferenceExpression, ModuleMetadata} from '../../src/metadata/schema'; | 
					
						
							| 
									
										
										
										
											2018-07-07 10:02:08 +10:00
										 |  |  | import {Directory, MockAotContext, MockCompilerHost} from '../mocks'; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 10:02:08 +10:00
										 |  |  | describe('compiler host adapter', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should retrieve metadata for an explicit index relative path reference', () => { | 
					
						
							|  |  |  |     const context = new MockAotContext('.', SIMPLE_LIBRARY); | 
					
						
							|  |  |  |     const host = new MockCompilerHost(context); | 
					
						
							|  |  |  |     const options: ts.CompilerOptions = { | 
					
						
							|  |  |  |       moduleResolution: ts.ModuleResolutionKind.NodeJs, | 
					
						
							|  |  |  |       module: ts.ModuleKind.CommonJS, | 
					
						
							|  |  |  |       target: ts.ScriptTarget.ES5, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     const adapter = new CompilerHostAdapter(host, null, options); | 
					
						
							|  |  |  |     const metadata = adapter.getMetadataFor('./lib/src/two/index', '.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(metadata).toBeDefined(); | 
					
						
							|  |  |  |     expect(Object.keys(metadata !.metadata).sort()).toEqual([ | 
					
						
							|  |  |  |       'PrivateTwo', | 
					
						
							|  |  |  |       'TWO_CLASSES', | 
					
						
							|  |  |  |       'Two', | 
					
						
							|  |  |  |       'TwoMore', | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should retrieve metadata for an implied index relative path reference', () => { | 
					
						
							|  |  |  |     const context = new MockAotContext('.', SIMPLE_LIBRARY_WITH_IMPLIED_INDEX); | 
					
						
							|  |  |  |     const host = new MockCompilerHost(context); | 
					
						
							|  |  |  |     const options: ts.CompilerOptions = { | 
					
						
							|  |  |  |       moduleResolution: ts.ModuleResolutionKind.NodeJs, | 
					
						
							|  |  |  |       module: ts.ModuleKind.CommonJS, | 
					
						
							|  |  |  |       target: ts.ScriptTarget.ES5, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     const adapter = new CompilerHostAdapter(host, null, options); | 
					
						
							|  |  |  |     const metadata = adapter.getMetadataFor('./lib/src/two', '.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(metadata).toBeDefined(); | 
					
						
							|  |  |  |     expect(Object.keys(metadata !.metadata).sort()).toEqual([ | 
					
						
							|  |  |  |       'PrivateTwo', | 
					
						
							|  |  |  |       'TWO_CLASSES', | 
					
						
							|  |  |  |       'Two', | 
					
						
							|  |  |  |       'TwoMore', | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should fail to retrieve metadata for an implied index with classic module resolution', () => { | 
					
						
							|  |  |  |     const context = new MockAotContext('.', SIMPLE_LIBRARY_WITH_IMPLIED_INDEX); | 
					
						
							|  |  |  |     const host = new MockCompilerHost(context); | 
					
						
							|  |  |  |     const options: ts.CompilerOptions = { | 
					
						
							|  |  |  |       moduleResolution: ts.ModuleResolutionKind.Classic, | 
					
						
							|  |  |  |       module: ts.ModuleKind.CommonJS, | 
					
						
							|  |  |  |       target: ts.ScriptTarget.ES5, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     const adapter = new CompilerHostAdapter(host, null, options); | 
					
						
							|  |  |  |     const metadata = adapter.getMetadataFor('./lib/src/two', '.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(metadata).toBeUndefined(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should retrieve exports for an explicit index relative path reference', () => { | 
					
						
							|  |  |  |     const context = new MockAotContext('.', SIMPLE_LIBRARY); | 
					
						
							|  |  |  |     const host = new MockCompilerHost(context); | 
					
						
							|  |  |  |     const options: ts.CompilerOptions = { | 
					
						
							|  |  |  |       moduleResolution: ts.ModuleResolutionKind.NodeJs, | 
					
						
							|  |  |  |       module: ts.ModuleKind.CommonJS, | 
					
						
							|  |  |  |       target: ts.ScriptTarget.ES5, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     const adapter = new CompilerHostAdapter(host, null, options); | 
					
						
							|  |  |  |     const metadata = adapter.getMetadataFor('./lib/src/index', '.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(metadata).toBeDefined(); | 
					
						
							|  |  |  |     expect(metadata !.exports !.map(e => e.export !) | 
					
						
							|  |  |  |                .reduce((prev, next) => prev.concat(next), []) | 
					
						
							|  |  |  |                .sort()) | 
					
						
							|  |  |  |         .toEqual([ | 
					
						
							|  |  |  |           'ONE_CLASSES', | 
					
						
							|  |  |  |           'One', | 
					
						
							|  |  |  |           'OneMore', | 
					
						
							|  |  |  |           'TWO_CLASSES', | 
					
						
							|  |  |  |           'Two', | 
					
						
							|  |  |  |           'TwoMore', | 
					
						
							|  |  |  |         ]); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should look for .ts file when resolving metadata via a package.json "main" entry', () => { | 
					
						
							|  |  |  |     const files = { | 
					
						
							|  |  |  |       'lib': { | 
					
						
							|  |  |  |         'one.ts': `
 | 
					
						
							|  |  |  |           class One {} | 
					
						
							|  |  |  |           class OneMore extends One {} | 
					
						
							|  |  |  |           class PrivateOne {} | 
					
						
							|  |  |  |           const ONE_CLASSES = [One, OneMore, PrivateOne]; | 
					
						
							|  |  |  |           export {One, OneMore, PrivateOne, ONE_CLASSES}; | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |         'one.js': `
 | 
					
						
							|  |  |  |           // This will throw an error if the metadata collector tries to load one.js
 | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |         'package.json': `
 | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           "main": "one" | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         `
 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const context = new MockAotContext('.', files); | 
					
						
							|  |  |  |     const host = new MockCompilerHost(context); | 
					
						
							|  |  |  |     const options: ts.CompilerOptions = { | 
					
						
							|  |  |  |       moduleResolution: ts.ModuleResolutionKind.NodeJs, | 
					
						
							|  |  |  |       module: ts.ModuleKind.CommonJS, | 
					
						
							|  |  |  |       target: ts.ScriptTarget.ES5, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     const adapter = new CompilerHostAdapter(host, null, options); | 
					
						
							|  |  |  |     const metadata = adapter.getMetadataFor('./lib', '.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(metadata).toBeDefined(); | 
					
						
							|  |  |  |     expect(Object.keys(metadata !.metadata).sort()).toEqual([ | 
					
						
							|  |  |  |       'ONE_CLASSES', | 
					
						
							|  |  |  |       'One', | 
					
						
							|  |  |  |       'OneMore', | 
					
						
							|  |  |  |       'PrivateOne', | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  |     expect(Array.isArray(metadata !.metadata !['ONE_CLASSES'])).toBeTruthy(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should look for non-declaration file when resolving metadata via a package.json "types" entry', | 
					
						
							|  |  |  |      () => { | 
					
						
							|  |  |  |        const files = { | 
					
						
							|  |  |  |          'lib': { | 
					
						
							|  |  |  |            'one.ts': `
 | 
					
						
							|  |  |  |           class One {} | 
					
						
							|  |  |  |           class OneMore extends One {} | 
					
						
							|  |  |  |           class PrivateOne {} | 
					
						
							|  |  |  |           const ONE_CLASSES = [One, OneMore, PrivateOne]; | 
					
						
							|  |  |  |           export {One, OneMore, PrivateOne, ONE_CLASSES}; | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |            'one.d.ts': `
 | 
					
						
							|  |  |  |           declare class One { | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           declare class OneMore extends One { | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           declare class PrivateOne { | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           declare const ONE_CLASSES: (typeof One)[]; | 
					
						
							|  |  |  |           export { One, OneMore, PrivateOne, ONE_CLASSES }; | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |            'one.js': `
 | 
					
						
							|  |  |  |           // This will throw an error if the metadata collector tries to load one.js
 | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |            'package.json': `
 | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           "main": "one", | 
					
						
							|  |  |  |           "types": "one.d.ts" | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         `
 | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  |        }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        const context = new MockAotContext('.', files); | 
					
						
							|  |  |  |        const host = new MockCompilerHost(context); | 
					
						
							|  |  |  |        const options: ts.CompilerOptions = { | 
					
						
							|  |  |  |          moduleResolution: ts.ModuleResolutionKind.NodeJs, | 
					
						
							|  |  |  |          module: ts.ModuleKind.CommonJS, | 
					
						
							|  |  |  |          target: ts.ScriptTarget.ES5, | 
					
						
							|  |  |  |        }; | 
					
						
							|  |  |  |        const adapter = new CompilerHostAdapter(host, null, options); | 
					
						
							|  |  |  |        const metadata = adapter.getMetadataFor('./lib', '.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        expect(metadata).toBeDefined(); | 
					
						
							|  |  |  |        expect(Object.keys(metadata !.metadata).sort()).toEqual([ | 
					
						
							|  |  |  |          'ONE_CLASSES', | 
					
						
							|  |  |  |          'One', | 
					
						
							|  |  |  |          'OneMore', | 
					
						
							|  |  |  |          'PrivateOne', | 
					
						
							|  |  |  |        ]); | 
					
						
							|  |  |  |        expect(Array.isArray(metadata !.metadata !['ONE_CLASSES'])).toBeTruthy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      }); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | describe('metadata bundler', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to bundle a simple library', () => { | 
					
						
							|  |  |  |     const host = new MockStringBundlerHost('/', SIMPLE_LIBRARY); | 
					
						
							| 
									
										
										
										
											2018-03-26 14:34:44 -07:00
										 |  |  |     const bundler = new MetadataBundler('/lib/index', undefined, host, 'prfx_'); | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     const result = bundler.getMetadataBundle(); | 
					
						
							|  |  |  |     expect(Object.keys(result.metadata.metadata).sort()).toEqual([ | 
					
						
							| 
									
										
										
										
											2018-03-26 14:34:44 -07:00
										 |  |  |       'ONE_CLASSES', 'One', 'OneMore', 'TWO_CLASSES', 'Two', 'TwoMore', 'ɵprfx_a', 'ɵprfx_b' | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     ]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const originalOne = './src/one'; | 
					
						
							|  |  |  |     const originalTwo = './src/two/index'; | 
					
						
							| 
									
										
										
										
											2017-11-15 08:43:35 -08:00
										 |  |  |     expect(Object.keys(result.metadata.origins !) | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |                .sort() | 
					
						
							|  |  |  |                .map(name => ({name, value: result.metadata.origins ![name]}))) | 
					
						
							|  |  |  |         .toEqual([ | 
					
						
							|  |  |  |           {name: 'ONE_CLASSES', value: originalOne}, {name: 'One', value: originalOne}, | 
					
						
							|  |  |  |           {name: 'OneMore', value: originalOne}, {name: 'TWO_CLASSES', value: originalTwo}, | 
					
						
							|  |  |  |           {name: 'Two', value: originalTwo}, {name: 'TwoMore', value: originalTwo}, | 
					
						
							| 
									
										
										
										
											2018-03-26 14:34:44 -07:00
										 |  |  |           {name: 'ɵprfx_a', value: originalOne}, {name: 'ɵprfx_b', value: originalTwo} | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |         ]); | 
					
						
							|  |  |  |     expect(result.privates).toEqual([ | 
					
						
							| 
									
										
										
										
											2018-03-26 14:34:44 -07:00
										 |  |  |       {privateName: 'ɵprfx_a', name: 'PrivateOne', module: originalOne}, | 
					
						
							|  |  |  |       {privateName: 'ɵprfx_b', name: 'PrivateTwo', module: originalTwo} | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     ]); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-15 18:12:56 +01:00
										 |  |  |   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.
 | 
					
						
							| 
									
										
										
										
											2019-06-14 12:19:09 +02:00
										 |  |  |     expect(deepIndexMetadata.metadata['MyClass']).toEqual(jasmine.objectContaining<MetadataEntry>({ | 
					
						
							| 
									
										
										
										
											2019-02-15 18:12:56 +01:00
										 |  |  |       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.
 | 
					
						
							| 
									
										
										
										
											2019-06-14 12:19:09 +02:00
										 |  |  |     expect(bundledMetadata.metadata['MyClass']).toEqual(jasmine.objectContaining<MetadataEntry>({ | 
					
						
							| 
									
										
										
										
											2019-02-15 18:12:56 +01:00
										 |  |  |       statics: { | 
					
						
							|  |  |  |         ngInjectableDef: { | 
					
						
							|  |  |  |           __symbolic: 'call', | 
					
						
							|  |  |  |           expression: { | 
					
						
							|  |  |  |             __symbolic: 'reference', | 
					
						
							|  |  |  |             name: 'ɵa', | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     })); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |   it('should be able to bundle an oddly constructed library', () => { | 
					
						
							|  |  |  |     const host = new MockStringBundlerHost('/', { | 
					
						
							|  |  |  |       'lib': { | 
					
						
							|  |  |  |         'index.ts': `
 | 
					
						
							|  |  |  |           export * from './src/index'; | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |         'src': { | 
					
						
							|  |  |  |           'index.ts': `
 | 
					
						
							|  |  |  |             export {One, OneMore, ONE_CLASSES} from './one'; | 
					
						
							|  |  |  |             export {Two, TwoMore, TWO_CLASSES} from './two/index'; | 
					
						
							|  |  |  |           `,
 | 
					
						
							|  |  |  |           'one.ts': `
 | 
					
						
							|  |  |  |             class One {} | 
					
						
							|  |  |  |             class OneMore extends One {} | 
					
						
							|  |  |  |             class PrivateOne {} | 
					
						
							|  |  |  |             const ONE_CLASSES = [One, OneMore, PrivateOne]; | 
					
						
							|  |  |  |             export {One, OneMore, PrivateOne, ONE_CLASSES}; | 
					
						
							|  |  |  |           `,
 | 
					
						
							|  |  |  |           'two': { | 
					
						
							|  |  |  |             'index.ts': `
 | 
					
						
							|  |  |  |               class Two {} | 
					
						
							|  |  |  |               class TwoMore extends Two {} | 
					
						
							|  |  |  |               class PrivateTwo {} | 
					
						
							|  |  |  |               const TWO_CLASSES = [Two, TwoMore, PrivateTwo]; | 
					
						
							|  |  |  |               export {Two, TwoMore, PrivateTwo, TWO_CLASSES}; | 
					
						
							|  |  |  |             `
 | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const bundler = new MetadataBundler('/lib/index', undefined, host); | 
					
						
							|  |  |  |     const result = bundler.getMetadataBundle(); | 
					
						
							|  |  |  |     expect(Object.keys(result.metadata.metadata).sort()).toEqual([ | 
					
						
							|  |  |  |       'ONE_CLASSES', 'One', 'OneMore', 'TWO_CLASSES', 'Two', 'TwoMore', 'ɵa', 'ɵb' | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  |     expect(result.privates).toEqual([ | 
					
						
							|  |  |  |       {privateName: 'ɵa', name: 'PrivateOne', module: './src/one'}, | 
					
						
							|  |  |  |       {privateName: 'ɵb', name: 'PrivateTwo', module: './src/two/index'} | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should not output windows paths in metadata', () => { | 
					
						
							|  |  |  |     const host = new MockStringBundlerHost('/', { | 
					
						
							|  |  |  |       'index.ts': `
 | 
					
						
							|  |  |  |         export * from './exports/test'; | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |       'exports': {'test.ts': `export class TestExport {}`} | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const bundler = new MetadataBundler('/index', undefined, host); | 
					
						
							|  |  |  |     const result = bundler.getMetadataBundle(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(result.metadata.origins).toEqual({'TestExport': './exports/test'}); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should convert re-exported to the export', () => { | 
					
						
							|  |  |  |     const host = new MockStringBundlerHost('/', { | 
					
						
							|  |  |  |       'index.ts': `
 | 
					
						
							|  |  |  |         export * from './bar'; | 
					
						
							|  |  |  |         export * from './foo'; | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |       'bar.ts': `
 | 
					
						
							|  |  |  |         import {Foo} from './foo'; | 
					
						
							|  |  |  |         export class Bar extends Foo { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |       'foo.ts': `
 | 
					
						
							|  |  |  |         export {Foo} from 'foo'; | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const bundler = new MetadataBundler('/index', undefined, host); | 
					
						
							|  |  |  |     const result = bundler.getMetadataBundle(); | 
					
						
							|  |  |  |     // Expect the extends reference to refer to the imported module
 | 
					
						
							|  |  |  |     expect((result.metadata.metadata as any).Bar.extends.module).toEqual('foo'); | 
					
						
							|  |  |  |     expect(result.privates).toEqual([]); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should treat import then export as a simple export', () => { | 
					
						
							|  |  |  |     const host = new MockStringBundlerHost('/', { | 
					
						
							|  |  |  |       'index.ts': `
 | 
					
						
							|  |  |  |         export * from './a'; | 
					
						
							|  |  |  |         export * from './c'; | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |       'a.ts': `
 | 
					
						
							|  |  |  |         import { B } from './b'; | 
					
						
							|  |  |  |         export { B }; | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |       'b.ts': `
 | 
					
						
							|  |  |  |         export class B { } | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |       'c.ts': `
 | 
					
						
							|  |  |  |         import { B } from './b'; | 
					
						
							|  |  |  |         export class C extends B { } | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const bundler = new MetadataBundler('/index', undefined, host); | 
					
						
							|  |  |  |     const result = bundler.getMetadataBundle(); | 
					
						
							|  |  |  |     expect(Object.keys(result.metadata.metadata).sort()).toEqual(['B', 'C']); | 
					
						
							|  |  |  |     expect(result.privates).toEqual([]); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to bundle a private from a un-exported module', () => { | 
					
						
							|  |  |  |     const host = new MockStringBundlerHost('/', { | 
					
						
							|  |  |  |       'index.ts': `
 | 
					
						
							|  |  |  |         export * from './foo'; | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |       'foo.ts': `
 | 
					
						
							|  |  |  |         import {Bar} from './bar'; | 
					
						
							|  |  |  |         export class Foo extends Bar { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |       'bar.ts': `
 | 
					
						
							|  |  |  |         export class Bar {} | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const bundler = new MetadataBundler('/index', undefined, host); | 
					
						
							|  |  |  |     const result = bundler.getMetadataBundle(); | 
					
						
							|  |  |  |     expect(Object.keys(result.metadata.metadata).sort()).toEqual(['Foo', 'ɵa']); | 
					
						
							|  |  |  |     expect(result.privates).toEqual([{privateName: 'ɵa', name: 'Bar', module: './bar'}]); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to bundle a library with re-exported symbols', () => { | 
					
						
							|  |  |  |     const host = new MockStringBundlerHost('/', { | 
					
						
							|  |  |  |       'public-api.ts': `
 | 
					
						
							|  |  |  |         export * from './src/core'; | 
					
						
							|  |  |  |         export * from './src/externals'; | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |       'src': { | 
					
						
							|  |  |  |         'core.ts': `
 | 
					
						
							|  |  |  |           export class A {} | 
					
						
							|  |  |  |           export class B extends A {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |         'externals.ts': `
 | 
					
						
							|  |  |  |           export {E, F, G} from 'external_one'; | 
					
						
							|  |  |  |           export * from 'external_two'; | 
					
						
							|  |  |  |         `
 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const bundler = new MetadataBundler('/public-api', undefined, host); | 
					
						
							|  |  |  |     const result = bundler.getMetadataBundle(); | 
					
						
							|  |  |  |     expect(result.metadata.exports).toEqual([ | 
					
						
							|  |  |  |       {from: 'external_two'}, { | 
					
						
							|  |  |  |         export: [{name: 'E', as: 'E'}, {name: 'F', as: 'F'}, {name: 'G', as: 'G'}], | 
					
						
							|  |  |  |         from: 'external_one' | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  |     expect(result.metadata.origins !['E']).toBeUndefined(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-17 18:40:17 +01:00
										 |  |  |   it('should be able to bundle a library with multiple unnamed re-exports', () => { | 
					
						
							|  |  |  |     const host = new MockStringBundlerHost('/', { | 
					
						
							|  |  |  |       'public-api.ts': `
 | 
					
						
							|  |  |  |         export * from '@mypkg/secondary1'; | 
					
						
							|  |  |  |         export * from '@mypkg/secondary2'; | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const bundler = new MetadataBundler('/public-api', undefined, host); | 
					
						
							|  |  |  |     const result = bundler.getMetadataBundle(); | 
					
						
							|  |  |  |     expect(result.metadata.exports).toEqual([ | 
					
						
							|  |  |  |       {from: '@mypkg/secondary1'}, {from: '@mypkg/secondary2'} | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |   it('should be able to de-duplicate symbols of re-exported modules', () => { | 
					
						
							|  |  |  |     const host = new MockStringBundlerHost('/', { | 
					
						
							|  |  |  |       'public-api.ts': `
 | 
					
						
							|  |  |  |         export {A as A2, A, B as B1, B as B2} from './src/core'; | 
					
						
							| 
									
										
										
										
											2017-09-18 15:43:02 +02:00
										 |  |  |         export {A as A3} from './src/alternate'; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |       `,
 | 
					
						
							|  |  |  |       'src': { | 
					
						
							|  |  |  |         'core.ts': `
 | 
					
						
							|  |  |  |           export class A {} | 
					
						
							|  |  |  |           export class B {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							| 
									
										
										
										
											2017-09-18 15:43:02 +02:00
										 |  |  |         'alternate.ts': `
 | 
					
						
							|  |  |  |           export class A {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const bundler = new MetadataBundler('/public-api', undefined, host); | 
					
						
							|  |  |  |     const result = bundler.getMetadataBundle(); | 
					
						
							| 
									
										
										
										
											2017-09-18 15:43:02 +02:00
										 |  |  |     const {A, A2, A3, B1, B2} = result.metadata.metadata as{ | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |       A: ClassMetadata, | 
					
						
							|  |  |  |       A2: MetadataGlobalReferenceExpression, | 
					
						
							| 
									
										
										
										
											2017-09-18 15:43:02 +02:00
										 |  |  |       A3: ClassMetadata, | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |       B1: ClassMetadata, | 
					
						
							|  |  |  |       B2: MetadataGlobalReferenceExpression | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     expect(A.__symbolic).toEqual('class'); | 
					
						
							|  |  |  |     expect(A2.__symbolic).toEqual('reference'); | 
					
						
							|  |  |  |     expect(A2.name).toEqual('A'); | 
					
						
							| 
									
										
										
										
											2017-09-18 15:43:02 +02:00
										 |  |  |     expect(A3.__symbolic).toEqual('class'); | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     expect(B1.__symbolic).toEqual('class'); | 
					
						
							|  |  |  |     expect(B2.__symbolic).toEqual('reference'); | 
					
						
							|  |  |  |     expect(B2.name).toEqual('B1'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class MockStringBundlerHost implements MetadataBundlerHost { | 
					
						
							|  |  |  |   collector = new MetadataCollector(); | 
					
						
							| 
									
										
										
										
											2018-07-07 10:02:08 +10:00
										 |  |  |   adapter: CompilerHostAdapter; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 10:02:08 +10:00
										 |  |  |   constructor(private dirName: string, directory: Directory) { | 
					
						
							|  |  |  |     const context = new MockAotContext(dirName, directory); | 
					
						
							|  |  |  |     const host = new MockCompilerHost(context); | 
					
						
							|  |  |  |     const options = { | 
					
						
							|  |  |  |       moduleResolution: ts.ModuleResolutionKind.NodeJs, | 
					
						
							|  |  |  |       module: ts.ModuleKind.CommonJS, | 
					
						
							|  |  |  |       target: ts.ScriptTarget.ES5, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     this.adapter = new CompilerHostAdapter(host, null, options); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   getMetadataFor(moduleName: string): ModuleMetadata|undefined { | 
					
						
							| 
									
										
										
										
											2018-07-07 10:02:08 +10:00
										 |  |  |     return this.adapter.getMetadataFor(moduleName, this.dirName); | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export const SIMPLE_LIBRARY = { | 
					
						
							|  |  |  |   'lib': { | 
					
						
							|  |  |  |     'index.ts': `
 | 
					
						
							|  |  |  |       export * from './src/index'; | 
					
						
							|  |  |  |     `,
 | 
					
						
							|  |  |  |     'src': { | 
					
						
							|  |  |  |       'index.ts': `
 | 
					
						
							|  |  |  |         export {One, OneMore, ONE_CLASSES} from './one'; | 
					
						
							|  |  |  |         export {Two, TwoMore, TWO_CLASSES} from './two/index'; | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |       'one.ts': `
 | 
					
						
							|  |  |  |         export class One {} | 
					
						
							|  |  |  |         export class OneMore extends One {} | 
					
						
							|  |  |  |         export class PrivateOne {} | 
					
						
							|  |  |  |         export const ONE_CLASSES = [One, OneMore, PrivateOne]; | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |       'two': { | 
					
						
							|  |  |  |         'index.ts': `
 | 
					
						
							|  |  |  |           export class Two {} | 
					
						
							|  |  |  |           export class TwoMore extends Two {} | 
					
						
							|  |  |  |           export class PrivateTwo {} | 
					
						
							|  |  |  |           export const TWO_CLASSES = [Two, TwoMore, PrivateTwo]; | 
					
						
							|  |  |  |         `
 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-07-07 10:02:08 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | export const SIMPLE_LIBRARY_WITH_IMPLIED_INDEX = { | 
					
						
							|  |  |  |   'lib': { | 
					
						
							|  |  |  |     'index.ts': `
 | 
					
						
							|  |  |  |       export * from './src'; | 
					
						
							|  |  |  |     `,
 | 
					
						
							|  |  |  |     'src': { | 
					
						
							|  |  |  |       'index.ts': `
 | 
					
						
							|  |  |  |         export {One, OneMore, ONE_CLASSES} from './one'; | 
					
						
							|  |  |  |         export {Two, TwoMore, TWO_CLASSES} from './two'; | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |       'one.ts': `
 | 
					
						
							|  |  |  |         export class One {} | 
					
						
							|  |  |  |         export class OneMore extends One {} | 
					
						
							|  |  |  |         export class PrivateOne {} | 
					
						
							|  |  |  |         export const ONE_CLASSES = [One, OneMore, PrivateOne]; | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |       'two': { | 
					
						
							|  |  |  |         'index.ts': `
 | 
					
						
							|  |  |  |           export class Two {} | 
					
						
							|  |  |  |           export class TwoMore extends Two {} | 
					
						
							|  |  |  |           export class PrivateTwo {} | 
					
						
							|  |  |  |           export const TWO_CLASSES = [Two, TwoMore, PrivateTwo]; | 
					
						
							|  |  |  |         `
 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; |