Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(language-service): support TypeScript 2.1 #13655

Merged
merged 1 commit into from
Jan 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
"declaration": true,
"lib": ["es6", "dom"],
"baseUrl": ".",
"outDir": "../node_modules/third_party"
}
"outDir": "../node_modules/third_party",
// Prevent scanning up the directory tree for types
"typeRoots": ["node_modules/@types"]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
"rootDir": "",
"declaration": true,
"lib": ["es6", "dom"],
"baseUrl": "."
"baseUrl": ".",
// Prevent scanning up the directory tree for types
"typeRoots": ["node_modules/@types"]
},

"files": [
Expand Down
24 changes: 16 additions & 8 deletions modules/@angular/language-service/src/typescript_host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,17 @@ import {createLanguageService} from './language_service';
import {ReflectorHost} from './reflector_host';
import {BuiltinType, CompletionKind, Declaration, DeclarationError, Declarations, Definition, LanguageService, LanguageServiceHost, PipeInfo, Pipes, Signature, Span, Symbol, SymbolDeclaration, SymbolQuery, SymbolTable, TemplateSource, TemplateSources} from './types';


// In TypeScript 2.1 these flags moved
// These helpers work for both 2.0 and 2.1.
const isPrivate = (ts as any).ModifierFlags ?
((node: ts.Node) =>
!!((ts as any).getCombinedModifierFlags(node) & (ts as any).ModifierFlags.Private)) :
((node: ts.Node) => !!(node.flags & (ts as any).NodeFlags.Private));
const isReferenceType = (ts as any).ObjectFlags ?
((type: ts.Type) =>
!!(type.flags & (ts as any).TypeFlags.Object &&
(type as any).objectFlags & (ts as any).ObjectFlags.Reference)) :
((type: ts.Type) => !!(type.flags & (ts as any).TypeFlags.Reference));

/**
* Create a `LanguageServiceHost`
Expand Down Expand Up @@ -680,7 +690,7 @@ class TypeScriptSymbolQuery implements SymbolQuery {
const constructorDeclaration = constructor.declarations[0] as ts.ConstructorTypeNode;
for (const parameter of constructorDeclaration.parameters) {
const type = this.checker.getTypeAtLocation(parameter.type);
if (type.symbol.name == 'TemplateRef' && type.flags & ts.TypeFlags.Reference) {
if (type.symbol.name == 'TemplateRef' && isReferenceType(type)) {
const typeReference = type as ts.TypeReference;
if (typeReference.typeArguments.length === 1) {
return typeReference.typeArguments[0].symbol;
Expand Down Expand Up @@ -805,7 +815,7 @@ class SymbolWrapper implements Symbol {

get public(): boolean {
// Symbols that are not explicitly made private are public.
return !(getDeclarationFlagsFromSymbol(this.symbol) & ts.NodeFlags.Private);
return !isSymbolPrivate(this.symbol);
}

get callable(): boolean { return typeCallable(this.tsType); }
Expand Down Expand Up @@ -1097,10 +1107,8 @@ function getCombinedNodeFlags(node: ts.Node): ts.NodeFlags {
return flags;
}

function getDeclarationFlagsFromSymbol(s: ts.Symbol): ts.NodeFlags {
return s.valueDeclaration ?
getCombinedNodeFlags(s.valueDeclaration) :
s.flags & ts.SymbolFlags.Prototype ? ts.NodeFlags.Public | ts.NodeFlags.Static : 0;
function isSymbolPrivate(s: ts.Symbol): boolean {
return s.valueDeclaration && isPrivate(s.valueDeclaration);
}

function getBuiltinTypeFromTs(kind: BuiltinType, context: TypeContext): ts.Type {
Expand Down Expand Up @@ -1258,4 +1266,4 @@ function typeKindOf(type: ts.Type): BuiltinType {
}
}
return BuiltinType.Other;
}
}
23 changes: 21 additions & 2 deletions scripts/ci-lite/offline_compiler_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ LINKABLE_PKGS=(
$(pwd)/dist/packages-dist/{common,forms,core,compiler,compiler-cli,platform-{browser,server},platform-browser-dynamic,router}
$(pwd)/dist/tools/@angular/tsc-wrapped
)
TYPESCRIPT_2_0=typescript@2.0.2
TYPESCRIPT_2_1=typescript@2.1.4
PKGS=(
reflect-metadata@0.1.8
typescript@2.0.2
zone.js@0.6.25
rxjs@5.0.1
@types/{node@6.0.38,jasmine@2.2.33}
Expand All @@ -30,7 +31,7 @@ cp -v package.json $TMP
(
cd $TMP
set -ex -o pipefail
npm install ${PKGS[*]}
npm install ${PKGS[*]} $TYPESCRIPT_2_0
# TODO(alexeagle): allow this to be npm link instead
npm install ${LINKABLE_PKGS[*]}

Expand Down Expand Up @@ -62,3 +63,21 @@ cp -v package.json $TMP
mv tsconfig-build.json othername.json
./node_modules/.bin/ngc -p othername.json
)

# Repeat selected parts of the above with TypeScript 2.1
readonly TMP_2_1=$TMPDIR/e2e_test.$(date +%s)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it make sense to:

  • move the 2.0 & 2.1 setup together,
  • have e2e/date/2.0 and e2e/date/2.1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a long-term solution. We should run this entire once per TypeScript version we want to support. But, as noted in the commit message, Tsickle is not ready for 2.1 yet so the annotation lowering test fails.

mkdir -p $TMP_2_1
cp -R -v modules/@angular/compiler-cli/integrationtest/* $TMP_2_1
cp -R -v modules/benchmarks $TMP_2_1
cp -v package.json $TMP_2_1
(
cd $TMP_2_1
set -ex -o pipefail

npm install ${PKGS[*]} $TYPESCRIPT_2_1
npm install ${LINKABLE_PKGS[*]}

./node_modules/.bin/tsc --version
node ./node_modules/@angular/tsc-wrapped/src/main -p third_party_src/tsconfig-build.json
./node_modules/.bin/ngc -p tsconfig-build.json --i18nFile=src/messages.fi.xlf --locale=fi --i18nFormat=xlf
)
32 changes: 22 additions & 10 deletions tools/@angular/tsc-wrapped/src/collector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ import {Evaluator, errorSymbol, isPrimitive} from './evaluator';
import {ClassMetadata, ConstructorMetadata, FunctionMetadata, MemberMetadata, MetadataEntry, MetadataError, MetadataMap, MetadataSymbolicBinaryExpression, MetadataSymbolicCallExpression, MetadataSymbolicExpression, MetadataSymbolicIfExpression, MetadataSymbolicIndexExpression, MetadataSymbolicPrefixExpression, MetadataSymbolicReferenceExpression, MetadataSymbolicSelectExpression, MetadataSymbolicSpreadExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata, VERSION, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataSymbolicExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSelectExpression, isMethodMetadata} from './schema';
import {Symbols} from './symbols';

// In TypeScript 2.1 these flags moved
// These helpers work for both 2.0 and 2.1.
const isExport = (ts as any).ModifierFlags ?
((node: ts.Node) =>
!!((ts as any).getCombinedModifierFlags(node) & (ts as any).ModifierFlags.Export)) :
((node: ts.Node) => !!((node.flags & (ts as any).NodeFlags.Export)));
const isStatic = (ts as any).ModifierFlags ?
((node: ts.Node) =>
!!((ts as any).getCombinedModifierFlags(node) & (ts as any).ModifierFlags.Static)) :
((node: ts.Node) => !!((node.flags & (ts as any).NodeFlags.Static)));

/**
* A set of collector options to use when collecting metadata.
Expand Down Expand Up @@ -146,7 +156,7 @@ export class MetadataCollector {
case ts.SyntaxKind.MethodDeclaration:
isConstructor = member.kind === ts.SyntaxKind.Constructor;
const method = <ts.MethodDeclaration|ts.ConstructorDeclaration>member;
if (method.flags & ts.NodeFlags.Static) {
if (isStatic(method)) {
const maybeFunc = maybeGetSimpleFunction(<ts.MethodDeclaration>method);
if (maybeFunc) {
recordStaticMember(maybeFunc.name, maybeFunc.func);
Expand Down Expand Up @@ -193,7 +203,7 @@ export class MetadataCollector {
case ts.SyntaxKind.GetAccessor:
case ts.SyntaxKind.SetAccessor:
const property = <ts.PropertyDeclaration>member;
if (property.flags & ts.NodeFlags.Static) {
if (isStatic(property)) {
const name = evaluator.nameOf(property.name);
if (!isMetadataError(name)) {
if (property.initializer) {
Expand Down Expand Up @@ -244,7 +254,7 @@ export class MetadataCollector {

const isExportedIdentifier = (identifier: ts.Identifier) => exportMap.has(identifier.text);
const isExported = (node: ts.FunctionDeclaration | ts.ClassDeclaration | ts.EnumDeclaration) =>
(node.flags & ts.NodeFlags.Export) || isExportedIdentifier(node.name);
isExport(node) || isExportedIdentifier(node.name);
const exportedIdentifierName = (identifier: ts.Identifier) =>
exportMap.get(identifier.text) || identifier.text;
const exportedName =
Expand Down Expand Up @@ -404,8 +414,7 @@ export class MetadataCollector {
varValue = recordEntry(errorSym('Variable not initialized', nameNode), nameNode);
}
let exported = false;
if (variableStatement.flags & ts.NodeFlags.Export ||
variableDeclaration.flags & ts.NodeFlags.Export ||
if (isExport(variableStatement) || isExport(variableDeclaration) ||
isExportedIdentifier(nameNode)) {
if (!metadata) metadata = {};
metadata[exportedIdentifierName(nameNode)] = recordEntry(varValue, node);
Expand All @@ -430,13 +439,13 @@ export class MetadataCollector {
// or
// var [<identifier>[, <identifier}+] = <expression>;
// are not supported.
const report = (nameNode: ts.Node) => {
const report: (nameNode: ts.Node) => void = (nameNode: ts.Node) => {
switch (nameNode.kind) {
case ts.SyntaxKind.Identifier:
const name = <ts.Identifier>nameNode;
const varValue = errorSym('Destructuring not supported', nameNode);
const varValue = errorSym('Destructuring not supported', name);
locals.define(name.text, varValue);
if (node.flags & ts.NodeFlags.Export) {
if (isExport(node)) {
if (!metadata) metadata = {};
metadata[name.text] = varValue;
}
Expand All @@ -448,7 +457,7 @@ export class MetadataCollector {
case ts.SyntaxKind.ObjectBindingPattern:
case ts.SyntaxKind.ArrayBindingPattern:
const bindings = <ts.BindingPattern>nameNode;
bindings.elements.forEach(report);
(bindings as any).elements.forEach(report);
break;
}
};
Expand Down Expand Up @@ -630,7 +639,10 @@ function namesOf(parameters: ts.NodeArray<ts.ParameterDeclaration>): string[] {
} else {
const bindingPattern = <ts.BindingPattern>name;
for (const element of bindingPattern.elements) {
addNamesOf(element.name);
const name = (element as any).name;
if (name) {
addNamesOf(name);
}
}
}
}
Expand Down
14 changes: 12 additions & 2 deletions tools/@angular/tsc-wrapped/src/compiler_host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,19 @@ export class MetadataWriterHost extends DelegatingHost {
// released
if (/*DTS*/ /\.js$/.test(emitFilePath)) {
const path = emitFilePath.replace(/*DTS*/ /\.js$/, '.metadata.json');

// Beginning with 2.1, TypeScript transforms the source tree before emitting it.
// We need the original, unmodified, tree which might be several levels back
// depending on the number of transforms performed. All SourceFile's prior to 2.1
// will appear to be the original source since they didn't include an original field.
let collectableFile = sourceFile;
while ((collectableFile as any).original) {
collectableFile = (collectableFile as any).original;
}

const metadata =
this.metadataCollector.getMetadata(sourceFile, !!this.ngOptions.strictMetadataEmit);
const metadata1 = this.metadataCollector1.getMetadata(sourceFile, false);
this.metadataCollector.getMetadata(collectableFile, !!this.ngOptions.strictMetadataEmit);
const metadata1 = this.metadataCollector1.getMetadata(collectableFile, false);
const metadatas: ModuleMetadata[] = [metadata, metadata1].filter(e => !!e);
if (metadatas.length) {
const metadataText = JSON.stringify(metadatas);
Expand Down
9 changes: 6 additions & 3 deletions tools/@angular/tsc-wrapped/src/evaluator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import {CollectorOptions} from './collector';
import {MetadataEntry, MetadataError, MetadataGlobalReferenceExpression, MetadataImportedSymbolReferenceExpression, MetadataSymbolicCallExpression, MetadataSymbolicReferenceExpression, MetadataValue, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportedSymbolReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSpreadExpression} from './schema';
import {Symbols} from './symbols';

// In TypeScript 2.1 the spread element kind was renamed.
const spreadElementSyntaxKind: ts.SyntaxKind =
(ts.SyntaxKind as any).SpreadElement || (ts.SyntaxKind as any).SpreadElementExpression;

function isMethodCallOf(callExpression: ts.CallExpression, memberName: string): boolean {
const expression = callExpression.expression;
if (expression.kind === ts.SyntaxKind.PropertyAccessExpression) {
Expand Down Expand Up @@ -282,9 +286,8 @@ export class Evaluator {
});
if (error) return error;
return arr;
case ts.SyntaxKind.SpreadElementExpression:
let spread = <ts.SpreadElementExpression>node;
let spreadExpression = this.evaluateNode(spread.expression);
case spreadElementSyntaxKind:
let spreadExpression = this.evaluateNode((node as any).expression);
return recordEntry({__symbolic: 'spread', expression: spreadExpression}, node);
case ts.SyntaxKind.CallExpression:
const callExpression = <ts.CallExpression>node;
Expand Down