From 346809ba2b4ab2050a99c593d117c36d342b57a3 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 23 Jul 2014 16:52:21 -0700 Subject: [PATCH] wire in getCompletions --- src/compiler/checker.ts | 122 ++++++++++----- src/compiler/parser.ts | 8 + src/compiler/types.ts | 1 + src/services/completionHelpers.ts | 72 ++++----- src/services/keywordCompletions.ts | 13 +- src/services/pullLanguageService.ts | 229 +++++++++++++++++++++++++++- src/services/services.ts | 4 + src/services/typescriptServices.ts | 2 + 8 files changed, 365 insertions(+), 86 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4ea24b834c5..ab32682c90a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -63,7 +63,33 @@ module ts { var diagnostics: Diagnostic[] = []; var diagnosticsModified: boolean = false; - var checker: TypeChecker; + var checker: TypeChecker = { + getProgram: () => program, + getDiagnostics: getDiagnostics, + getGlobalDiagnostics: getGlobalDiagnostics, + getNodeCount: () => sum(program.getSourceFiles(), "nodeCount"), + getIdentifierCount: () => sum(program.getSourceFiles(), "identifierCount"), + getSymbolCount: () => sum(program.getSourceFiles(), "symbolCount"), + getTypeCount: () => typeCount, + checkProgram: checkProgram, + emitFiles: invokeEmitter, + getSymbolOfNode: getSymbolOfNode, + getParentOfSymbol: getParentOfSymbol, + getTypeOfSymbol: getTypeOfSymbol, + getDeclaredTypeOfSymbol: getDeclaredTypeOfSymbol, + getPropertiesOfType: getPropertiesOfType, + getSignaturesOfType: getSignaturesOfType, + getIndexTypeOfType: getIndexTypeOfType, + getReturnTypeOfSignature: getReturnTypeOfSignature, + resolveEntityName: resolveEntityName, + getSymbolsInScope: getSymbolsInScope, + getSymbolOfIdentifier: getSymbolOfIdentifier, + getTypeOfExpression: getTypeOfExpression, + typeToString: typeToString, + symbolToString: symbolToString, + writeTypeToTextWriter: writeTypeToTextWriter, + getAugmentedPropertiesOfApparentType: getAugmentedPropertiesOfApparentType + }; function addDiagnostic(diagnostic: Diagnostic) { diagnostics.push(diagnostic); @@ -4784,14 +4810,6 @@ module ts { return (node.flags & NodeFlags.Private) && isInAmbientContext(node); } - function isInAmbientContext(node: Node): boolean { - while (node) { - if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) return true; - node = node.parent; - } - return false; - } - function checkSpecializedSignatureDeclaration(signatureDeclarationNode: SignatureDeclaration): void { var signature = getSignatureFromDeclaration(signatureDeclarationNode); if (!signature.hasStringLiterals) { @@ -6191,9 +6209,14 @@ module ts { return false; } + function isRightSideOfQualifiedName(node: Node) { + return (node.parent.kind === SyntaxKind.QualifiedName || node.parent.kind === SyntaxKind.PropertyAccess) && + (node.parent).right === node; + } + function getSymbolOfIdentifier(identifier: Identifier) { if (isExpression(identifier)) { - if (isRightSideOfQualifiedName()) { + if (isRightSideOfQualifiedName(identifier)) { var node = identifier.parent; var symbol = getNodeLinks(node).resolvedSymbol; if (!symbol) { @@ -6207,16 +6230,58 @@ module ts { return getSymbolOfNode(identifier.parent); } if (isTypeReferenceIdentifier(identifier)) { - var entityName = isRightSideOfQualifiedName() ? identifier.parent : identifier; + var entityName = isRightSideOfQualifiedName(identifier) ? identifier.parent : identifier; var meaning = entityName.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type : SymbolFlags.Namespace; return resolveEntityName(entityName, entityName, meaning); } - function isRightSideOfQualifiedName() { - return (identifier.parent.kind === SyntaxKind.QualifiedName || identifier.parent.kind === SyntaxKind.PropertyAccess) && - (identifier.parent).right === identifier; - } } + function getTypeOfExpression(node: Node) { + if (isExpression(node)) { + while (isRightSideOfQualifiedName(node)) { + node = node.parent; + } + return getApparentType(checkExpression(node)); + } + return unknownType; + } + + function getAugmentedPropertiesOfApparentType(type: Type): Symbol[]{ + var apparentType = getApparentType(type); + + if (apparentType.flags & TypeFlags.ObjectType) { + // Augment the apprent type with Function and Object memeber as applicaple + var propertiesByName: Map = {}; + var results: Symbol[] = []; + + forEach(getPropertiesOfType(apparentType), (s) => { + propertiesByName[s.name] = s; + results.push(s); + }); + + var resolved = resolveObjectTypeMembers(type); + forEachValue(resolved.members, (s) => { + if (symbolIsValue(s) && !propertiesByName[s.name]) { + propertiesByName[s.name] = s; + results.push(s); + } + }); + + if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) { + forEach(getPropertiesOfType(globalFunctionType), (s) => { + if (!propertiesByName[s.name]) { + propertiesByName[s.name] = s; + results.push(s); + } + }); + } + + return results; + } + else { + return getPropertiesOfType(apparentType); + } + } // Emitter support function isExternalModuleSymbol(symbol: Symbol): boolean { @@ -6410,32 +6475,7 @@ module ts { } initializeTypeChecker(); - checker = { - getProgram: () => program, - getDiagnostics: getDiagnostics, - getGlobalDiagnostics: getGlobalDiagnostics, - getNodeCount: () => sum(program.getSourceFiles(), "nodeCount"), - getIdentifierCount: () => sum(program.getSourceFiles(), "identifierCount"), - getSymbolCount: () => sum(program.getSourceFiles(), "symbolCount"), - getTypeCount: () => typeCount, - checkProgram: checkProgram, - emitFiles: invokeEmitter, - getSymbolOfNode: getSymbolOfNode, - getParentOfSymbol: getParentOfSymbol, - getTypeOfSymbol: getTypeOfSymbol, - getDeclaredTypeOfSymbol: getDeclaredTypeOfSymbol, - getPropertiesOfType: getPropertiesOfType, - getSignaturesOfType: getSignaturesOfType, - getIndexTypeOfType: getIndexTypeOfType, - getReturnTypeOfSignature: getReturnTypeOfSignature, - resolveEntityName: resolveEntityName, - getSymbolsInScope: getSymbolsInScope, - getSymbolOfIdentifier: getSymbolOfIdentifier, - getTypeOfExpression: checkExpression, - typeToString: typeToString, - symbolToString: symbolToString, - writeTypeToTextWriter: writeTypeToTextWriter - }; + return checker; } } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index d1e2b83a2b7..bd4b0510b9a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -327,6 +327,14 @@ module ts { return s.parameters.length > 0 && (s.parameters[s.parameters.length - 1].flags & NodeFlags.Rest) !== 0; } + export function isInAmbientContext(node: Node): boolean { + while (node) { + if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) return true; + node = node.parent; + } + return false; + } + enum ParsingContext { SourceElements, // Elements in source file ModuleElements, // Elements in module declaration diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9078e8a4b56..71d1c9d1e84 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -603,6 +603,7 @@ module ts { typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string; symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string; writeTypeToTextWriter(type: Type, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void; + getAugmentedPropertiesOfApparentType(type: Type): Symbol[]; } export interface TextWriter { diff --git a/src/services/completionHelpers.ts b/src/services/completionHelpers.ts index c5cb961af79..17a68d097b0 100644 --- a/src/services/completionHelpers.ts +++ b/src/services/completionHelpers.ts @@ -9,46 +9,46 @@ module TypeScript.Services { return new TextSpan(start(ast), width(ast)); } - private static symbolDeclarationIntersectsPosition(symbol: PullSymbol, fileName: string, position: number) { - var decl = symbol.getDeclarations()[0]; - if (decl.fileName() === fileName && this.getSpan(decl.ast()).intersectsWithPosition(position)) { - // This is the symbol declaration from the given position in the file - return true; - } + //private static symbolDeclarationIntersectsPosition(symbol: PullSymbol, fileName: string, position: number) { + // var decl = symbol.getDeclarations()[0]; + // if (decl.fileName() === fileName && this.getSpan(decl.ast()).intersectsWithPosition(position)) { + // // This is the symbol declaration from the given position in the file + // return true; + // } - return false; - } + // return false; + //} - public static filterContextualMembersList(contextualMemberSymbols: TypeScript.PullSymbol[], existingMembers: TypeScript.PullVisibleSymbolsInfo, fileName: string, position: number): TypeScript.PullSymbol[] { - if (!existingMembers || !existingMembers.symbols || existingMembers.symbols.length === 0) { - return contextualMemberSymbols; - } + //public static filterContextualMembersList(contextualMemberSymbols: TypeScript.PullSymbol[], existingMembers: TypeScript.PullVisibleSymbolsInfo, fileName: string, position: number): TypeScript.PullSymbol[] { + // if (!existingMembers || !existingMembers.symbols || existingMembers.symbols.length === 0) { + // return contextualMemberSymbols; + // } - var existingMemberSymbols = existingMembers.symbols; - var existingMemberNames = TypeScript.createIntrinsicsObject(); - for (var i = 0, n = existingMemberSymbols.length; i < n; i++) { - if (this.symbolDeclarationIntersectsPosition(existingMemberSymbols[i], fileName, position)) { - // If this is the current item we are editing right now, do not filter it out - continue; - } + // var existingMemberSymbols = existingMembers.symbols; + // var existingMemberNames = TypeScript.createIntrinsicsObject(); + // for (var i = 0, n = existingMemberSymbols.length; i < n; i++) { + // if (this.symbolDeclarationIntersectsPosition(existingMemberSymbols[i], fileName, position)) { + // // If this is the current item we are editing right now, do not filter it out + // continue; + // } - existingMemberNames[TypeScript.stripStartAndEndQuotes(existingMemberSymbols[i].getDisplayName())] = true; - } + // existingMemberNames[TypeScript.stripStartAndEndQuotes(existingMemberSymbols[i].getDisplayName())] = true; + // } - var filteredMembers: TypeScript.PullSymbol[] = []; - for (var j = 0, m = contextualMemberSymbols.length; j < m; j++) { - var contextualMemberSymbol = contextualMemberSymbols[j]; - if (!existingMemberNames[TypeScript.stripStartAndEndQuotes(contextualMemberSymbol.getDisplayName())]) { - if (this.symbolDeclarationIntersectsPosition(contextualMemberSymbol, fileName, position)) { - // If this contextual member symbol was created as part of editing the current position, do not use it - continue; - } - filteredMembers.push(contextualMemberSymbol); - } - } + // var filteredMembers: TypeScript.PullSymbol[] = []; + // for (var j = 0, m = contextualMemberSymbols.length; j < m; j++) { + // var contextualMemberSymbol = contextualMemberSymbols[j]; + // if (!existingMemberNames[TypeScript.stripStartAndEndQuotes(contextualMemberSymbol.getDisplayName())]) { + // if (this.symbolDeclarationIntersectsPosition(contextualMemberSymbol, fileName, position)) { + // // If this contextual member symbol was created as part of editing the current position, do not use it + // continue; + // } + // filteredMembers.push(contextualMemberSymbol); + // } + // } - return filteredMembers; - } + // return filteredMembers; + //} public static isCompletionListBlocker(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { // We shouldn't be getting a possition that is outside the file because @@ -173,7 +173,7 @@ module TypeScript.Services { return false; } - public static getValidCompletionEntryDisplayName(displayName: string): string { + public static getValidCompletionEntryDisplayName(displayName: string, target: ts.ScriptTarget): string { if (displayName && displayName.length > 0) { var firstChar = displayName.charCodeAt(0); if (firstChar === TypeScript.CharacterCodes.singleQuote || firstChar === TypeScript.CharacterCodes.doubleQuote) { @@ -182,7 +182,7 @@ module TypeScript.Services { displayName = TypeScript.stripStartAndEndQuotes(displayName); } - if (TypeScript.Scanner.isValidIdentifier(TypeScript.SimpleText.fromString(displayName), TypeScript.LanguageVersion.EcmaScript5)) { + if (TypeScript.Scanner.isValidIdentifier(TypeScript.SimpleText.fromString(displayName), target)) { return displayName; } } diff --git a/src/services/keywordCompletions.ts b/src/services/keywordCompletions.ts index 90ebc5bdd53..3233a0f95a7 100644 --- a/src/services/keywordCompletions.ts +++ b/src/services/keywordCompletions.ts @@ -53,15 +53,18 @@ module TypeScript.Services { "with", ]; - private static keywordCompletions: ResolvedCompletionEntry[] = null; + private static keywordCompletions: CompletionEntry[] = null; - public static getKeywordCompltions(): ResolvedCompletionEntry[]{ + public static getKeywordCompltions(): CompletionEntry[]{ if (KeywordCompletions.keywordCompletions === null) { - var completions: ResolvedCompletionEntry[] = []; + var completions: CompletionEntry[] = []; for (var i = 0, n = KeywordCompletions.keywords.length; i < n; i++) { var keyword = KeywordCompletions.keywords[i]; - var entry = new ResolvedCompletionEntry(/*name*/ keyword, ScriptElementKind.keyword, ScriptElementKindModifier.none, /*type*/null, /*fullName*/ keyword, /*docComment*/ null); - completions.push(entry); + completions.push({ + name: keyword, + kind: ScriptElementKind.keyword, + kindModifiers: ScriptElementKindModifier.none + }); } KeywordCompletions.keywordCompletions = completions; diff --git a/src/services/pullLanguageService.ts b/src/services/pullLanguageService.ts index 9286c4ea203..7b97c1a9d63 100644 --- a/src/services/pullLanguageService.ts +++ b/src/services/pullLanguageService.ts @@ -7,6 +7,15 @@ /// module TypeScript.Services { + interface CompletionSession { + filename: string; // the file where the completion was requested + position: number; // position in the file where the completion was requested + entries: CompletionEntry[]; // entries for this completion + symbols: ts.Map; // symbols by entry name map + location: ts.Node; // the node where the completion was requested + typeChecker: ts.TypeChecker;// the typeChecker used to generate this completion + } + // Information about a specific host file. class HostFileInformation { private _sourceText: TypeScript.IScriptSnapshot; @@ -420,6 +429,7 @@ module TypeScript.Services { private documentsByName: ts.Map = {}; private documentRegistry: IDocumentRegistry private cancellationToken: CancellationToken; + private activeCompletionSession: CompletionSession; constructor(public host: ILanguageServiceHost, documentRegistry: IDocumentRegistry) { this.logger = this.host; @@ -558,11 +568,206 @@ module TypeScript.Services { this.synchronizeHostData(); return this.program.getGlobalDiagnostics(); } + + private getCompletionEntriesFromSymbols(symbols: ts.Symbol[], session:CompletionSession): void { + ts.forEach(symbols, (symbol) => { + var entry = this.createCompletionEntry(symbol); + if (entry) { + session.entries.push(entry); + session.symbols[entry.name] = symbol; + } + }); + } + + private createCompletionEntry(symbol: ts.Symbol): CompletionEntry { + // Try to get a valid display name for this symbol, if we could not find one, then ignore it. + // We would like to only show things that can be added after a dot, so for instance numeric properties can + // not be accessed with a dot (a.1 <- invalid) + var displayName = CompletionHelpers.getValidCompletionEntryDisplayName(symbol.getName(), this.program.getCompilerOptions().target); + if (!displayName) { + return undefined; + } + + var declarations = symbol.getDeclarations(); + var firstDeclaration = [0]; + return { + name: displayName, + kind: this.getSymbolKind(symbol), + kindModifiers: declarations ? this.getNodeModifiers(declarations[0]) : ScriptElementKindModifier.none + }; + } + getCompletionsAtPosition(filename: string, position: number, isMemberCompletion: boolean) { - return undefined; + this.synchronizeHostData(); + + filename = TypeScript.switchToForwardSlashes(filename); + + var document = this.documentsByName[filename]; + var sourceUnit = document.sourceUnit(); + + if (CompletionHelpers.isCompletionListBlocker(document.syntaxTree().sourceUnit(), position)) { + this.logger.log("Returning an empty list because completion was blocked."); + return null; + } + + var node = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, position, /*useTrailingTriviaAsLimChar*/ true, /*forceInclusive*/ true); + + if (node && node.kind() === TypeScript.SyntaxKind.IdentifierName && + start(node) === end(node)) { + // Ignore missing name nodes + node = node.parent; + } + + var isRightOfDot = false; + if (node && + node.kind() === TypeScript.SyntaxKind.MemberAccessExpression && + end((node).expression) < position) { + + isRightOfDot = true; + node = (node).expression; + } + else if (node && + node.kind() === TypeScript.SyntaxKind.QualifiedName && + end((node).left) < position) { + + isRightOfDot = true; + node = (node).left; + } + else if (node && node.parent && + node.kind() === TypeScript.SyntaxKind.IdentifierName && + node.parent.kind() === TypeScript.SyntaxKind.MemberAccessExpression && + (node.parent).name === node) { + + isRightOfDot = true; + node = (node.parent).expression; + } + else if (node && node.parent && + node.kind() === TypeScript.SyntaxKind.IdentifierName && + node.parent.kind() === TypeScript.SyntaxKind.QualifiedName && + (node.parent).right === node) { + + isRightOfDot = true; + node = (node.parent).left; + } + + // TODO: this is a hack for now, we need a proper walking mechanism to verify that we have the correct node + var mappedNode = this.getNodeAtPosition(document.sourceFile(), end(node) - 1); + + Debug.assert(mappedNode, "Could not map a Fidelity node to an AST node"); + + // Get the completions + this.activeCompletionSession = { + filename: filename, + position: position, + entries: [], + symbols: {}, + location: mappedNode, + typeChecker: this.typeChecker + }; + + // Right of dot member completion list + if (isRightOfDot) { + var type: ts.Type = this.typeChecker.getTypeOfExpression(mappedNode); + if (!type) { + return undefined; + } + + var symbols = type.getApparentProperties(); + isMemberCompletion = true; + this.getCompletionEntriesFromSymbols(symbols, this.activeCompletionSession); + } + else { + var containingObjectLiteral = CompletionHelpers.getContainingObjectLiteralApplicableForCompletion(document.syntaxTree().sourceUnit(), position); + + // Object literal expression, look up possible property names from contextual type + if (containingObjectLiteral) { + var searchPosition = Math.min(position, end(containingObjectLiteral)); + var path = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, searchPosition); + // Get the object literal node + + while (node && node.kind() !== TypeScript.SyntaxKind.ObjectLiteralExpression) { + node = node.parent; + } + + if (!node || node.kind() !== TypeScript.SyntaxKind.ObjectLiteralExpression) { + // AST Path look up did not result in the same node as Fidelity Syntax Tree look up. + // Once we remove AST this will no longer be a problem. + return null; + } + + isMemberCompletion = true; + + //// Try to get the object members form contextual typing + //var contextualMembers = this.compiler.getContextualMembersFromAST(node, document); + //if (contextualMembers && contextualMembers.symbols && contextualMembers.symbols.length > 0) { + // // get existing members + // var existingMembers = this.compiler.getVisibleMemberSymbolsFromAST(node, document); + + // // Add filtterd items to the completion list + // this.getCompletionEntriesFromSymbols({ + // symbols: CompletionHelpers.filterContextualMembersList(contextualMembers.symbols, existingMembers, filename, position), + // enclosingScopeSymbol: contextualMembers.enclosingScopeSymbol + // }, entries); + //} + } + // Get scope memebers + else { + isMemberCompletion = false; + /// TODO filter meaning based on the current context + var symbolMeanings = ts.SymbolFlags.Type | ts.SymbolFlags.Value | ts.SymbolFlags.Namespace; + var symbols = this.typeChecker.getSymbolsInScope(mappedNode, symbolMeanings); + + this.getCompletionEntriesFromSymbols(symbols, this.activeCompletionSession); + } + } + + // Add keywords if this is not a member completion list + if (!isMemberCompletion) { + Array.prototype.push.apply(this.activeCompletionSession.entries, KeywordCompletions.getKeywordCompltions()); + } + + return { + isMemberCompletion: isMemberCompletion, + entries: this.activeCompletionSession.entries + }; } getCompletionEntryDetails(filename: string, position: number, entryName: string) { - return undefined; + // Note: No need to call synchronizeHostData, as we have captured all the data we need + // in the getCompletionsAtPosition erlier + filename = TypeScript.switchToForwardSlashes(filename); + + var session = this.activeCompletionSession; + + // Ensure that the current active completion session is still valid for this request + if (!session || session.filename !== filename || session.position !== position) { + return undefined; + } + + var symbol = this.activeCompletionSession.symbols[entryName]; + if (symbol) { + var type = session.typeChecker.getTypeOfSymbol(symbol); + Debug.assert(type, "Could not find type for symbol"); + var completionEntry = this.createCompletionEntry(symbol); + return { + name: entryName, + kind: completionEntry.kind, + kindModifiers: completionEntry.kindModifiers, + type: session.typeChecker.typeToString(type, session.location), + fullSymbolName: this.typeChecker.symbolToString(symbol, session.location), + docComment: "" + }; + } + else { + // No symbol, it is a keyword + return { + name: entryName, + kind: ScriptElementKind.keyword, + kindModifiers: ScriptElementKindModifier.none, + type: undefined, + fullSymbolName: entryName, + docComment: undefined + }; + } } private getNodeAtPosition(sourceFile: ts.SourceFile, position: number) { @@ -581,7 +786,7 @@ module TypeScript.Services { } } - getEnclosingDeclaration(node: ts.Node): ts.Node { + private getEnclosingDeclaration(node: ts.Node): ts.Node { while (true) { node = node.parent; if (!node) { @@ -601,10 +806,10 @@ module TypeScript.Services { } } } - getSymbolKind(symbol: ts.Symbol): string { var flags = symbol.getFlags(); + if (flags & ts.SymbolFlags.Module) return ScriptElementKind.moduleElement; if (flags & ts.SymbolFlags.Class) return ScriptElementKind.classElement; if (flags & ts.SymbolFlags.Interface) return ScriptElementKind.interfaceElement; @@ -621,20 +826,36 @@ module TypeScript.Services { if (flags & ts.SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement; if (flags & ts.SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; if (flags & ts.SymbolFlags.EnumMember) return ScriptElementKind.variableElement; + return ScriptElementKind.unknown; } getTypeKind(type: ts.Type): string { var flags = type.getFlags(); + if (flags & ts.TypeFlags.Enum) return ScriptElementKind.enumElement; if (flags & ts.TypeFlags.Class) return ScriptElementKind.classElement; if (flags & ts.TypeFlags.Interface) return ScriptElementKind.interfaceElement; if (flags & ts.TypeFlags.TypeParameter) return ScriptElementKind.typeParameterElement; if (flags & ts.TypeFlags.Intrinsic) return ScriptElementKind.primitiveType; if (flags & ts.TypeFlags.StringLiteral) return ScriptElementKind.primitiveType; + return ScriptElementKind.unknown; } + getNodeModifiers(node: ts.Node): string { + var flags = node.flags; + var result: string[] = []; + + if (flags & ts.NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); + if (flags & ts.NodeFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier); + if (flags & ts.NodeFlags.Static) result.push(ScriptElementKindModifier.staticModifier); + if (flags & ts.NodeFlags.Export) result.push(ScriptElementKindModifier.exportedModifier); + if (ts.isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier); + + return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none; + } + getTypeAtPosition(filename: string, position: number): TypeInfo { this.synchronizeHostData(); diff --git a/src/services/services.ts b/src/services/services.ts index 5f9d3a2f708..e8cd12002fd 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -28,6 +28,7 @@ module ts { getFlags(): TypeFlags; getSymbol(): Symbol; getProperties(): Symbol[]; + getApparentProperties(): Symbol[]; getCallSignatures(): Signature[]; getConstructSignatures(): Signature[]; getStringIndexType(): Type; @@ -213,6 +214,9 @@ module ts { getProperties(): Symbol[] { return this.checker.getPropertiesOfType(this); } + getApparentProperties(): Symbol[]{ + return this.checker.getAugmentedPropertiesOfApparentType(this); + } getCallSignatures(): Signature[] { return this.checker.getSignaturesOfType(this, SignatureKind.Call); } diff --git a/src/services/typescriptServices.ts b/src/services/typescriptServices.ts index 9c79c2db5b0..21ae5f6a6fa 100644 --- a/src/services/typescriptServices.ts +++ b/src/services/typescriptServices.ts @@ -34,6 +34,8 @@ /// /// /// +/// +/// ///