fix(language-service): support TypeScript 2.1 (#13655)
@angular/language-service now supports using TypeScript 2.1 as the the TypeScript host. TypeScript 2.1 is now also partially supported in `ngc` but is not recommended as Tsickle does not yet support 2.1.
This commit is contained in:
parent
21030e9a1c
commit
8063b0d9a2
|
@ -15,6 +15,8 @@
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"lib": ["es6", "dom"],
|
"lib": ["es6", "dom"],
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"outDir": "../node_modules/third_party"
|
"outDir": "../node_modules/third_party",
|
||||||
|
// Prevent scanning up the directory tree for types
|
||||||
|
"typeRoots": ["node_modules/@types"]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,7 +14,9 @@
|
||||||
"rootDir": "",
|
"rootDir": "",
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"lib": ["es6", "dom"],
|
"lib": ["es6", "dom"],
|
||||||
"baseUrl": "."
|
"baseUrl": ".",
|
||||||
|
// Prevent scanning up the directory tree for types
|
||||||
|
"typeRoots": ["node_modules/@types"]
|
||||||
},
|
},
|
||||||
|
|
||||||
"files": [
|
"files": [
|
||||||
|
|
|
@ -29,7 +29,17 @@ import {createLanguageService} from './language_service';
|
||||||
import {ReflectorHost} from './reflector_host';
|
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';
|
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`
|
* Create a `LanguageServiceHost`
|
||||||
|
@ -680,7 +690,7 @@ class TypeScriptSymbolQuery implements SymbolQuery {
|
||||||
const constructorDeclaration = constructor.declarations[0] as ts.ConstructorTypeNode;
|
const constructorDeclaration = constructor.declarations[0] as ts.ConstructorTypeNode;
|
||||||
for (const parameter of constructorDeclaration.parameters) {
|
for (const parameter of constructorDeclaration.parameters) {
|
||||||
const type = this.checker.getTypeAtLocation(parameter.type);
|
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;
|
const typeReference = type as ts.TypeReference;
|
||||||
if (typeReference.typeArguments.length === 1) {
|
if (typeReference.typeArguments.length === 1) {
|
||||||
return typeReference.typeArguments[0].symbol;
|
return typeReference.typeArguments[0].symbol;
|
||||||
|
@ -805,7 +815,7 @@ class SymbolWrapper implements Symbol {
|
||||||
|
|
||||||
get public(): boolean {
|
get public(): boolean {
|
||||||
// Symbols that are not explicitly made private are public.
|
// 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); }
|
get callable(): boolean { return typeCallable(this.tsType); }
|
||||||
|
@ -1097,10 +1107,8 @@ function getCombinedNodeFlags(node: ts.Node): ts.NodeFlags {
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDeclarationFlagsFromSymbol(s: ts.Symbol): ts.NodeFlags {
|
function isSymbolPrivate(s: ts.Symbol): boolean {
|
||||||
return s.valueDeclaration ?
|
return s.valueDeclaration && isPrivate(s.valueDeclaration);
|
||||||
getCombinedNodeFlags(s.valueDeclaration) :
|
|
||||||
s.flags & ts.SymbolFlags.Prototype ? ts.NodeFlags.Public | ts.NodeFlags.Static : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBuiltinTypeFromTs(kind: BuiltinType, context: TypeContext): ts.Type {
|
function getBuiltinTypeFromTs(kind: BuiltinType, context: TypeContext): ts.Type {
|
||||||
|
|
|
@ -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/packages-dist/{common,forms,core,compiler,compiler-cli,platform-{browser,server},platform-browser-dynamic,router}
|
||||||
$(pwd)/dist/tools/@angular/tsc-wrapped
|
$(pwd)/dist/tools/@angular/tsc-wrapped
|
||||||
)
|
)
|
||||||
|
TYPESCRIPT_2_0=typescript@2.0.2
|
||||||
|
TYPESCRIPT_2_1=typescript@2.1.4
|
||||||
PKGS=(
|
PKGS=(
|
||||||
reflect-metadata@0.1.8
|
reflect-metadata@0.1.8
|
||||||
typescript@2.0.2
|
|
||||||
zone.js@0.6.25
|
zone.js@0.6.25
|
||||||
rxjs@5.0.1
|
rxjs@5.0.1
|
||||||
@types/{node@6.0.38,jasmine@2.2.33}
|
@types/{node@6.0.38,jasmine@2.2.33}
|
||||||
|
@ -30,7 +31,7 @@ cp -v package.json $TMP
|
||||||
(
|
(
|
||||||
cd $TMP
|
cd $TMP
|
||||||
set -ex -o pipefail
|
set -ex -o pipefail
|
||||||
npm install ${PKGS[*]}
|
npm install ${PKGS[*]} $TYPESCRIPT_2_0
|
||||||
# TODO(alexeagle): allow this to be npm link instead
|
# TODO(alexeagle): allow this to be npm link instead
|
||||||
npm install ${LINKABLE_PKGS[*]}
|
npm install ${LINKABLE_PKGS[*]}
|
||||||
|
|
||||||
|
@ -62,3 +63,21 @@ cp -v package.json $TMP
|
||||||
mv tsconfig-build.json othername.json
|
mv tsconfig-build.json othername.json
|
||||||
./node_modules/.bin/ngc -p 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)
|
||||||
|
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
|
||||||
|
)
|
|
@ -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 {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';
|
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.
|
* A set of collector options to use when collecting metadata.
|
||||||
|
@ -146,7 +156,7 @@ export class MetadataCollector {
|
||||||
case ts.SyntaxKind.MethodDeclaration:
|
case ts.SyntaxKind.MethodDeclaration:
|
||||||
isConstructor = member.kind === ts.SyntaxKind.Constructor;
|
isConstructor = member.kind === ts.SyntaxKind.Constructor;
|
||||||
const method = <ts.MethodDeclaration|ts.ConstructorDeclaration>member;
|
const method = <ts.MethodDeclaration|ts.ConstructorDeclaration>member;
|
||||||
if (method.flags & ts.NodeFlags.Static) {
|
if (isStatic(method)) {
|
||||||
const maybeFunc = maybeGetSimpleFunction(<ts.MethodDeclaration>method);
|
const maybeFunc = maybeGetSimpleFunction(<ts.MethodDeclaration>method);
|
||||||
if (maybeFunc) {
|
if (maybeFunc) {
|
||||||
recordStaticMember(maybeFunc.name, maybeFunc.func);
|
recordStaticMember(maybeFunc.name, maybeFunc.func);
|
||||||
|
@ -193,7 +203,7 @@ export class MetadataCollector {
|
||||||
case ts.SyntaxKind.GetAccessor:
|
case ts.SyntaxKind.GetAccessor:
|
||||||
case ts.SyntaxKind.SetAccessor:
|
case ts.SyntaxKind.SetAccessor:
|
||||||
const property = <ts.PropertyDeclaration>member;
|
const property = <ts.PropertyDeclaration>member;
|
||||||
if (property.flags & ts.NodeFlags.Static) {
|
if (isStatic(property)) {
|
||||||
const name = evaluator.nameOf(property.name);
|
const name = evaluator.nameOf(property.name);
|
||||||
if (!isMetadataError(name)) {
|
if (!isMetadataError(name)) {
|
||||||
if (property.initializer) {
|
if (property.initializer) {
|
||||||
|
@ -244,7 +254,7 @@ export class MetadataCollector {
|
||||||
|
|
||||||
const isExportedIdentifier = (identifier: ts.Identifier) => exportMap.has(identifier.text);
|
const isExportedIdentifier = (identifier: ts.Identifier) => exportMap.has(identifier.text);
|
||||||
const isExported = (node: ts.FunctionDeclaration | ts.ClassDeclaration | ts.EnumDeclaration) =>
|
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) =>
|
const exportedIdentifierName = (identifier: ts.Identifier) =>
|
||||||
exportMap.get(identifier.text) || identifier.text;
|
exportMap.get(identifier.text) || identifier.text;
|
||||||
const exportedName =
|
const exportedName =
|
||||||
|
@ -404,8 +414,7 @@ export class MetadataCollector {
|
||||||
varValue = recordEntry(errorSym('Variable not initialized', nameNode), nameNode);
|
varValue = recordEntry(errorSym('Variable not initialized', nameNode), nameNode);
|
||||||
}
|
}
|
||||||
let exported = false;
|
let exported = false;
|
||||||
if (variableStatement.flags & ts.NodeFlags.Export ||
|
if (isExport(variableStatement) || isExport(variableDeclaration) ||
|
||||||
variableDeclaration.flags & ts.NodeFlags.Export ||
|
|
||||||
isExportedIdentifier(nameNode)) {
|
isExportedIdentifier(nameNode)) {
|
||||||
if (!metadata) metadata = {};
|
if (!metadata) metadata = {};
|
||||||
metadata[exportedIdentifierName(nameNode)] = recordEntry(varValue, node);
|
metadata[exportedIdentifierName(nameNode)] = recordEntry(varValue, node);
|
||||||
|
@ -430,13 +439,13 @@ export class MetadataCollector {
|
||||||
// or
|
// or
|
||||||
// var [<identifier>[, <identifier}+] = <expression>;
|
// var [<identifier>[, <identifier}+] = <expression>;
|
||||||
// are not supported.
|
// are not supported.
|
||||||
const report = (nameNode: ts.Node) => {
|
const report: (nameNode: ts.Node) => void = (nameNode: ts.Node) => {
|
||||||
switch (nameNode.kind) {
|
switch (nameNode.kind) {
|
||||||
case ts.SyntaxKind.Identifier:
|
case ts.SyntaxKind.Identifier:
|
||||||
const name = <ts.Identifier>nameNode;
|
const name = <ts.Identifier>nameNode;
|
||||||
const varValue = errorSym('Destructuring not supported', nameNode);
|
const varValue = errorSym('Destructuring not supported', name);
|
||||||
locals.define(name.text, varValue);
|
locals.define(name.text, varValue);
|
||||||
if (node.flags & ts.NodeFlags.Export) {
|
if (isExport(node)) {
|
||||||
if (!metadata) metadata = {};
|
if (!metadata) metadata = {};
|
||||||
metadata[name.text] = varValue;
|
metadata[name.text] = varValue;
|
||||||
}
|
}
|
||||||
|
@ -448,7 +457,7 @@ export class MetadataCollector {
|
||||||
case ts.SyntaxKind.ObjectBindingPattern:
|
case ts.SyntaxKind.ObjectBindingPattern:
|
||||||
case ts.SyntaxKind.ArrayBindingPattern:
|
case ts.SyntaxKind.ArrayBindingPattern:
|
||||||
const bindings = <ts.BindingPattern>nameNode;
|
const bindings = <ts.BindingPattern>nameNode;
|
||||||
bindings.elements.forEach(report);
|
(bindings as any).elements.forEach(report);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -630,7 +639,10 @@ function namesOf(parameters: ts.NodeArray<ts.ParameterDeclaration>): string[] {
|
||||||
} else {
|
} else {
|
||||||
const bindingPattern = <ts.BindingPattern>name;
|
const bindingPattern = <ts.BindingPattern>name;
|
||||||
for (const element of bindingPattern.elements) {
|
for (const element of bindingPattern.elements) {
|
||||||
addNamesOf(element.name);
|
const name = (element as any).name;
|
||||||
|
if (name) {
|
||||||
|
addNamesOf(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,9 +119,19 @@ export class MetadataWriterHost extends DelegatingHost {
|
||||||
// released
|
// released
|
||||||
if (/*DTS*/ /\.js$/.test(emitFilePath)) {
|
if (/*DTS*/ /\.js$/.test(emitFilePath)) {
|
||||||
const path = emitFilePath.replace(/*DTS*/ /\.js$/, '.metadata.json');
|
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 =
|
const metadata =
|
||||||
this.metadataCollector.getMetadata(sourceFile, !!this.ngOptions.strictMetadataEmit);
|
this.metadataCollector.getMetadata(collectableFile, !!this.ngOptions.strictMetadataEmit);
|
||||||
const metadata1 = this.metadataCollector1.getMetadata(sourceFile, false);
|
const metadata1 = this.metadataCollector1.getMetadata(collectableFile, false);
|
||||||
const metadatas: ModuleMetadata[] = [metadata, metadata1].filter(e => !!e);
|
const metadatas: ModuleMetadata[] = [metadata, metadata1].filter(e => !!e);
|
||||||
if (metadatas.length) {
|
if (metadatas.length) {
|
||||||
const metadataText = JSON.stringify(metadatas);
|
const metadataText = JSON.stringify(metadatas);
|
||||||
|
|
|
@ -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 {MetadataEntry, MetadataError, MetadataGlobalReferenceExpression, MetadataImportedSymbolReferenceExpression, MetadataSymbolicCallExpression, MetadataSymbolicReferenceExpression, MetadataValue, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportedSymbolReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSpreadExpression} from './schema';
|
||||||
import {Symbols} from './symbols';
|
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 {
|
function isMethodCallOf(callExpression: ts.CallExpression, memberName: string): boolean {
|
||||||
const expression = callExpression.expression;
|
const expression = callExpression.expression;
|
||||||
if (expression.kind === ts.SyntaxKind.PropertyAccessExpression) {
|
if (expression.kind === ts.SyntaxKind.PropertyAccessExpression) {
|
||||||
|
@ -282,9 +286,8 @@ export class Evaluator {
|
||||||
});
|
});
|
||||||
if (error) return error;
|
if (error) return error;
|
||||||
return arr;
|
return arr;
|
||||||
case ts.SyntaxKind.SpreadElementExpression:
|
case spreadElementSyntaxKind:
|
||||||
let spread = <ts.SpreadElementExpression>node;
|
let spreadExpression = this.evaluateNode((node as any).expression);
|
||||||
let spreadExpression = this.evaluateNode(spread.expression);
|
|
||||||
return recordEntry({__symbolic: 'spread', expression: spreadExpression}, node);
|
return recordEntry({__symbolic: 'spread', expression: spreadExpression}, node);
|
||||||
case ts.SyntaxKind.CallExpression:
|
case ts.SyntaxKind.CallExpression:
|
||||||
const callExpression = <ts.CallExpression>node;
|
const callExpression = <ts.CallExpression>node;
|
||||||
|
|
Loading…
Reference in New Issue