feat: add support for TS 2.2
This commit is contained in:
parent
bccfaa46ec
commit
3c8a61e40c
|
@ -71,6 +71,8 @@ export function create(info: any /* ts.server.PluginCreateInfo */): ts.LanguageS
|
||||||
|
|
||||||
proxy.getQuickInfoAtPosition = function(fileName: string, position: number): ts.QuickInfo {
|
proxy.getQuickInfoAtPosition = function(fileName: string, position: number): ts.QuickInfo {
|
||||||
let base = oldLS.getQuickInfoAtPosition(fileName, position);
|
let base = oldLS.getQuickInfoAtPosition(fileName, position);
|
||||||
|
// TODO(vicb): the tags property has been removed in TS 2.2
|
||||||
|
const tags = (<any>base).tags;
|
||||||
tryOperation('get quick info', () => {
|
tryOperation('get quick info', () => {
|
||||||
const ours = ls.getHoverAt(fileName, position);
|
const ours = ls.getHoverAt(fileName, position);
|
||||||
if (ours) {
|
if (ours) {
|
||||||
|
@ -78,14 +80,16 @@ export function create(info: any /* ts.server.PluginCreateInfo */): ts.LanguageS
|
||||||
for (const part of ours.text) {
|
for (const part of ours.text) {
|
||||||
displayParts.push({kind: part.language !, text: part.text});
|
displayParts.push({kind: part.language !, text: part.text});
|
||||||
}
|
}
|
||||||
base = {
|
base = <any>{
|
||||||
displayParts,
|
displayParts,
|
||||||
documentation: [],
|
documentation: [],
|
||||||
kind: 'angular',
|
kind: 'angular',
|
||||||
kindModifiers: 'what does this do?',
|
kindModifiers: 'what does this do?',
|
||||||
textSpan: {start: ours.span.start, length: ours.span.end - ours.span.start},
|
textSpan: {start: ours.span.start, length: ours.span.end - ours.span.start},
|
||||||
tags: [],
|
|
||||||
};
|
};
|
||||||
|
if (tags) {
|
||||||
|
(<any>base).tags = tags;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AotSummaryResolver, CompileDirectiveMetadata, CompileMetadataResolver, CompilerConfig, DEFAULT_INTERPOLATION_CONFIG, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, HtmlParser, InterpolationConfig, NgAnalyzedModules, NgModuleResolver, ParseTreeResult, Parser, PipeResolver, ResourceLoader, StaticAndDynamicReflectionCapabilities, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, SummaryResolver, UrlResolver, analyzeNgModules, componentModuleUrl, createOfflineCompileUrlResolver, extractProgramSymbols} from '@angular/compiler';
|
import {AotSummaryResolver, CompileMetadataResolver, CompilerConfig, DEFAULT_INTERPOLATION_CONFIG, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, HtmlParser, InterpolationConfig, NgAnalyzedModules, NgModuleResolver, ParseTreeResult, PipeResolver, ResourceLoader, StaticAndDynamicReflectionCapabilities, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, SummaryResolver, analyzeNgModules, componentModuleUrl, createOfflineCompileUrlResolver, extractProgramSymbols} from '@angular/compiler';
|
||||||
import {AngularCompilerOptions} from '@angular/compiler-cli';
|
import {AngularCompilerOptions} from '@angular/compiler-cli';
|
||||||
import {Type, ViewEncapsulation, ɵConsole as Console} from '@angular/core';
|
import {ViewEncapsulation, ɵConsole as Console} from '@angular/core';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
@ -16,6 +16,7 @@ import * as ts from 'typescript';
|
||||||
import {createLanguageService} from './language_service';
|
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';
|
||||||
|
import {isTypescriptVersion} from './utils';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,6 +26,7 @@ const isPrivate = (ts as any).ModifierFlags ?
|
||||||
((node: ts.Node) =>
|
((node: ts.Node) =>
|
||||||
!!((ts as any).getCombinedModifierFlags(node) & (ts as any).ModifierFlags.Private)) :
|
!!((ts as any).getCombinedModifierFlags(node) & (ts as any).ModifierFlags.Private)) :
|
||||||
((node: ts.Node) => !!(node.flags & (ts as any).NodeFlags.Private));
|
((node: ts.Node) => !!(node.flags & (ts as any).NodeFlags.Private));
|
||||||
|
|
||||||
const isReferenceType = (ts as any).ObjectFlags ?
|
const isReferenceType = (ts as any).ObjectFlags ?
|
||||||
((type: ts.Type) =>
|
((type: ts.Type) =>
|
||||||
!!(type.flags & (ts as any).TypeFlags.Object &&
|
!!(type.flags & (ts as any).TypeFlags.Object &&
|
||||||
|
@ -46,11 +48,9 @@ export function createLanguageServiceFromTypescript(
|
||||||
* The language service never needs the normalized versions of the metadata. To avoid parsing
|
* The language service never needs the normalized versions of the metadata. To avoid parsing
|
||||||
* the content and resolving references, return an empty file. This also allows normalizing
|
* the content and resolving references, return an empty file. This also allows normalizing
|
||||||
* template that are syntatically incorrect which is required to provide completions in
|
* template that are syntatically incorrect which is required to provide completions in
|
||||||
* syntatically incorrect templates.
|
* syntactically incorrect templates.
|
||||||
*/
|
*/
|
||||||
export class DummyHtmlParser extends HtmlParser {
|
export class DummyHtmlParser extends HtmlParser {
|
||||||
constructor() { super(); }
|
|
||||||
|
|
||||||
parse(
|
parse(
|
||||||
source: string, url: string, parseExpansionForms: boolean = false,
|
source: string, url: string, parseExpansionForms: boolean = false,
|
||||||
interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): ParseTreeResult {
|
interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): ParseTreeResult {
|
||||||
|
@ -71,7 +71,7 @@ export class DummyResourceLoader extends ResourceLoader {
|
||||||
* The `TypeScriptServiceHost` implements the Angular `LanguageServiceHost` using
|
* The `TypeScriptServiceHost` implements the Angular `LanguageServiceHost` using
|
||||||
* the TypeScript language services.
|
* the TypeScript language services.
|
||||||
*
|
*
|
||||||
* @expermental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
export class TypeScriptServiceHost implements LanguageServiceHost {
|
export class TypeScriptServiceHost implements LanguageServiceHost {
|
||||||
private _resolver: CompileMetadataResolver;
|
private _resolver: CompileMetadataResolver;
|
||||||
|
@ -342,7 +342,6 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
|
||||||
case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
|
case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||||
case ts.SyntaxKind.StringLiteral:
|
case ts.SyntaxKind.StringLiteral:
|
||||||
let [declaration, decorator] = this.getTemplateClassDeclFromNode(node);
|
let [declaration, decorator] = this.getTemplateClassDeclFromNode(node);
|
||||||
let queryCache: SymbolQuery|undefined = undefined;
|
|
||||||
if (declaration && declaration.name) {
|
if (declaration && declaration.name) {
|
||||||
const sourceFile = this.getSourceFile(fileName);
|
const sourceFile = this.getSourceFile(fileName);
|
||||||
return this.getSourceFromDeclaration(
|
return this.getSourceFromDeclaration(
|
||||||
|
@ -564,8 +563,6 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
private findNode(sourceFile: ts.SourceFile, position: number): ts.Node|undefined {
|
private findNode(sourceFile: ts.SourceFile, position: number): ts.Node|undefined {
|
||||||
let _this = this;
|
|
||||||
|
|
||||||
function find(node: ts.Node): ts.Node|undefined {
|
function find(node: ts.Node): ts.Node|undefined {
|
||||||
if (position >= node.getStart() && position < node.getEnd()) {
|
if (position >= node.getStart() && position < node.getEnd()) {
|
||||||
return ts.forEachChild(node, find) || node;
|
return ts.forEachChild(node, find) || node;
|
||||||
|
@ -634,8 +631,6 @@ class TypeScriptSymbolQuery implements SymbolQuery {
|
||||||
|
|
||||||
getTypeUnion(...types: Symbol[]): Symbol {
|
getTypeUnion(...types: Symbol[]): Symbol {
|
||||||
// TODO: Replace with typeChecker API when available
|
// TODO: Replace with typeChecker API when available
|
||||||
const checker = this.checker;
|
|
||||||
|
|
||||||
// No API exists so the cheat is to just return the last type any if no types are given.
|
// No API exists so the cheat is to just return the last type any if no types are given.
|
||||||
return types.length ? types[types.length - 1] : this.getBuiltinType(BuiltinType.Any);
|
return types.length ? types[types.length - 1] : this.getBuiltinType(BuiltinType.Any);
|
||||||
}
|
}
|
||||||
|
@ -708,7 +703,9 @@ class TypeScriptSymbolQuery implements SymbolQuery {
|
||||||
|
|
||||||
private getTemplateRefContextType(typeSymbol: ts.Symbol): ts.Symbol|undefined {
|
private getTemplateRefContextType(typeSymbol: ts.Symbol): ts.Symbol|undefined {
|
||||||
const type = this.checker.getTypeOfSymbolAtLocation(typeSymbol, this.source);
|
const type = this.checker.getTypeOfSymbolAtLocation(typeSymbol, this.source);
|
||||||
const constructor = type.symbol && type.symbol.members && type.symbol.members['__constructor'];
|
const constructor = type.symbol && type.symbol.members &&
|
||||||
|
getFromSymbolTable(type.symbol.members !, '__constructor');
|
||||||
|
|
||||||
if (constructor) {
|
if (constructor) {
|
||||||
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) {
|
||||||
|
@ -719,7 +716,7 @@ class TypeScriptSymbolQuery implements SymbolQuery {
|
||||||
return typeReference.typeArguments[0].symbol;
|
return typeReference.typeArguments[0].symbol;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,29 +758,6 @@ function selectSignature(type: ts.Type, context: TypeContext, types: Symbol[]):
|
||||||
return signatures.length ? new SignatureWrapper(signatures[0], context) : undefined;
|
return signatures.length ? new SignatureWrapper(signatures[0], context) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function toSymbolTable(symbols: ts.Symbol[]): ts.SymbolTable {
|
|
||||||
const result: ts.SymbolTable = <any>{};
|
|
||||||
for (const symbol of symbols) {
|
|
||||||
result[symbol.name] = symbol;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function toSymbols(
|
|
||||||
symbolTable: ts.SymbolTable | undefined, filter?: (symbol: ts.Symbol) => boolean) {
|
|
||||||
const result: ts.Symbol[] = [];
|
|
||||||
if (!symbolTable) return result;
|
|
||||||
const own = typeof symbolTable.hasOwnProperty === 'function' ?
|
|
||||||
(name: string) => symbolTable.hasOwnProperty(name) :
|
|
||||||
(name: string) => !!symbolTable[name];
|
|
||||||
for (const name in symbolTable) {
|
|
||||||
if (own(name) && (!filter || filter(symbolTable[name]))) {
|
|
||||||
result.push(symbolTable[name]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
class TypeWrapper implements Symbol {
|
class TypeWrapper implements Symbol {
|
||||||
constructor(public tsType: ts.Type, public context: TypeContext) {
|
constructor(public tsType: ts.Type, public context: TypeContext) {
|
||||||
if (!tsType) {
|
if (!tsType) {
|
||||||
|
@ -932,31 +906,72 @@ class SignatureResultOverride implements Signature {
|
||||||
get result(): Symbol { return this.resultType; }
|
get result(): Symbol { return this.resultType; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toSymbolTable(symbols: ts.Symbol[]): ts.SymbolTable {
|
||||||
|
if (isTypescriptVersion('2.2')) {
|
||||||
|
const result = new Map<string, ts.Symbol>();
|
||||||
|
for (const symbol of symbols) {
|
||||||
|
result.set(symbol.name, symbol);
|
||||||
|
}
|
||||||
|
return <ts.SymbolTable>(result as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = <any>{};
|
||||||
|
for (const symbol of symbols) {
|
||||||
|
result[symbol.name] = symbol;
|
||||||
|
}
|
||||||
|
return result as ts.SymbolTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toSymbols(symbolTable: ts.SymbolTable | undefined): ts.Symbol[] {
|
||||||
|
if (!symbolTable) return [];
|
||||||
|
|
||||||
|
const table = symbolTable as any;
|
||||||
|
|
||||||
|
if (typeof table.values === 'function') {
|
||||||
|
return Array.from(table.values()) as ts.Symbol[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: ts.Symbol[] = [];
|
||||||
|
|
||||||
|
const own = typeof table.hasOwnProperty === 'function' ?
|
||||||
|
(name: string) => table.hasOwnProperty(name) :
|
||||||
|
(name: string) => !!table[name];
|
||||||
|
|
||||||
|
for (const name in table) {
|
||||||
|
if (own(name)) {
|
||||||
|
result.push(table[name]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
class SymbolTableWrapper implements SymbolTable {
|
class SymbolTableWrapper implements SymbolTable {
|
||||||
private symbols: ts.Symbol[];
|
private symbols: ts.Symbol[];
|
||||||
private symbolTable: ts.SymbolTable;
|
private symbolTable: ts.SymbolTable;
|
||||||
|
|
||||||
constructor(
|
constructor(symbols: ts.SymbolTable|ts.Symbol[]|undefined, private context: TypeContext) {
|
||||||
symbols: ts.SymbolTable|ts.Symbol[]|undefined, private context: TypeContext,
|
|
||||||
filter?: (symbol: ts.Symbol) => boolean) {
|
|
||||||
symbols = symbols || [];
|
symbols = symbols || [];
|
||||||
|
|
||||||
if (Array.isArray(symbols)) {
|
if (Array.isArray(symbols)) {
|
||||||
this.symbols = filter ? symbols.filter(filter) : symbols;
|
this.symbols = symbols;
|
||||||
this.symbolTable = toSymbolTable(symbols);
|
this.symbolTable = toSymbolTable(symbols);
|
||||||
} else {
|
} else {
|
||||||
this.symbols = toSymbols(symbols, filter);
|
this.symbols = toSymbols(symbols);
|
||||||
this.symbolTable = filter ? toSymbolTable(this.symbols) : symbols;
|
this.symbolTable = symbols;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get size(): number { return this.symbols.length; }
|
get size(): number { return this.symbols.length; }
|
||||||
|
|
||||||
get(key: string): Symbol|undefined {
|
get(key: string): Symbol|undefined {
|
||||||
const symbol = this.symbolTable[key];
|
const symbol = getFromSymbolTable(this.symbolTable, key);
|
||||||
return symbol ? new SymbolWrapper(symbol, this.context) : undefined;
|
return symbol ? new SymbolWrapper(symbol, this.context) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
has(key: string): boolean { return this.symbolTable[key] != null; }
|
has(key: string): boolean {
|
||||||
|
const table: any = this.symbolTable;
|
||||||
|
return (typeof table.has === 'function') ? table.has(key) : table[key] != null;
|
||||||
|
}
|
||||||
|
|
||||||
values(): Symbol[] { return this.symbols.map(s => new SymbolWrapper(s, this.context)); }
|
values(): Symbol[] { return this.symbols.map(s => new SymbolWrapper(s, this.context)); }
|
||||||
}
|
}
|
||||||
|
@ -1320,3 +1335,19 @@ function typeKindOf(type: ts.Type): BuiltinType {
|
||||||
}
|
}
|
||||||
return BuiltinType.Other;
|
return BuiltinType.Other;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getFromSymbolTable(symbolTable: ts.SymbolTable, key: string): ts.Symbol|undefined {
|
||||||
|
const table = symbolTable as any;
|
||||||
|
let symbol: ts.Symbol|undefined;
|
||||||
|
|
||||||
|
if (typeof table.get === 'function') {
|
||||||
|
// TS 2.2 uses a Map
|
||||||
|
symbol = table.get(key);
|
||||||
|
} else {
|
||||||
|
// TS pre-2.2 uses an object
|
||||||
|
symbol = table[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompileDirectiveSummary, CompileTypeMetadata, CssSelector, ParseSourceSpan, SelectorMatcher, identifierName} from '@angular/compiler';
|
import {CompileDirectiveSummary, CompileTypeMetadata, CssSelector, ParseSourceSpan, identifierName} from '@angular/compiler';
|
||||||
|
import * as ts from 'typescript';
|
||||||
import {SelectorInfo, TemplateInfo} from './common';
|
import {SelectorInfo, TemplateInfo} from './common';
|
||||||
import {Span} from './types';
|
import {Span} from './types';
|
||||||
|
|
||||||
|
@ -96,3 +96,13 @@ export function uniqueByName < T extends {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isTypescriptVersion(low: string, high?: string) {
|
||||||
|
const version = ts.version;
|
||||||
|
|
||||||
|
if (version.substring(0, low.length) < low) return false;
|
||||||
|
|
||||||
|
if (high && (version.substring(0, high.length) > high)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
export interface Directory { [name: string]: (Directory|string); }
|
export interface Directory { [name: string]: (Directory|string); }
|
||||||
|
@ -127,7 +126,8 @@ export class MockSymbol implements ts.Symbol {
|
||||||
getName(): string { return this.name; }
|
getName(): string { return this.name; }
|
||||||
getDeclarations(): ts.Declaration[] { return [this.node]; }
|
getDeclarations(): ts.Declaration[] { return [this.node]; }
|
||||||
getDocumentationComment(): ts.SymbolDisplayPart[] { return []; }
|
getDocumentationComment(): ts.SymbolDisplayPart[] { return []; }
|
||||||
getJsDocTags(): ts.JSDocTagInfo[]{return []};
|
// TODO(vicb): removed in TS 2.2
|
||||||
|
getJsDocTags(): any[]{return []};
|
||||||
|
|
||||||
static of (name: string): MockSymbol { return new MockSymbol(name); }
|
static of (name: string): MockSymbol { return new MockSymbol(name); }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue