| 
									
										
										
										
											2016-12-15 09:12:40 -08: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 {StaticSymbol, StaticSymbolCache, StaticSymbolResolver, StaticSymbolResolverHost, Summary, SummaryResolver} from '@angular/compiler'; | 
					
						
							| 
									
										
										
										
											2017-09-26 13:31:59 -07:00
										 |  |  | import {CollectorOptions, METADATA_VERSION} from '@angular/compiler-cli'; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  | import {MetadataCollector} from '@angular/compiler-cli/src/metadata/collector'; | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  | import * as ts from 'typescript'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This matches .ts files but not .d.ts files.
 | 
					
						
							|  |  |  | const TS_EXT = /(^.|(?!\.d)..)\.ts$/; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | describe('StaticSymbolResolver', () => { | 
					
						
							| 
									
										
										
										
											2016-12-27 09:36:47 -08:00
										 |  |  |   const noContext = new StaticSymbol('', '', []); | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |   let host: StaticSymbolResolverHost; | 
					
						
							|  |  |  |   let symbolResolver: StaticSymbolResolver; | 
					
						
							|  |  |  |   let symbolCache: StaticSymbolCache; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   beforeEach(() => { symbolCache = new StaticSymbolCache(); }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function init( | 
					
						
							| 
									
										
										
										
											2016-12-27 09:36:47 -08:00
										 |  |  |       testData: {[key: string]: any} = DEFAULT_TEST_DATA, summaries: Summary<StaticSymbol>[] = [], | 
					
						
							|  |  |  |       summaryImportAs: {symbol: StaticSymbol, importAs: StaticSymbol}[] = []) { | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |     host = new MockStaticSymbolResolverHost(testData); | 
					
						
							| 
									
										
										
										
											2016-12-27 09:36:47 -08:00
										 |  |  |     symbolResolver = new StaticSymbolResolver( | 
					
						
							|  |  |  |         host, symbolCache, new MockSummaryResolver(summaries, summaryImportAs)); | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   beforeEach(() => init()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should throw an exception for unsupported metadata versions', () => { | 
					
						
							|  |  |  |     expect( | 
					
						
							|  |  |  |         () => symbolResolver.resolveSymbol( | 
					
						
							|  |  |  |             symbolResolver.getSymbolByModule('src/version-error', 'e'))) | 
					
						
							|  |  |  |         .toThrow(new Error( | 
					
						
							| 
									
										
										
										
											2017-09-26 13:31:59 -07:00
										 |  |  |             `Metadata version mismatch for module /tmp/src/version-error.d.ts, found version 100, expected ${METADATA_VERSION}`)); | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should throw an exception for version 2 metadata', () => { | 
					
						
							|  |  |  |     expect( | 
					
						
							|  |  |  |         () => symbolResolver.resolveSymbol( | 
					
						
							|  |  |  |             symbolResolver.getSymbolByModule('src/version-2-error', 'e'))) | 
					
						
							|  |  |  |         .toThrowError( | 
					
						
							|  |  |  |             'Unsupported metadata version 2 for module /tmp/src/version-2-error.d.ts. This module should be compiled with a newer version of ngc'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be produce the same symbol if asked twice', () => { | 
					
						
							|  |  |  |     const foo1 = symbolResolver.getStaticSymbol('main.ts', 'foo'); | 
					
						
							|  |  |  |     const foo2 = symbolResolver.getStaticSymbol('main.ts', 'foo'); | 
					
						
							|  |  |  |     expect(foo1).toBe(foo2); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to produce a symbol for a module with no file', () => { | 
					
						
							|  |  |  |     expect(symbolResolver.getStaticSymbol('angularjs', 'SomeAngularSymbol')).toBeDefined(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to split the metadata per symbol', () => { | 
					
						
							|  |  |  |     init({ | 
					
						
							|  |  |  |       '/tmp/src/test.ts': `
 | 
					
						
							|  |  |  |         export var a = 1; | 
					
						
							|  |  |  |         export var b = 2; | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     expect(symbolResolver.resolveSymbol(symbolResolver.getStaticSymbol('/tmp/src/test.ts', 'a')) | 
					
						
							|  |  |  |                .metadata) | 
					
						
							|  |  |  |         .toBe(1); | 
					
						
							|  |  |  |     expect(symbolResolver.resolveSymbol(symbolResolver.getStaticSymbol('/tmp/src/test.ts', 'b')) | 
					
						
							|  |  |  |                .metadata) | 
					
						
							|  |  |  |         .toBe(2); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to resolve static symbols with members', () => { | 
					
						
							|  |  |  |     init({ | 
					
						
							|  |  |  |       '/tmp/src/test.ts': `
 | 
					
						
							|  |  |  |         export {exportedObj} from './export'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         export var obj = {a: 1}; | 
					
						
							|  |  |  |         export class SomeClass { | 
					
						
							|  |  |  |           static someField = 2; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |       '/tmp/src/export.ts': `
 | 
					
						
							|  |  |  |         export var exportedObj = {}; | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     expect(symbolResolver | 
					
						
							|  |  |  |                .resolveSymbol(symbolResolver.getStaticSymbol('/tmp/src/test.ts', 'obj', ['a'])) | 
					
						
							|  |  |  |                .metadata) | 
					
						
							|  |  |  |         .toBe(1); | 
					
						
							|  |  |  |     expect(symbolResolver | 
					
						
							|  |  |  |                .resolveSymbol( | 
					
						
							|  |  |  |                    symbolResolver.getStaticSymbol('/tmp/src/test.ts', 'SomeClass', ['someField'])) | 
					
						
							|  |  |  |                .metadata) | 
					
						
							|  |  |  |         .toBe(2); | 
					
						
							|  |  |  |     expect(symbolResolver | 
					
						
							|  |  |  |                .resolveSymbol(symbolResolver.getStaticSymbol( | 
					
						
							|  |  |  |                    '/tmp/src/test.ts', 'exportedObj', ['someMember'])) | 
					
						
							|  |  |  |                .metadata) | 
					
						
							|  |  |  |         .toBe(symbolResolver.getStaticSymbol('/tmp/src/export.ts', 'exportedObj', ['someMember'])); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should use summaries in resolveSymbol and prefer them over regular metadata', () => { | 
					
						
							| 
									
										
										
										
											2017-08-22 16:18:18 -07:00
										 |  |  |     const symbolA = symbolCache.get('/test.ts', 'a'); | 
					
						
							|  |  |  |     const symbolB = symbolCache.get('/test.ts', 'b'); | 
					
						
							|  |  |  |     const symbolC = symbolCache.get('/test.ts', 'c'); | 
					
						
							|  |  |  |     init({'/test.ts': 'export var a = 2; export var b = 2; export var c = 2;'}, [ | 
					
						
							|  |  |  |       {symbol: symbolA, metadata: 1}, | 
					
						
							|  |  |  |       {symbol: symbolB, metadata: 1}, | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  |     // reading the metadata of a symbol without a summary first,
 | 
					
						
							|  |  |  |     // to test whether summaries are still preferred after this.
 | 
					
						
							|  |  |  |     expect(symbolResolver.resolveSymbol(symbolC).metadata).toBe(2); | 
					
						
							|  |  |  |     expect(symbolResolver.resolveSymbol(symbolA).metadata).toBe(1); | 
					
						
							|  |  |  |     expect(symbolResolver.resolveSymbol(symbolB).metadata).toBe(1); | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to get all exported symbols of a file', () => { | 
					
						
							|  |  |  |     expect(symbolResolver.getSymbolsOf('/tmp/src/reexport/src/origin1.d.ts')).toEqual([ | 
					
						
							|  |  |  |       symbolResolver.getStaticSymbol('/tmp/src/reexport/src/origin1.d.ts', 'One'), | 
					
						
							|  |  |  |       symbolResolver.getStaticSymbol('/tmp/src/reexport/src/origin1.d.ts', 'Two'), | 
					
						
							|  |  |  |       symbolResolver.getStaticSymbol('/tmp/src/reexport/src/origin1.d.ts', 'Three'), | 
					
						
							| 
									
										
										
										
											2017-09-24 11:19:01 -07:00
										 |  |  |       symbolResolver.getStaticSymbol('/tmp/src/reexport/src/origin1.d.ts', 'Six'), | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |     ]); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to get all reexported symbols of a file', () => { | 
					
						
							|  |  |  |     expect(symbolResolver.getSymbolsOf('/tmp/src/reexport/reexport.d.ts')).toEqual([ | 
					
						
							|  |  |  |       symbolResolver.getStaticSymbol('/tmp/src/reexport/reexport.d.ts', 'One'), | 
					
						
							|  |  |  |       symbolResolver.getStaticSymbol('/tmp/src/reexport/reexport.d.ts', 'Two'), | 
					
						
							|  |  |  |       symbolResolver.getStaticSymbol('/tmp/src/reexport/reexport.d.ts', 'Four'), | 
					
						
							| 
									
										
										
										
											2017-09-24 11:19:01 -07:00
										 |  |  |       symbolResolver.getStaticSymbol('/tmp/src/reexport/reexport.d.ts', 'Six'), | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |       symbolResolver.getStaticSymbol('/tmp/src/reexport/reexport.d.ts', 'Five'), | 
					
						
							| 
									
										
										
										
											2017-09-24 11:19:01 -07:00
										 |  |  |       symbolResolver.getStaticSymbol('/tmp/src/reexport/reexport.d.ts', 'Thirty'), | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |     ]); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-28 15:51:27 -07:00
										 |  |  |   it('should read the exported symbols of a file from the summary and ignore exports in the source', | 
					
						
							|  |  |  |      () => { | 
					
						
							|  |  |  |        const someSymbol = symbolCache.get('/test.ts', 'a'); | 
					
						
							|  |  |  |        init( | 
					
						
							|  |  |  |            {'/test.ts': 'export var b = 2'}, | 
					
						
							|  |  |  |            [{symbol: symbolCache.get('/test.ts', 'a'), metadata: 1}]); | 
					
						
							|  |  |  |        expect(symbolResolver.getSymbolsOf('/test.ts')).toEqual([symbolCache.get('/test.ts', 'a')]); | 
					
						
							|  |  |  |      }); | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-27 09:36:47 -08:00
										 |  |  |   describe('importAs', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should calculate importAs relationship for non source files without summaries', () => { | 
					
						
							|  |  |  |       init( | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             '/test.d.ts': [{ | 
					
						
							|  |  |  |               '__symbolic': 'module', | 
					
						
							| 
									
										
										
										
											2017-09-26 13:31:59 -07:00
										 |  |  |               'version': METADATA_VERSION, | 
					
						
							| 
									
										
										
										
											2016-12-27 09:36:47 -08:00
										 |  |  |               'metadata': { | 
					
						
							|  |  |  |                 'a': {'__symbolic': 'reference', 'name': 'b', 'module': './test2'}, | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             }], | 
					
						
							|  |  |  |             '/test2.d.ts': [{ | 
					
						
							|  |  |  |               '__symbolic': 'module', | 
					
						
							| 
									
										
										
										
											2017-09-26 13:31:59 -07:00
										 |  |  |               'version': METADATA_VERSION, | 
					
						
							| 
									
										
										
										
											2016-12-27 09:36:47 -08:00
										 |  |  |               'metadata': { | 
					
						
							|  |  |  |                 'b': {'__symbolic': 'reference', 'name': 'c', 'module': './test3'}, | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             }] | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           []); | 
					
						
							|  |  |  |       symbolResolver.getSymbolsOf('/test.d.ts'); | 
					
						
							|  |  |  |       symbolResolver.getSymbolsOf('/test2.d.ts'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(symbolResolver.getImportAs(symbolCache.get('/test2.d.ts', 'b'))) | 
					
						
							|  |  |  |           .toBe(symbolCache.get('/test.d.ts', 'a')); | 
					
						
							|  |  |  |       expect(symbolResolver.getImportAs(symbolCache.get('/test3.d.ts', 'c'))) | 
					
						
							|  |  |  |           .toBe(symbolCache.get('/test.d.ts', 'a')); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should calculate importAs relationship for non source files with summaries', () => { | 
					
						
							|  |  |  |       init( | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             '/test.ts': `
 | 
					
						
							|  |  |  |           export {a} from './test2'; | 
					
						
							|  |  |  |         `
 | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           [], [{ | 
					
						
							|  |  |  |             symbol: symbolCache.get('/test2.d.ts', 'a'), | 
					
						
							|  |  |  |             importAs: symbolCache.get('/test3.d.ts', 'b') | 
					
						
							|  |  |  |           }]); | 
					
						
							|  |  |  |       symbolResolver.getSymbolsOf('/test.ts'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(symbolResolver.getImportAs(symbolCache.get('/test2.d.ts', 'a'))) | 
					
						
							|  |  |  |           .toBe(symbolCache.get('/test3.d.ts', 'b')); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-11 08:50:46 -08:00
										 |  |  |     it('should ignore summaries for inputAs if requested', () => { | 
					
						
							|  |  |  |       init( | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             '/test.ts': `
 | 
					
						
							|  |  |  |         export {a} from './test2'; | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           [], [{ | 
					
						
							|  |  |  |             symbol: symbolCache.get('/test2.d.ts', 'a'), | 
					
						
							|  |  |  |             importAs: symbolCache.get('/test3.d.ts', 'b') | 
					
						
							|  |  |  |           }]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       symbolResolver.getSymbolsOf('/test.ts'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect( | 
					
						
							|  |  |  |           symbolResolver.getImportAs(symbolCache.get('/test2.d.ts', 'a'), /* useSummaries */ false)) | 
					
						
							|  |  |  |           .toBeUndefined(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-27 09:36:47 -08:00
										 |  |  |     it('should calculate importAs for symbols with members based on importAs for symbols without', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          init( | 
					
						
							|  |  |  |              { | 
					
						
							|  |  |  |                '/test.ts': `
 | 
					
						
							|  |  |  |           export {a} from './test2'; | 
					
						
							|  |  |  |         `
 | 
					
						
							|  |  |  |              }, | 
					
						
							|  |  |  |              [], [{ | 
					
						
							|  |  |  |                symbol: symbolCache.get('/test2.d.ts', 'a'), | 
					
						
							|  |  |  |                importAs: symbolCache.get('/test3.d.ts', 'b') | 
					
						
							|  |  |  |              }]); | 
					
						
							|  |  |  |          symbolResolver.getSymbolsOf('/test.ts'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          expect(symbolResolver.getImportAs(symbolCache.get('/test2.d.ts', 'a', ['someMember']))) | 
					
						
							|  |  |  |              .toBe(symbolCache.get('/test3.d.ts', 'b', ['someMember'])); | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |   it('should replace references by StaticSymbols', () => { | 
					
						
							|  |  |  |     init({ | 
					
						
							|  |  |  |       '/test.ts': `
 | 
					
						
							|  |  |  |         import {b, y} from './test2'; | 
					
						
							|  |  |  |         export var a = b; | 
					
						
							|  |  |  |         export var x = [y]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         export function simpleFn(fnArg) { | 
					
						
							|  |  |  |           return [a, y, fnArg]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |       '/test2.ts': `
 | 
					
						
							|  |  |  |         export var b; | 
					
						
							|  |  |  |         export var y; | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'a')).metadata) | 
					
						
							|  |  |  |         .toEqual(symbolCache.get('/test2.ts', 'b')); | 
					
						
							| 
									
										
										
										
											2017-11-14 17:49:47 -08:00
										 |  |  |     expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'x')).metadata).toEqual([{ | 
					
						
							|  |  |  |       __symbolic: 'resolved', | 
					
						
							|  |  |  |       symbol: symbolCache.get('/test2.ts', 'y'), | 
					
						
							|  |  |  |       line: 3, | 
					
						
							|  |  |  |       character: 24, | 
					
						
							|  |  |  |       fileName: '/test.ts' | 
					
						
							|  |  |  |     }]); | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |     expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'simpleFn')).metadata).toEqual({ | 
					
						
							|  |  |  |       __symbolic: 'function', | 
					
						
							|  |  |  |       parameters: ['fnArg'], | 
					
						
							|  |  |  |       value: [ | 
					
						
							| 
									
										
										
										
											2017-11-14 17:49:47 -08:00
										 |  |  |         symbolCache.get('/test.ts', 'a'), { | 
					
						
							|  |  |  |           __symbolic: 'resolved', | 
					
						
							|  |  |  |           symbol: symbolCache.get('/test2.ts', 'y'), | 
					
						
							|  |  |  |           line: 6, | 
					
						
							|  |  |  |           character: 21, | 
					
						
							|  |  |  |           fileName: '/test.ts' | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         {__symbolic: 'reference', name: 'fnArg'} | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |       ] | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should ignore module references without a name', () => { | 
					
						
							|  |  |  |     init({ | 
					
						
							|  |  |  |       '/test.ts': `
 | 
					
						
							|  |  |  |         import Default from './test2'; | 
					
						
							|  |  |  |         export {Default}; | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'Default')).metadata) | 
					
						
							|  |  |  |         .toBeFalsy(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-27 09:36:47 -08:00
										 |  |  |   it('should fill references to ambient symbols with undefined', () => { | 
					
						
							|  |  |  |     init({ | 
					
						
							|  |  |  |       '/test.ts': `
 | 
					
						
							|  |  |  |         export var y = 1; | 
					
						
							|  |  |  |         export var z = [window, z]; | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'z')).metadata).toEqual([ | 
					
						
							|  |  |  |       undefined, symbolCache.get('/test.ts', 'z') | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should allow to use symbols with __', () => { | 
					
						
							|  |  |  |     init({ | 
					
						
							|  |  |  |       '/test.ts': `
 | 
					
						
							|  |  |  |         export {__a__ as __b__} from './test2'; | 
					
						
							|  |  |  |         import {__c__} from './test2'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         export var __x__ = 1; | 
					
						
							|  |  |  |         export var __y__ = __c__; | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', '__x__')).metadata).toBe(1); | 
					
						
							|  |  |  |     expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', '__y__')).metadata) | 
					
						
							|  |  |  |         .toBe(symbolCache.get('/test2.d.ts', '__c__')); | 
					
						
							|  |  |  |     expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', '__b__')).metadata) | 
					
						
							|  |  |  |         .toBe(symbolCache.get('/test2.d.ts', '__a__')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(symbolResolver.getSymbolsOf('/test.ts')).toEqual([ | 
					
						
							| 
									
										
										
										
											2017-09-24 11:19:01 -07:00
										 |  |  |       symbolCache.get('/test.ts', '__b__'), | 
					
						
							|  |  |  |       symbolCache.get('/test.ts', '__x__'), | 
					
						
							|  |  |  |       symbolCache.get('/test.ts', '__y__'), | 
					
						
							| 
									
										
										
										
											2016-12-27 09:36:47 -08:00
										 |  |  |     ]); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-30 14:51:29 -07:00
										 |  |  |   it('should only use the arity for classes from libraries without summaries', () => { | 
					
						
							|  |  |  |     init({ | 
					
						
							|  |  |  |       '/test.d.ts': [{ | 
					
						
							|  |  |  |         '__symbolic': 'module', | 
					
						
							| 
									
										
										
										
											2017-09-26 13:31:59 -07:00
										 |  |  |         'version': METADATA_VERSION, | 
					
						
							| 
									
										
										
										
											2017-03-30 14:51:29 -07:00
										 |  |  |         'metadata': { | 
					
						
							|  |  |  |           'AParam': {__symbolic: 'class'}, | 
					
						
							|  |  |  |           'AClass': { | 
					
						
							|  |  |  |             __symbolic: 'class', | 
					
						
							|  |  |  |             arity: 1, | 
					
						
							|  |  |  |             members: { | 
					
						
							|  |  |  |               __ctor__: [{ | 
					
						
							|  |  |  |                 __symbolic: 'constructor', | 
					
						
							|  |  |  |                 parameters: [symbolCache.get('/test.d.ts', 'AParam')] | 
					
						
							|  |  |  |               }] | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }] | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(symbolResolver.resolveSymbol(symbolCache.get('/test.d.ts', 'AClass')).metadata) | 
					
						
							|  |  |  |         .toEqual({__symbolic: 'class', arity: 1}); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |   it('should be able to trace a named export', () => { | 
					
						
							|  |  |  |     const symbol = symbolResolver | 
					
						
							|  |  |  |                        .resolveSymbol(symbolResolver.getSymbolByModule( | 
					
						
							|  |  |  |                            './reexport/reexport', 'One', '/tmp/src/main.ts')) | 
					
						
							|  |  |  |                        .metadata; | 
					
						
							|  |  |  |     expect(symbol.name).toEqual('One'); | 
					
						
							|  |  |  |     expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin1.d.ts'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to trace a renamed export', () => { | 
					
						
							|  |  |  |     const symbol = symbolResolver | 
					
						
							|  |  |  |                        .resolveSymbol(symbolResolver.getSymbolByModule( | 
					
						
							|  |  |  |                            './reexport/reexport', 'Four', '/tmp/src/main.ts')) | 
					
						
							|  |  |  |                        .metadata; | 
					
						
							|  |  |  |     expect(symbol.name).toEqual('Three'); | 
					
						
							|  |  |  |     expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin1.d.ts'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to trace an export * export', () => { | 
					
						
							|  |  |  |     const symbol = symbolResolver | 
					
						
							|  |  |  |                        .resolveSymbol(symbolResolver.getSymbolByModule( | 
					
						
							|  |  |  |                            './reexport/reexport', 'Five', '/tmp/src/main.ts')) | 
					
						
							|  |  |  |                        .metadata; | 
					
						
							|  |  |  |     expect(symbol.name).toEqual('Five'); | 
					
						
							|  |  |  |     expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin5.d.ts'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to trace a multi-level re-export', () => { | 
					
						
							|  |  |  |     const symbol1 = symbolResolver | 
					
						
							|  |  |  |                         .resolveSymbol(symbolResolver.getSymbolByModule( | 
					
						
							|  |  |  |                             './reexport/reexport', 'Thirty', '/tmp/src/main.ts')) | 
					
						
							|  |  |  |                         .metadata; | 
					
						
							|  |  |  |     expect(symbol1.name).toEqual('Thirty'); | 
					
						
							|  |  |  |     expect(symbol1.filePath).toEqual('/tmp/src/reexport/src/reexport2.d.ts'); | 
					
						
							|  |  |  |     const symbol2 = symbolResolver.resolveSymbol(symbol1).metadata; | 
					
						
							|  |  |  |     expect(symbol2.name).toEqual('Thirty'); | 
					
						
							|  |  |  |     expect(symbol2.filePath).toEqual('/tmp/src/reexport/src/origin30.d.ts'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-24 11:19:01 -07:00
										 |  |  |   it('should prefer names in the file over reexports', () => { | 
					
						
							|  |  |  |     const metadata = symbolResolver | 
					
						
							|  |  |  |                          .resolveSymbol(symbolResolver.getSymbolByModule( | 
					
						
							|  |  |  |                              './reexport/reexport', 'Six', '/tmp/src/main.ts')) | 
					
						
							|  |  |  |                          .metadata; | 
					
						
							|  |  |  |     expect(metadata.__symbolic).toBe('class'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |   it('should cache tracing a named export', () => { | 
					
						
							|  |  |  |     const moduleNameToFileNameSpy = spyOn(host, 'moduleNameToFileName').and.callThrough(); | 
					
						
							|  |  |  |     const getMetadataForSpy = spyOn(host, 'getMetadataFor').and.callThrough(); | 
					
						
							|  |  |  |     symbolResolver.resolveSymbol( | 
					
						
							|  |  |  |         symbolResolver.getSymbolByModule('./reexport/reexport', 'One', '/tmp/src/main.ts')); | 
					
						
							|  |  |  |     moduleNameToFileNameSpy.calls.reset(); | 
					
						
							|  |  |  |     getMetadataForSpy.calls.reset(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const symbol = symbolResolver | 
					
						
							|  |  |  |                        .resolveSymbol(symbolResolver.getSymbolByModule( | 
					
						
							|  |  |  |                            './reexport/reexport', 'One', '/tmp/src/main.ts')) | 
					
						
							|  |  |  |                        .metadata; | 
					
						
							|  |  |  |     expect(moduleNameToFileNameSpy.calls.count()).toBe(1); | 
					
						
							|  |  |  |     expect(getMetadataForSpy.calls.count()).toBe(0); | 
					
						
							|  |  |  |     expect(symbol.name).toEqual('One'); | 
					
						
							|  |  |  |     expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin1.d.ts'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class MockSummaryResolver implements SummaryResolver<StaticSymbol> { | 
					
						
							| 
									
										
										
										
											2016-12-27 09:36:47 -08:00
										 |  |  |   constructor(private summaries: Summary<StaticSymbol>[] = [], private importAs: { | 
					
						
							|  |  |  |     symbol: StaticSymbol, | 
					
						
							|  |  |  |     importAs: StaticSymbol | 
					
						
							|  |  |  |   }[] = []) {} | 
					
						
							| 
									
										
										
										
											2017-09-22 19:51:03 +02:00
										 |  |  |   addSummary(summary: Summary<StaticSymbol>) { this.summaries.push(summary); } | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |   resolveSummary(reference: StaticSymbol): Summary<StaticSymbol> { | 
					
						
							| 
									
										
										
										
											2018-12-19 13:06:43 -08:00
										 |  |  |     return this.summaries.find(summary => summary.symbol === reference) !; | 
					
						
							| 
									
										
										
										
											2017-09-22 19:51:03 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-08-28 15:51:27 -07:00
										 |  |  |   getSymbolsOf(filePath: string): StaticSymbol[]|null { | 
					
						
							|  |  |  |     const symbols = this.summaries.filter(summary => summary.symbol.filePath === filePath) | 
					
						
							|  |  |  |                         .map(summary => summary.symbol); | 
					
						
							|  |  |  |     return symbols.length ? symbols : null; | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-12-27 09:36:47 -08:00
										 |  |  |   getImportAs(symbol: StaticSymbol): StaticSymbol { | 
					
						
							|  |  |  |     const entry = this.importAs.find(entry => entry.symbol === symbol); | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:58 -07:00
										 |  |  |     return entry ? entry.importAs : undefined !; | 
					
						
							| 
									
										
										
										
											2016-12-27 09:36:47 -08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-09-28 09:39:16 -07:00
										 |  |  |   getKnownModuleName(fileName: string): string|null { return null; } | 
					
						
							| 
									
										
										
										
											2016-12-27 09:36:47 -08:00
										 |  |  |   isLibraryFile(filePath: string): boolean { return filePath.endsWith('.d.ts'); } | 
					
						
							| 
									
										
										
										
											2017-08-15 14:41:48 -07:00
										 |  |  |   toSummaryFileName(filePath: string): string { return filePath.replace(/(\.d)?\.ts$/, '.d.ts'); } | 
					
						
							|  |  |  |   fromSummaryFileName(filePath: string): string { return filePath; } | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class MockStaticSymbolResolverHost implements StaticSymbolResolverHost { | 
					
						
							| 
									
										
										
										
											2017-03-01 13:23:34 -08:00
										 |  |  |   private collector: MetadataCollector; | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-01 13:23:34 -08:00
										 |  |  |   constructor(private data: {[key: string]: any}, collectorOptions?: CollectorOptions) { | 
					
						
							|  |  |  |     this.collector = new MetadataCollector(collectorOptions); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // In tests, assume that symbols are not re-exported
 | 
					
						
							|  |  |  |   moduleNameToFileName(modulePath: string, containingFile?: string): string { | 
					
						
							|  |  |  |     function splitPath(path: string): string[] { return path.split(/\/|\\/g); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function resolvePath(pathParts: string[]): string { | 
					
						
							|  |  |  |       const result: string[] = []; | 
					
						
							|  |  |  |       pathParts.forEach((part, index) => { | 
					
						
							|  |  |  |         switch (part) { | 
					
						
							|  |  |  |           case '': | 
					
						
							|  |  |  |           case '.': | 
					
						
							|  |  |  |             if (index > 0) return; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           case '..': | 
					
						
							|  |  |  |             if (index > 0 && result.length != 0) result.pop(); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         result.push(part); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       return result.join('/'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function pathTo(from: string, to: string): string { | 
					
						
							|  |  |  |       let result = to; | 
					
						
							|  |  |  |       if (to.startsWith('.')) { | 
					
						
							|  |  |  |         const fromParts = splitPath(from); | 
					
						
							|  |  |  |         fromParts.pop();  // remove the file name.
 | 
					
						
							|  |  |  |         const toParts = splitPath(to); | 
					
						
							|  |  |  |         result = resolvePath(fromParts.concat(toParts)); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (modulePath.indexOf('.') === 0) { | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:58 -07:00
										 |  |  |       const baseName = pathTo(containingFile !, modulePath); | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |       const tsName = baseName + '.ts'; | 
					
						
							|  |  |  |       if (this._getMetadataFor(tsName)) { | 
					
						
							|  |  |  |         return tsName; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return baseName + '.d.ts'; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-04-14 09:02:32 -07:00
										 |  |  |     if (modulePath == 'unresolved') { | 
					
						
							| 
									
										
										
										
											2017-04-14 14:40:56 -07:00
										 |  |  |       return undefined !; | 
					
						
							| 
									
										
										
										
											2017-04-14 09:02:32 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |     return '/tmp/' + modulePath + '.d.ts'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getMetadataFor(moduleId: string): any { return this._getMetadataFor(moduleId); } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-10 09:55:03 -08:00
										 |  |  |   getOutputName(filePath: string): string { return filePath; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |   private _getMetadataFor(filePath: string): any { | 
					
						
							|  |  |  |     if (this.data[filePath] && filePath.match(TS_EXT)) { | 
					
						
							|  |  |  |       const text = this.data[filePath]; | 
					
						
							|  |  |  |       if (typeof text === 'string') { | 
					
						
							|  |  |  |         const sf = ts.createSourceFile( | 
					
						
							|  |  |  |             filePath, this.data[filePath], ts.ScriptTarget.ES5, /* setParentNodes */ true); | 
					
						
							|  |  |  |         const diagnostics: ts.Diagnostic[] = (<any>sf).parseDiagnostics; | 
					
						
							|  |  |  |         if (diagnostics && diagnostics.length) { | 
					
						
							| 
									
										
										
										
											2017-07-13 17:16:56 -06:00
										 |  |  |           const errors = | 
					
						
							|  |  |  |               diagnostics | 
					
						
							|  |  |  |                   .map(d => { | 
					
						
							| 
									
										
										
										
											2017-08-02 16:26:42 -07:00
										 |  |  |                     const {line, character} = ts.getLineAndCharacterOfPosition(d.file !, d.start !); | 
					
						
							| 
									
										
										
										
											2017-07-13 17:16:56 -06:00
										 |  |  |                     return `(${line}:${character}): ${d.messageText}`; | 
					
						
							|  |  |  |                   }) | 
					
						
							|  |  |  |                   .join('\n'); | 
					
						
							| 
									
										
										
										
											2017-03-15 09:24:56 -07:00
										 |  |  |           throw Error(`Error encountered during parse of file ${filePath}\n${errors}`); | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |         } | 
					
						
							|  |  |  |         return [this.collector.getMetadata(sf)]; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const result = this.data[filePath]; | 
					
						
							|  |  |  |     if (result) { | 
					
						
							|  |  |  |       return Array.isArray(result) ? result : [result]; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const DEFAULT_TEST_DATA: {[key: string]: any} = { | 
					
						
							|  |  |  |   '/tmp/src/version-error.d.ts': {'__symbolic': 'module', 'version': 100, metadata: {e: 's'}}, | 
					
						
							|  |  |  |   '/tmp/src/version-2-error.d.ts': {'__symbolic': 'module', 'version': 2, metadata: {e: 's'}}, | 
					
						
							|  |  |  |   '/tmp/src/reexport/reexport.d.ts': { | 
					
						
							|  |  |  |     __symbolic: 'module', | 
					
						
							| 
									
										
										
										
											2017-09-26 13:31:59 -07:00
										 |  |  |     version: METADATA_VERSION, | 
					
						
							| 
									
										
										
										
											2017-09-24 11:19:01 -07:00
										 |  |  |     metadata: { | 
					
						
							|  |  |  |       Six: {__symbolic: 'class'}, | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |     exports: [ | 
					
						
							| 
									
										
										
										
											2017-09-24 11:19:01 -07:00
										 |  |  |       {from: './src/origin1', export: ['One', 'Two', {name: 'Three', as: 'Four'}, 'Six']}, | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |       {from: './src/origin5'}, {from: './src/reexport2'} | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   '/tmp/src/reexport/src/origin1.d.ts': { | 
					
						
							|  |  |  |     __symbolic: 'module', | 
					
						
							| 
									
										
										
										
											2017-09-26 13:31:59 -07:00
										 |  |  |     version: METADATA_VERSION, | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |     metadata: { | 
					
						
							|  |  |  |       One: {__symbolic: 'class'}, | 
					
						
							|  |  |  |       Two: {__symbolic: 'class'}, | 
					
						
							|  |  |  |       Three: {__symbolic: 'class'}, | 
					
						
							| 
									
										
										
										
											2017-09-24 11:19:01 -07:00
										 |  |  |       Six: {__symbolic: 'class'}, | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |     }, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   '/tmp/src/reexport/src/origin5.d.ts': { | 
					
						
							|  |  |  |     __symbolic: 'module', | 
					
						
							| 
									
										
										
										
											2017-09-26 13:31:59 -07:00
										 |  |  |     version: METADATA_VERSION, | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |     metadata: { | 
					
						
							|  |  |  |       Five: {__symbolic: 'class'}, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   '/tmp/src/reexport/src/origin30.d.ts': { | 
					
						
							|  |  |  |     __symbolic: 'module', | 
					
						
							| 
									
										
										
										
											2017-09-26 13:31:59 -07:00
										 |  |  |     version: METADATA_VERSION, | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |     metadata: { | 
					
						
							|  |  |  |       Thirty: {__symbolic: 'class'}, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   '/tmp/src/reexport/src/originNone.d.ts': { | 
					
						
							|  |  |  |     __symbolic: 'module', | 
					
						
							| 
									
										
										
										
											2017-09-26 13:31:59 -07:00
										 |  |  |     version: METADATA_VERSION, | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |     metadata: {}, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   '/tmp/src/reexport/src/reexport2.d.ts': { | 
					
						
							|  |  |  |     __symbolic: 'module', | 
					
						
							| 
									
										
										
										
											2017-09-26 13:31:59 -07:00
										 |  |  |     version: METADATA_VERSION, | 
					
						
							| 
									
										
										
										
											2016-12-15 09:12:40 -08:00
										 |  |  |     metadata: {}, | 
					
						
							|  |  |  |     exports: [{from: './originNone'}, {from: './origin30'}] | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; |