Skip to content

Commit e178ee4

Browse files
committed
fix(compiler): Added support for '* as m' style imports. (angular#9077)
Also includes fixes for broken test.
1 parent 9f506cd commit e178ee4

File tree

5 files changed

+82
-71
lines changed

5 files changed

+82
-71
lines changed

modules/@angular/compiler-cli/integrationtest/src/features.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Component, Inject, OpaqueToken} from '@angular/core';
2-
import {NgIf} from '@angular/common';
2+
import * as common from '@angular/common';
33

44
export const SOME_OPAQUE_TOKEN = new OpaqueToken('opaqueToken');
55

@@ -9,7 +9,7 @@ export const SOME_OPAQUE_TOKEN = new OpaqueToken('opaqueToken');
99
providers: [
1010
{provide: 'strToken', useValue: 'strValue'},
1111
{provide: SOME_OPAQUE_TOKEN, useValue: 10},
12-
{provide: 'reference', useValue: NgIf},
12+
{provide: 'reference', useValue: common.NgIf},
1313
{provide: 'complexToken', useValue: {a: 1, b: ['test', SOME_OPAQUE_TOKEN]}},
1414
]
1515
})
@@ -23,7 +23,7 @@ export class CompWithProviders {
2323
<input #a>{{a.value}}
2424
<div *ngIf="true">{{a.value}}</div>
2525
`,
26-
directives: [NgIf]
26+
directives: [common.NgIf]
2727
})
2828
export class CompWithReferences {
2929
}

tools/@angular/tsc-wrapped/src/evaluator.ts

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as ts from 'typescript';
22

3-
import {MetadataValue, MetadataSymbolicCallExpression, MetadataSymbolicReferenceExpression, MetadataError, isMetadataError, isMetadataModuleReferenceExpression, isMetadataImportedSymbolReferenceExpression, isMetadataGlobalReferenceExpression,} from './schema';
3+
import {MetadataError, MetadataGlobalReferenceExpression, MetadataImportedSymbolReferenceExpression, MetadataSymbolicCallExpression, MetadataSymbolicReferenceExpression, MetadataValue, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportedSymbolReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicReferenceExpression} from './schema';
44
import {Symbols} from './symbols';
55

66
function isMethodCallOf(callExpression: ts.CallExpression, memberName: string): boolean {
@@ -66,14 +66,21 @@ function getSourceFileOfNode(node: ts.Node): ts.SourceFile {
6666
export function errorSymbol(
6767
message: string, node?: ts.Node, context?: {[name: string]: string},
6868
sourceFile?: ts.SourceFile): MetadataError {
69+
let result: MetadataError;
6970
if (node) {
7071
sourceFile = sourceFile || getSourceFileOfNode(node);
7172
if (sourceFile) {
7273
let {line, character} = ts.getLineAndCharacterOfPosition(sourceFile, node.pos);
73-
return {__symbolic: 'error', message, line, character, context};
74+
result = {__symbolic: 'error', message, line, character};
7475
};
7576
}
76-
return {__symbolic: 'error', message, context};
77+
if (!result) {
78+
result = {__symbolic: 'error', message};
79+
}
80+
if (context) {
81+
result.context = context;
82+
}
83+
return result;
7784
}
7885

7986
/**
@@ -325,27 +332,36 @@ export class Evaluator {
325332
case ts.SyntaxKind.TypeReference:
326333
const typeReferenceNode = <ts.TypeReferenceNode>node;
327334
const typeNameNode = typeReferenceNode.typeName;
328-
if (typeNameNode.kind != ts.SyntaxKind.Identifier) {
329-
return errorSymbol('Qualified type names not supported', node);
330-
}
331-
const typeNameIdentifier = <ts.Identifier>typeReferenceNode.typeName;
332-
const typeName = typeNameIdentifier.text;
333-
const typeReference = this.symbols.resolve(typeName);
334-
if (!typeReference) {
335-
return errorSymbol('Could not resolve type', node, {typeName});
335+
const getReference: (typeNameNode: ts.Identifier | ts.QualifiedName) =>
336+
MetadataSymbolicReferenceExpression | MetadataError = node => {
337+
if (typeNameNode.kind === ts.SyntaxKind.QualifiedName) {
338+
const qualifiedName = <ts.QualifiedName>node;
339+
const left = this.evaluateNode(qualifiedName.left);
340+
if (isMetadataModuleReferenceExpression(left)) {
341+
return <MetadataImportedSymbolReferenceExpression> {
342+
__symbolic: 'reference', module: left.module, name: qualifiedName.right.text
343+
}
344+
}
345+
return errorSymbol('Qualified type names not supported', node);
346+
} else {
347+
const identifier = <ts.Identifier>typeNameNode;
348+
let symbol = this.symbols.resolve(identifier.text);
349+
if (isMetadataError(symbol) || isMetadataSymbolicReferenceExpression(symbol)) {
350+
return symbol;
351+
}
352+
return errorSymbol('Could not resolve type', node, {typeName: identifier.text});
353+
}
354+
};
355+
const typeReference = getReference(typeNameNode);
356+
if (isMetadataError(typeReference)) {
357+
return typeReference;
336358
}
337-
if (typeReferenceNode.typeArguments && typeReferenceNode.typeArguments.length) {
359+
if (!isMetadataModuleReferenceExpression(typeReference) &&
360+
typeReferenceNode.typeArguments && typeReferenceNode.typeArguments.length) {
338361
const args = typeReferenceNode.typeArguments.map(element => this.evaluateNode(element));
339-
if (isMetadataImportedSymbolReferenceExpression(typeReference)) {
340-
return {
341-
__symbolic: 'reference',
342-
module: typeReference.module,
343-
name: typeReference.name,
344-
arguments: args
345-
};
346-
} else if (isMetadataGlobalReferenceExpression(typeReference)) {
347-
return {__symbolic: 'reference', name: typeReference.name, arguments: args};
348-
}
362+
// TODO: Remove typecast when upgraded to 2.0 as it will be corretly inferred.
363+
// Some versions of 1.9 do not infer this correctly.
364+
(<MetadataImportedSymbolReferenceExpression>typeReference).arguments = args;
349365
}
350366
return typeReference;
351367
case ts.SyntaxKind.NoSubstitutionTemplateLiteral:

tools/@angular/tsc-wrapped/src/schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ export interface MetadataImportedDefaultReferenceExpression extends MetadataSymb
165165
module: string;
166166
default:
167167
boolean;
168+
arguments?: MetadataValue[];
168169
}
169170
export function isMetadataImportDefaultReference(value: any):
170171
value is MetadataImportedDefaultReferenceExpression {

tools/@angular/tsc-wrapped/test/collector.spec.ts

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ describe('Collector', () => {
1414
beforeEach(() => {
1515
host = new Host(FILES, [
1616
'/app/app.component.ts', '/app/cases-data.ts', '/app/error-cases.ts', '/promise.ts',
17-
'/unsupported-1.ts', '/unsupported-2.ts'
17+
'/unsupported-1.ts', '/unsupported-2.ts', 'import-star.ts'
1818
]);
1919
service = ts.createLanguageService(host);
2020
program = service.getProgram();
@@ -212,53 +212,40 @@ describe('Collector', () => {
212212
__symbolic: 'module',
213213
version: 1,
214214
metadata: {
215-
a: {
216-
__symbolic: 'error',
217-
message: 'Destructuring declarations cannot be referenced statically',
218-
line: 1,
219-
character: 16
220-
},
221-
b: {
222-
__symbolic: 'error',
223-
message: 'Destructuring declarations cannot be referenced statically',
224-
line: 1,
225-
character: 18
226-
},
227-
c: {
228-
__symbolic: 'error',
229-
message: 'Destructuring declarations cannot be referenced statically',
230-
line: 2,
231-
character: 16
232-
},
233-
d: {
234-
__symbolic: 'error',
235-
message: 'Destructuring declarations cannot be referenced statically',
236-
line: 2,
237-
character: 18
238-
},
239-
e: {
240-
__symbolic: 'error',
241-
message: 'Only intialized variables and constants can be referenced statically',
242-
line: 3,
243-
character: 14
244-
}
215+
a: {__symbolic: 'error', message: 'Destructuring not supported', line: 1, character: 16},
216+
b: {__symbolic: 'error', message: 'Destructuring not supported', line: 1, character: 18},
217+
c: {__symbolic: 'error', message: 'Destructuring not supported', line: 2, character: 16},
218+
d: {__symbolic: 'error', message: 'Destructuring not supported', line: 2, character: 18},
219+
e: {__symbolic: 'error', message: 'Variable not initialized', line: 3, character: 14}
245220
}
246221
});
247222
});
248223

249-
it('should report an error for refrences to unexpected types', () => {
224+
it('should report an error for references to unexpected types', () => {
250225
let unsupported1 = program.getSourceFile('/unsupported-2.ts');
251226
let metadata = collector.getMetadata(unsupported1);
252227
let barClass = <ClassMetadata>metadata.metadata['Bar'];
253228
let ctor = <ConstructorMetadata>barClass.members['__ctor__'][0];
254229
let parameter = ctor.parameters[0];
255230
expect(parameter).toEqual({
256231
__symbolic: 'error',
257-
message: 'Reference to non-exported class Foo',
232+
message: 'Reference to non-exported class',
258233
line: 1,
259-
character: 45
234+
character: 45,
235+
context: {className: 'Foo'}
260236
});
261237
});
238+
239+
it('should be able to handle import star type references', () => {
240+
let importStar = program.getSourceFile('/import-star.ts');
241+
let metadata = collector.getMetadata(importStar);
242+
let someClass = <ClassMetadata>metadata.metadata['SomeClass'];
243+
let ctor = <ConstructorMetadata>someClass.members['__ctor__'][0];
244+
let parameters = ctor.parameters;
245+
expect(parameters).toEqual([
246+
{__symbolic: 'reference', module: 'angular2/common', name: 'NgFor'}
247+
]);
248+
});
262249
});
263250

264251
// TODO: Do not use \` in a template literal as it confuses clang-format
@@ -468,6 +455,15 @@ const FILES: Directory = {
468455
constructor(private f: Foo) {}
469456
}
470457
`,
458+
'import-star.ts': `
459+
import {Injectable} from 'angular2/core';
460+
import * as common from 'angular2/common';
461+
462+
@Injectable()
463+
export class SomeClass {
464+
constructor(private f: common.NgFor) {}
465+
}
466+
`,
471467
'node_modules': {
472468
'angular2': {
473469
'core.d.ts': `

tools/@angular/tsc-wrapped/test/evaluator.spec.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -156,31 +156,29 @@ describe('Evaluator', () => {
156156
character: 10
157157
});
158158
let fDecl = findVar(errors, 'f');
159-
expect(evaluator.evaluateNode(fDecl.initializer)).toEqual({
160-
__symbolic: 'error',
161-
message:
162-
'Functions cannot be evaluated statically; consider replacing with a reference to an exported function',
163-
line: 6,
164-
character: 11
165-
});
159+
expect(evaluator.evaluateNode(fDecl.initializer))
160+
.toEqual(
161+
{__symbolic: 'error', message: 'Function call not supported', line: 6, character: 11});
166162
let eDecl = findVar(errors, 'e');
167163
expect(evaluator.evaluateNode(eDecl.type)).toEqual({
168164
__symbolic: 'error',
169-
message: 'Could not resolve type NotFound',
165+
message: 'Could not resolve type',
170166
line: 7,
171-
character: 10
167+
character: 10,
168+
context: {typeName: 'NotFound'}
172169
});
173170
let sDecl = findVar(errors, 's');
174171
expect(evaluator.evaluateNode(sDecl.initializer)).toEqual({
175172
__symbolic: 'error',
176-
message: 'Name expected a string or an identifier but received "1"',
173+
message: 'Name expected',
177174
line: 8,
178-
character: 13
175+
character: 13,
176+
context: {received: '1'}
179177
});
180178
let tDecl = findVar(errors, 't');
181179
expect(evaluator.evaluateNode(tDecl.initializer)).toEqual({
182180
__symbolic: 'error',
183-
message: 'Expression form not supported statically',
181+
message: 'Expression form not supported',
184182
line: 9,
185183
character: 11
186184
});

0 commit comments

Comments
 (0)