Update the license headers throughout the repository to reference Google LLC rather than Google Inc, for the required license headers. PR Close #37205
		
			
				
	
	
		
			604 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			604 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
/**
 | 
						|
 * @license
 | 
						|
 * Copyright Google LLC 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';
 | 
						|
import {CollectorOptions, METADATA_VERSION} from '@angular/compiler-cli';
 | 
						|
import {MetadataCollector} from '@angular/compiler-cli/src/metadata/collector';
 | 
						|
import * as ts from 'typescript';
 | 
						|
 | 
						|
// This matches .ts files but not .d.ts files.
 | 
						|
const TS_EXT = /(^.|(?!\.d)..)\.ts$/;
 | 
						|
 | 
						|
describe('StaticSymbolResolver', () => {
 | 
						|
  let host: StaticSymbolResolverHost;
 | 
						|
  let symbolResolver: StaticSymbolResolver;
 | 
						|
  let symbolCache: StaticSymbolCache;
 | 
						|
 | 
						|
  beforeEach(() => {
 | 
						|
    symbolCache = new StaticSymbolCache();
 | 
						|
  });
 | 
						|
 | 
						|
  function init(
 | 
						|
      testData: {[key: string]: any} = DEFAULT_TEST_DATA, summaries: Summary<StaticSymbol>[] = [],
 | 
						|
      summaryImportAs: {symbol: StaticSymbol, importAs: StaticSymbol}[] = []) {
 | 
						|
    host = new MockStaticSymbolResolverHost(testData);
 | 
						|
    symbolResolver = new StaticSymbolResolver(
 | 
						|
        host, symbolCache, new MockSummaryResolver(summaries, summaryImportAs));
 | 
						|
  }
 | 
						|
 | 
						|
  beforeEach(() => init());
 | 
						|
 | 
						|
  it('should throw an exception for unsupported metadata versions', () => {
 | 
						|
    expect(
 | 
						|
        () => symbolResolver.resolveSymbol(
 | 
						|
            symbolResolver.getSymbolByModule('src/version-error', 'e')))
 | 
						|
        .toThrow(new Error(
 | 
						|
            `Metadata version mismatch for module /tmp/src/version-error.d.ts, found version 100, expected ${
 | 
						|
                METADATA_VERSION}`));
 | 
						|
  });
 | 
						|
 | 
						|
  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 not explore re-exports of the same module', () => {
 | 
						|
    init({
 | 
						|
      '/tmp/src/test.ts': `
 | 
						|
        export * from './test';
 | 
						|
 | 
						|
        export const testValue = 10;
 | 
						|
      `,
 | 
						|
    });
 | 
						|
 | 
						|
    const symbols = symbolResolver.getSymbolsOf('/tmp/src/test.ts');
 | 
						|
    expect(symbols).toEqual([symbolResolver.getStaticSymbol('/tmp/src/test.ts', 'testValue')]);
 | 
						|
  });
 | 
						|
 | 
						|
  it('should use summaries in resolveSymbol and prefer them over regular metadata', () => {
 | 
						|
    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);
 | 
						|
  });
 | 
						|
 | 
						|
  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'),
 | 
						|
      symbolResolver.getStaticSymbol('/tmp/src/reexport/src/origin1.d.ts', 'Six'),
 | 
						|
    ]);
 | 
						|
  });
 | 
						|
 | 
						|
  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'),
 | 
						|
      symbolResolver.getStaticSymbol('/tmp/src/reexport/reexport.d.ts', 'Six'),
 | 
						|
      symbolResolver.getStaticSymbol('/tmp/src/reexport/reexport.d.ts', 'Five'),
 | 
						|
      symbolResolver.getStaticSymbol('/tmp/src/reexport/reexport.d.ts', 'Thirty'),
 | 
						|
    ]);
 | 
						|
  });
 | 
						|
 | 
						|
  it('should read the exported symbols of a file from the summary and ignore exports in the source',
 | 
						|
     () => {
 | 
						|
       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')]);
 | 
						|
     });
 | 
						|
 | 
						|
  describe('importAs', () => {
 | 
						|
    it('should calculate importAs relationship for non source files without summaries', () => {
 | 
						|
      init(
 | 
						|
          {
 | 
						|
            '/test.d.ts': [{
 | 
						|
              '__symbolic': 'module',
 | 
						|
              'version': METADATA_VERSION,
 | 
						|
              'metadata': {
 | 
						|
                'a': {'__symbolic': 'reference', 'name': 'b', 'module': './test2'},
 | 
						|
              }
 | 
						|
            }],
 | 
						|
            '/test2.d.ts': [{
 | 
						|
              '__symbolic': 'module',
 | 
						|
              'version': METADATA_VERSION,
 | 
						|
              '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'));
 | 
						|
    });
 | 
						|
 | 
						|
    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();
 | 
						|
    });
 | 
						|
 | 
						|
    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']));
 | 
						|
       });
 | 
						|
  });
 | 
						|
 | 
						|
  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'));
 | 
						|
    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'
 | 
						|
    }]);
 | 
						|
    expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'simpleFn')).metadata).toEqual({
 | 
						|
      __symbolic: 'function',
 | 
						|
      parameters: ['fnArg'],
 | 
						|
      value: [
 | 
						|
        symbolCache.get('/test.ts', 'a'), {
 | 
						|
          __symbolic: 'resolved',
 | 
						|
          symbol: symbolCache.get('/test2.ts', 'y'),
 | 
						|
          line: 6,
 | 
						|
          character: 21,
 | 
						|
          fileName: '/test.ts'
 | 
						|
        },
 | 
						|
        {__symbolic: 'reference', name: 'fnArg'}
 | 
						|
      ]
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  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();
 | 
						|
  });
 | 
						|
 | 
						|
  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([
 | 
						|
      symbolCache.get('/test.ts', '__b__'),
 | 
						|
      symbolCache.get('/test.ts', '__x__'),
 | 
						|
      symbolCache.get('/test.ts', '__y__'),
 | 
						|
    ]);
 | 
						|
  });
 | 
						|
 | 
						|
  it('should only use the arity for classes from libraries without summaries', () => {
 | 
						|
    init({
 | 
						|
      '/test.d.ts': [{
 | 
						|
        '__symbolic': 'module',
 | 
						|
        'version': METADATA_VERSION,
 | 
						|
        '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});
 | 
						|
  });
 | 
						|
 | 
						|
  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');
 | 
						|
  });
 | 
						|
 | 
						|
  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');
 | 
						|
  });
 | 
						|
 | 
						|
  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> {
 | 
						|
  constructor(private summaries: Summary<StaticSymbol>[] = [], private importAs: {
 | 
						|
    symbol: StaticSymbol,
 | 
						|
    importAs: StaticSymbol
 | 
						|
  }[] = []) {}
 | 
						|
  addSummary(summary: Summary<StaticSymbol>) {
 | 
						|
    this.summaries.push(summary);
 | 
						|
  }
 | 
						|
  resolveSummary(reference: StaticSymbol): Summary<StaticSymbol> {
 | 
						|
    return this.summaries.find(summary => summary.symbol === reference)!;
 | 
						|
  }
 | 
						|
  getSymbolsOf(filePath: string): StaticSymbol[]|null {
 | 
						|
    const symbols = this.summaries.filter(summary => summary.symbol.filePath === filePath)
 | 
						|
                        .map(summary => summary.symbol);
 | 
						|
    return symbols.length ? symbols : null;
 | 
						|
  }
 | 
						|
  getImportAs(symbol: StaticSymbol): StaticSymbol {
 | 
						|
    const entry = this.importAs.find(entry => entry.symbol === symbol);
 | 
						|
    return entry ? entry.importAs : undefined!;
 | 
						|
  }
 | 
						|
  getKnownModuleName(fileName: string): string|null {
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
  isLibraryFile(filePath: string): boolean {
 | 
						|
    return filePath.endsWith('.d.ts');
 | 
						|
  }
 | 
						|
  toSummaryFileName(filePath: string): string {
 | 
						|
    return filePath.replace(/(\.d)?\.ts$/, '.d.ts');
 | 
						|
  }
 | 
						|
  fromSummaryFileName(filePath: string): string {
 | 
						|
    return filePath;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
export class MockStaticSymbolResolverHost implements StaticSymbolResolverHost {
 | 
						|
  private collector: MetadataCollector;
 | 
						|
 | 
						|
  constructor(private data: {[key: string]: any}, collectorOptions?: CollectorOptions) {
 | 
						|
    this.collector = new MetadataCollector(collectorOptions);
 | 
						|
  }
 | 
						|
 | 
						|
  // 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) {
 | 
						|
      const baseName = pathTo(containingFile!, modulePath);
 | 
						|
      const tsName = baseName + '.ts';
 | 
						|
      if (this._getMetadataFor(tsName)) {
 | 
						|
        return tsName;
 | 
						|
      }
 | 
						|
      return baseName + '.d.ts';
 | 
						|
    }
 | 
						|
    if (modulePath == 'unresolved') {
 | 
						|
      return undefined!;
 | 
						|
    }
 | 
						|
    return '/tmp/' + modulePath + '.d.ts';
 | 
						|
  }
 | 
						|
 | 
						|
  getMetadataFor(moduleId: string): any {
 | 
						|
    return this._getMetadataFor(moduleId);
 | 
						|
  }
 | 
						|
 | 
						|
  getOutputName(filePath: string): string {
 | 
						|
    return filePath;
 | 
						|
  }
 | 
						|
 | 
						|
  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) {
 | 
						|
          const errors = diagnostics
 | 
						|
                             .map(d => {
 | 
						|
                               const {line, character} =
 | 
						|
                                   ts.getLineAndCharacterOfPosition(d.file!, d.start!);
 | 
						|
                               return `(${line}:${character}): ${d.messageText}`;
 | 
						|
                             })
 | 
						|
                             .join('\n');
 | 
						|
          throw Error(`Error encountered during parse of file ${filePath}\n${errors}`);
 | 
						|
        }
 | 
						|
        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',
 | 
						|
    version: METADATA_VERSION,
 | 
						|
    metadata: {
 | 
						|
      Six: {__symbolic: 'class'},
 | 
						|
    },
 | 
						|
    exports: [
 | 
						|
      {from: './src/origin1', export: ['One', 'Two', {name: 'Three', as: 'Four'}, 'Six']},
 | 
						|
      {from: './src/origin5'}, {from: './src/reexport2'}
 | 
						|
    ]
 | 
						|
  },
 | 
						|
  '/tmp/src/reexport/src/origin1.d.ts': {
 | 
						|
    __symbolic: 'module',
 | 
						|
    version: METADATA_VERSION,
 | 
						|
    metadata: {
 | 
						|
      One: {__symbolic: 'class'},
 | 
						|
      Two: {__symbolic: 'class'},
 | 
						|
      Three: {__symbolic: 'class'},
 | 
						|
      Six: {__symbolic: 'class'},
 | 
						|
    },
 | 
						|
  },
 | 
						|
  '/tmp/src/reexport/src/origin5.d.ts': {
 | 
						|
    __symbolic: 'module',
 | 
						|
    version: METADATA_VERSION,
 | 
						|
    metadata: {
 | 
						|
      Five: {__symbolic: 'class'},
 | 
						|
    },
 | 
						|
  },
 | 
						|
  '/tmp/src/reexport/src/origin30.d.ts': {
 | 
						|
    __symbolic: 'module',
 | 
						|
    version: METADATA_VERSION,
 | 
						|
    metadata: {
 | 
						|
      Thirty: {__symbolic: 'class'},
 | 
						|
    },
 | 
						|
  },
 | 
						|
  '/tmp/src/reexport/src/originNone.d.ts': {
 | 
						|
    __symbolic: 'module',
 | 
						|
    version: METADATA_VERSION,
 | 
						|
    metadata: {},
 | 
						|
  },
 | 
						|
  '/tmp/src/reexport/src/reexport2.d.ts': {
 | 
						|
    __symbolic: 'module',
 | 
						|
    version: METADATA_VERSION,
 | 
						|
    metadata: {},
 | 
						|
    exports: [{from: './originNone'}, {from: './origin30'}]
 | 
						|
  }
 | 
						|
};
 |