2016-06-23 12:47:54 -04: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
|
|
|
|
*/
|
|
|
|
|
2016-10-03 19:46:05 -04:00
|
|
|
import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
|
2016-06-09 17:51:53 -04:00
|
|
|
import * as ts from 'typescript';
|
|
|
|
|
2016-06-20 11:09:16 -04:00
|
|
|
import {ReflectorHost} from '../src/reflector_host';
|
2016-06-09 17:51:53 -04:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
import {Directory, Entry, MockCompilerHost, MockContext} from './mocks';
|
2016-06-09 17:51:53 -04:00
|
|
|
|
|
|
|
describe('reflector_host', () => {
|
|
|
|
var context: MockContext;
|
|
|
|
var host: ts.CompilerHost;
|
|
|
|
var program: ts.Program;
|
2016-08-04 00:34:03 -04:00
|
|
|
var reflectorNestedGenDir: ReflectorHost;
|
|
|
|
var reflectorSiblingGenDir: ReflectorHost;
|
2016-06-09 17:51:53 -04:00
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
context = new MockContext('/tmp/src', clone(FILES));
|
2016-07-21 20:12:00 -04:00
|
|
|
host = new MockCompilerHost(context);
|
2016-06-08 19:38:52 -04:00
|
|
|
program = ts.createProgram(
|
|
|
|
['main.ts'], {
|
|
|
|
module: ts.ModuleKind.CommonJS,
|
|
|
|
},
|
|
|
|
host);
|
2016-06-09 17:51:53 -04:00
|
|
|
// Force a typecheck
|
|
|
|
let errors = program.getSemanticDiagnostics();
|
|
|
|
if (errors && errors.length) {
|
|
|
|
throw new Error('Expected no errors');
|
|
|
|
}
|
2016-08-04 00:34:03 -04:00
|
|
|
reflectorNestedGenDir = new ReflectorHost(
|
2016-06-08 19:38:52 -04:00
|
|
|
program, host, {
|
2016-08-12 20:38:29 -04:00
|
|
|
genDir: '/tmp/project/src/gen/',
|
|
|
|
basePath: '/tmp/project/src',
|
2016-06-08 19:38:52 -04:00
|
|
|
skipMetadataEmit: false,
|
2016-08-22 20:37:48 -04:00
|
|
|
strictMetadataEmit: false,
|
2016-06-08 19:38:52 -04:00
|
|
|
skipTemplateCodegen: false,
|
|
|
|
trace: false
|
|
|
|
},
|
|
|
|
context);
|
2016-08-04 00:34:03 -04:00
|
|
|
reflectorSiblingGenDir = new ReflectorHost(
|
|
|
|
program, host, {
|
2016-08-12 20:38:29 -04:00
|
|
|
genDir: '/tmp/project/gen',
|
|
|
|
basePath: '/tmp/project/src/',
|
2016-08-04 00:34:03 -04:00
|
|
|
skipMetadataEmit: false,
|
2016-08-22 20:37:48 -04:00
|
|
|
strictMetadataEmit: false,
|
2016-08-04 00:34:03 -04:00
|
|
|
skipTemplateCodegen: false,
|
|
|
|
trace: false
|
|
|
|
},
|
|
|
|
context);
|
|
|
|
});
|
|
|
|
|
2016-08-12 20:38:29 -04:00
|
|
|
describe('nestedGenDir', () => {
|
2016-08-04 00:34:03 -04:00
|
|
|
it('should import node_module from factory', () => {
|
|
|
|
expect(reflectorNestedGenDir.getImportPath(
|
2016-08-12 20:38:29 -04:00
|
|
|
'/tmp/project/src/gen/my.ngfactory.ts',
|
|
|
|
'/tmp/project/node_modules/@angular/core.d.ts'))
|
2016-08-04 00:34:03 -04:00
|
|
|
.toEqual('@angular/core');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should import factory from factory', () => {
|
|
|
|
expect(reflectorNestedGenDir.getImportPath(
|
2016-08-12 20:38:29 -04:00
|
|
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ngfactory.ts'))
|
2016-08-04 00:34:03 -04:00
|
|
|
.toEqual('./my.other.ngfactory');
|
|
|
|
expect(reflectorNestedGenDir.getImportPath(
|
2016-08-12 20:38:29 -04:00
|
|
|
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.css.ts'))
|
2016-08-04 00:34:03 -04:00
|
|
|
.toEqual('../my.other.css');
|
|
|
|
expect(reflectorNestedGenDir.getImportPath(
|
2016-08-12 20:38:29 -04:00
|
|
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.css.shim.ts'))
|
2016-08-04 00:34:03 -04:00
|
|
|
.toEqual('./a/my.other.css.shim');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should import application from factory', () => {
|
2016-08-12 20:38:29 -04:00
|
|
|
expect(reflectorNestedGenDir.getImportPath(
|
|
|
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
|
2016-08-04 00:34:03 -04:00
|
|
|
.toEqual('../my.other');
|
2016-08-12 20:38:29 -04:00
|
|
|
expect(reflectorNestedGenDir.getImportPath(
|
|
|
|
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
|
2016-08-04 00:34:03 -04:00
|
|
|
.toEqual('../../my.other');
|
2016-08-12 20:38:29 -04:00
|
|
|
expect(reflectorNestedGenDir.getImportPath(
|
|
|
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.ts'))
|
2016-08-04 00:34:03 -04:00
|
|
|
.toEqual('../a/my.other');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-08-12 20:38:29 -04:00
|
|
|
describe('nestedGenDir', () => {
|
2016-08-04 00:34:03 -04:00
|
|
|
it('should import node_module from factory', () => {
|
|
|
|
expect(reflectorSiblingGenDir.getImportPath(
|
2016-08-12 20:38:29 -04:00
|
|
|
'/tmp/project/src/gen/my.ngfactory.ts',
|
|
|
|
'/tmp/project/node_modules/@angular/core.d.ts'))
|
2016-08-04 00:34:03 -04:00
|
|
|
.toEqual('@angular/core');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should import factory from factory', () => {
|
|
|
|
expect(reflectorSiblingGenDir.getImportPath(
|
2016-08-12 20:38:29 -04:00
|
|
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ngfactory.ts'))
|
2016-08-04 00:34:03 -04:00
|
|
|
.toEqual('./my.other.ngfactory');
|
|
|
|
expect(reflectorSiblingGenDir.getImportPath(
|
2016-08-12 20:38:29 -04:00
|
|
|
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.css.ts'))
|
2016-08-04 00:34:03 -04:00
|
|
|
.toEqual('../my.other.css');
|
|
|
|
expect(reflectorSiblingGenDir.getImportPath(
|
2016-08-12 20:38:29 -04:00
|
|
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.css.shim.ts'))
|
2016-08-04 00:34:03 -04:00
|
|
|
.toEqual('./a/my.other.css.shim');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should import application from factory', () => {
|
2016-08-12 20:38:29 -04:00
|
|
|
expect(reflectorSiblingGenDir.getImportPath(
|
|
|
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
|
2016-08-04 00:34:03 -04:00
|
|
|
.toEqual('./my.other');
|
|
|
|
expect(reflectorSiblingGenDir.getImportPath(
|
2016-08-12 20:38:29 -04:00
|
|
|
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
|
2016-08-04 00:34:03 -04:00
|
|
|
.toEqual('../my.other');
|
|
|
|
expect(reflectorSiblingGenDir.getImportPath(
|
2016-08-12 20:38:29 -04:00
|
|
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.ts'))
|
2016-08-04 00:34:03 -04:00
|
|
|
.toEqual('./a/my.other');
|
|
|
|
});
|
2016-06-09 17:51:53 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should provide the import locations for angular', () => {
|
2016-06-08 19:38:52 -04:00
|
|
|
let {coreDecorators, diDecorators, diMetadata, animationMetadata, provider} =
|
2016-08-04 00:34:03 -04:00
|
|
|
reflectorNestedGenDir.angularImportLocations();
|
2016-06-09 17:51:53 -04:00
|
|
|
expect(coreDecorators).toEqual('@angular/core/src/metadata');
|
2016-09-12 23:30:42 -04:00
|
|
|
expect(diDecorators).toEqual('@angular/core/src/di/metadata');
|
2016-06-09 17:51:53 -04:00
|
|
|
expect(diMetadata).toEqual('@angular/core/src/di/metadata');
|
|
|
|
expect(animationMetadata).toEqual('@angular/core/src/animation/metadata');
|
|
|
|
expect(provider).toEqual('@angular/core/src/di/provider');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should be able to produce an import from main @angular/core', () => {
|
2016-08-04 00:34:03 -04:00
|
|
|
expect(reflectorNestedGenDir.getImportPath(
|
2016-08-12 20:38:29 -04:00
|
|
|
'/tmp/project/src/main.ts', '/tmp/project/node_modules/@angular/core.d.ts'))
|
2016-06-08 19:38:52 -04:00
|
|
|
.toEqual('@angular/core');
|
2016-06-09 17:51:53 -04:00
|
|
|
});
|
|
|
|
|
2016-08-04 00:34:03 -04:00
|
|
|
it('should be able to produce an import from main to a sub-directory', () => {
|
|
|
|
expect(reflectorNestedGenDir.getImportPath('main.ts', 'lib/utils.ts')).toEqual('./lib/utils');
|
2016-06-09 17:51:53 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should be able to produce an import from to a peer file', () => {
|
2016-08-04 00:34:03 -04:00
|
|
|
expect(reflectorNestedGenDir.getImportPath('lib/utils.ts', 'lib/collections.ts'))
|
2016-06-08 19:38:52 -04:00
|
|
|
.toEqual('./collections');
|
2016-06-09 17:51:53 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should be able to produce an import from to a sibling directory', () => {
|
2016-08-04 00:34:03 -04:00
|
|
|
expect(reflectorNestedGenDir.getImportPath('lib2/utils2.ts', 'lib/utils.ts'))
|
|
|
|
.toEqual('../lib/utils');
|
2016-06-09 17:51:53 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should be able to produce a symbol for an exported symbol', () => {
|
2016-08-09 18:18:55 -04:00
|
|
|
expect(reflectorNestedGenDir.findDeclaration('@angular/router', 'foo', 'main.ts'))
|
2016-06-20 11:09:16 -04:00
|
|
|
.toBeDefined();
|
2016-06-09 17:51:53 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should be able to produce a symbol for values space only reference', () => {
|
2016-08-09 18:18:55 -04:00
|
|
|
expect(reflectorNestedGenDir.findDeclaration('@angular/router/src/providers', 'foo', 'main.ts'))
|
2016-06-08 19:38:52 -04:00
|
|
|
.toBeDefined();
|
2016-06-09 17:51:53 -04:00
|
|
|
});
|
|
|
|
|
2016-07-11 20:26:35 -04:00
|
|
|
|
2016-06-09 17:51:53 -04:00
|
|
|
it('should be produce the same symbol if asked twice', () => {
|
2016-08-04 00:34:03 -04:00
|
|
|
let foo1 = reflectorNestedGenDir.getStaticSymbol('main.ts', 'foo');
|
|
|
|
let foo2 = reflectorNestedGenDir.getStaticSymbol('main.ts', 'foo');
|
2016-06-09 17:51:53 -04:00
|
|
|
expect(foo1).toBe(foo2);
|
|
|
|
});
|
|
|
|
|
2016-07-11 20:26:35 -04:00
|
|
|
it('should be able to produce a symbol for a module with no file', () => {
|
2016-08-04 00:34:03 -04:00
|
|
|
expect(reflectorNestedGenDir.getStaticSymbol('angularjs', 'SomeAngularSymbol')).toBeDefined();
|
2016-07-11 20:26:35 -04:00
|
|
|
});
|
|
|
|
|
2016-07-21 20:12:00 -04:00
|
|
|
it('should be able to read a metadata file', () => {
|
2016-08-04 00:34:03 -04:00
|
|
|
expect(reflectorNestedGenDir.getMetadataFor('node_modules/@angular/core.d.ts'))
|
2016-07-21 20:12:00 -04:00
|
|
|
.toEqual({__symbolic: 'module', version: 1, metadata: {foo: {__symbolic: 'class'}}});
|
|
|
|
});
|
2016-07-06 17:26:31 -04:00
|
|
|
|
|
|
|
it('should be able to read metadata from an otherwise unused .d.ts file ', () => {
|
2016-08-04 00:34:03 -04:00
|
|
|
expect(reflectorNestedGenDir.getMetadataFor('node_modules/@angular/unused.d.ts'))
|
|
|
|
.toBeUndefined();
|
2016-07-06 17:26:31 -04:00
|
|
|
});
|
2016-07-11 20:26:35 -04:00
|
|
|
|
2016-08-10 14:52:56 -04:00
|
|
|
it('should be able to read empty metadata ', () => {
|
|
|
|
expect(reflectorNestedGenDir.getMetadataFor('node_modules/@angular/empty.d.ts'))
|
|
|
|
.toBeUndefined();
|
|
|
|
});
|
|
|
|
|
2016-07-11 20:26:35 -04:00
|
|
|
it('should return undefined for missing modules', () => {
|
2016-08-04 00:34:03 -04:00
|
|
|
expect(reflectorNestedGenDir.getMetadataFor('node_modules/@angular/missing.d.ts'))
|
|
|
|
.toBeUndefined();
|
2016-07-11 20:26:35 -04:00
|
|
|
});
|
2016-08-02 14:45:14 -04:00
|
|
|
|
|
|
|
it('should be able to trace a named export', () => {
|
2016-08-04 00:34:03 -04:00
|
|
|
const symbol = reflectorNestedGenDir.findDeclaration(
|
|
|
|
'./reexport/reexport.d.ts', 'One', '/tmp/src/main.ts');
|
2016-08-02 14:45:14 -04:00
|
|
|
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', () => {
|
2016-08-04 00:34:03 -04:00
|
|
|
const symbol = reflectorNestedGenDir.findDeclaration(
|
|
|
|
'./reexport/reexport.d.ts', 'Four', '/tmp/src/main.ts');
|
2016-08-02 14:45:14 -04:00
|
|
|
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', () => {
|
2016-08-04 00:34:03 -04:00
|
|
|
const symbol = reflectorNestedGenDir.findDeclaration(
|
|
|
|
'./reexport/reexport.d.ts', 'Five', '/tmp/src/main.ts');
|
2016-08-02 14:45:14 -04:00
|
|
|
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', () => {
|
2016-08-04 00:34:03 -04:00
|
|
|
const symbol = reflectorNestedGenDir.findDeclaration(
|
|
|
|
'./reexport/reexport.d.ts', 'Thirty', '/tmp/src/main.ts');
|
2016-08-02 14:45:14 -04:00
|
|
|
expect(symbol.name).toEqual('Thirty');
|
|
|
|
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin30.d.ts');
|
|
|
|
});
|
2016-06-09 17:51:53 -04:00
|
|
|
});
|
|
|
|
|
2016-07-21 20:12:00 -04:00
|
|
|
const dummyModule = 'export let foo: any[];';
|
|
|
|
|
2016-06-09 17:51:53 -04:00
|
|
|
const FILES: Entry = {
|
|
|
|
'tmp': {
|
|
|
|
'src': {
|
|
|
|
'main.ts': `
|
|
|
|
import * as c from '@angular/core';
|
2016-08-09 18:18:55 -04:00
|
|
|
import * as r from '@angular/router';
|
2016-06-09 17:51:53 -04:00
|
|
|
import * as u from './lib/utils';
|
|
|
|
import * as cs from './lib/collections';
|
|
|
|
import * as u2 from './lib2/utils2';
|
|
|
|
`,
|
|
|
|
'lib': {
|
|
|
|
'utils.ts': dummyModule,
|
|
|
|
'collections.ts': dummyModule,
|
|
|
|
},
|
2016-06-08 19:38:52 -04:00
|
|
|
'lib2': {'utils2.ts': dummyModule},
|
2016-08-02 14:45:14 -04:00
|
|
|
'reexport': {
|
|
|
|
'reexport.d.ts': `
|
|
|
|
import * as c from '@angular/core';
|
|
|
|
`,
|
|
|
|
'reexport.metadata.json': JSON.stringify({
|
|
|
|
__symbolic: 'module',
|
|
|
|
version: 1,
|
|
|
|
metadata: {},
|
|
|
|
exports: [
|
|
|
|
{from: './src/origin1', export: ['One', 'Two', {name: 'Three', as: 'Four'}]},
|
|
|
|
{from: './src/origin5'}, {from: './src/reexport2'}
|
|
|
|
]
|
|
|
|
}),
|
|
|
|
'src': {
|
|
|
|
'origin1.d.ts': `
|
|
|
|
export class One {}
|
|
|
|
export class Two {}
|
|
|
|
export class Three {}
|
|
|
|
`,
|
|
|
|
'origin1.metadata.json': JSON.stringify({
|
|
|
|
__symbolic: 'module',
|
|
|
|
version: 1,
|
|
|
|
metadata: {
|
|
|
|
One: {__symbolic: 'class'},
|
|
|
|
Two: {__symbolic: 'class'},
|
|
|
|
Three: {__symbolic: 'class'},
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
'origin5.d.ts': `
|
|
|
|
export class Five {}
|
|
|
|
`,
|
|
|
|
'origin5.metadata.json': JSON.stringify({
|
|
|
|
__symbolic: 'module',
|
|
|
|
version: 1,
|
|
|
|
metadata: {
|
|
|
|
Five: {__symbolic: 'class'},
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
'origin30.d.ts': `
|
|
|
|
export class Thirty {}
|
|
|
|
`,
|
|
|
|
'origin30.metadata.json': JSON.stringify({
|
|
|
|
__symbolic: 'module',
|
|
|
|
version: 1,
|
|
|
|
metadata: {
|
|
|
|
Thirty: {__symbolic: 'class'},
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
'originNone.d.ts': dummyModule,
|
|
|
|
'originNone.metadata.json': JSON.stringify({
|
|
|
|
__symbolic: 'module',
|
|
|
|
version: 1,
|
|
|
|
metadata: {},
|
|
|
|
}),
|
|
|
|
'reexport2.d.ts': dummyModule,
|
|
|
|
'reexport2.metadata.json': JSON.stringify({
|
|
|
|
__symbolic: 'module',
|
|
|
|
version: 1,
|
|
|
|
metadata: {},
|
|
|
|
exports: [{from: './originNone'}, {from: './origin30'}]
|
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
2016-06-09 17:51:53 -04:00
|
|
|
'node_modules': {
|
|
|
|
'@angular': {
|
|
|
|
'core.d.ts': dummyModule,
|
2016-06-08 19:38:52 -04:00
|
|
|
'core.metadata.json':
|
|
|
|
`{"__symbolic":"module", "version": 1, "metadata": {"foo": {"__symbolic": "class"}}}`,
|
2016-08-09 18:18:55 -04:00
|
|
|
'router': {'index.d.ts': dummyModule, 'src': {'providers.d.ts': dummyModule}},
|
2016-08-10 14:52:56 -04:00
|
|
|
'unused.d.ts': dummyModule,
|
|
|
|
'empty.d.ts': 'export declare var a: string;',
|
|
|
|
'empty.metadata.json': '[]',
|
2016-06-09 17:51:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-07-21 20:12:00 -04:00
|
|
|
};
|
2016-06-09 17:51:53 -04:00
|
|
|
|
|
|
|
function clone(entry: Entry): Entry {
|
2016-06-08 19:38:52 -04:00
|
|
|
if (typeof entry === 'string') {
|
2016-06-09 17:51:53 -04:00
|
|
|
return entry;
|
|
|
|
} else {
|
|
|
|
let result: Directory = {};
|
|
|
|
for (let name in entry) {
|
|
|
|
result[name] = clone(entry[name]);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|