diff --git a/src/services/services.js b/src/services/services.js deleted file mode 100644 index 2f3a191d5d6..00000000000 --- a/src/services/services.js +++ /dev/null @@ -1,4423 +0,0 @@ -/// -var __extends = this.__extends || function (d, b) { - for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; - function __() { this.constructor = d; } - __.prototype = b.prototype; - d.prototype = new __(); -}; -/// -/// -/// -/// -/// -/// -/// -var ts; -(function (ts) { - ts.servicesVersion = "0.4"; - var ScriptSnapshot; - (function (ScriptSnapshot) { - var StringScriptSnapshot = (function () { - function StringScriptSnapshot(text) { - this.text = text; - this._lineStartPositions = undefined; - } - StringScriptSnapshot.prototype.getText = function (start, end) { - return this.text.substring(start, end); - }; - StringScriptSnapshot.prototype.getLength = function () { - return this.text.length; - }; - StringScriptSnapshot.prototype.getLineStartPositions = function () { - if (!this._lineStartPositions) { - this._lineStartPositions = ts.computeLineStarts(this.text); - } - return this._lineStartPositions; - }; - StringScriptSnapshot.prototype.getChangeRange = function (oldSnapshot) { - // Text-based snapshots do not support incremental parsing. Return undefined - // to signal that to the caller. - return undefined; - }; - return StringScriptSnapshot; - })(); - function fromString(text) { - return new StringScriptSnapshot(text); - } - ScriptSnapshot.fromString = fromString; - })(ScriptSnapshot = ts.ScriptSnapshot || (ts.ScriptSnapshot = {})); - var scanner = ts.createScanner(ts.ScriptTarget.Latest, true); - var emptyArray = []; - function createNode(kind, pos, end, flags, parent) { - var node = new (ts.getNodeConstructor(kind))(); - node.pos = pos; - node.end = end; - node.flags = flags; - node.parent = parent; - return node; - } - var NodeObject = (function () { - function NodeObject() { - } - NodeObject.prototype.getSourceFile = function () { - return ts.getSourceFileOfNode(this); - }; - NodeObject.prototype.getStart = function (sourceFile) { - return ts.getTokenPosOfNode(this, sourceFile); - }; - NodeObject.prototype.getFullStart = function () { - return this.pos; - }; - NodeObject.prototype.getEnd = function () { - return this.end; - }; - NodeObject.prototype.getWidth = function (sourceFile) { - return this.getEnd() - this.getStart(sourceFile); - }; - NodeObject.prototype.getFullWidth = function () { - return this.end - this.getFullStart(); - }; - NodeObject.prototype.getLeadingTriviaWidth = function (sourceFile) { - return this.getStart(sourceFile) - this.pos; - }; - NodeObject.prototype.getFullText = function (sourceFile) { - return (sourceFile || this.getSourceFile()).text.substring(this.pos, this.end); - }; - NodeObject.prototype.getText = function (sourceFile) { - return (sourceFile || this.getSourceFile()).text.substring(this.getStart(), this.getEnd()); - }; - NodeObject.prototype.addSyntheticNodes = function (nodes, pos, end) { - scanner.setTextPos(pos); - while (pos < end) { - var token = scanner.scan(); - var textPos = scanner.getTextPos(); - nodes.push(createNode(token, pos, textPos, ts.NodeFlags.Synthetic, this)); - pos = textPos; - } - return pos; - }; - NodeObject.prototype.createSyntaxList = function (nodes) { - var list = createNode(ts.SyntaxKind.SyntaxList, nodes.pos, nodes.end, ts.NodeFlags.Synthetic, this); - list._children = []; - var pos = nodes.pos; - for (var i = 0, len = nodes.length; i < len; i++) { - var node = nodes[i]; - if (pos < node.pos) { - pos = this.addSyntheticNodes(list._children, pos, node.pos); - } - list._children.push(node); - pos = node.end; - } - if (pos < nodes.end) { - this.addSyntheticNodes(list._children, pos, nodes.end); - } - return list; - }; - NodeObject.prototype.createChildren = function (sourceFile) { - var _this = this; - if (this.kind >= ts.SyntaxKind.FirstNode) { - scanner.setText((sourceFile || this.getSourceFile()).text); - var children = []; - var pos = this.pos; - var processNode = function (node) { - if (pos < node.pos) { - pos = _this.addSyntheticNodes(children, pos, node.pos); - } - children.push(node); - pos = node.end; - }; - var processNodes = function (nodes) { - if (pos < nodes.pos) { - pos = _this.addSyntheticNodes(children, pos, nodes.pos); - } - children.push(_this.createSyntaxList(nodes)); - pos = nodes.end; - }; - ts.forEachChild(this, processNode, processNodes); - if (pos < this.end) { - this.addSyntheticNodes(children, pos, this.end); - } - scanner.setText(undefined); - } - this._children = children || emptyArray; - }; - NodeObject.prototype.getChildCount = function (sourceFile) { - if (!this._children) - this.createChildren(sourceFile); - return this._children.length; - }; - NodeObject.prototype.getChildAt = function (index, sourceFile) { - if (!this._children) - this.createChildren(sourceFile); - return this._children[index]; - }; - NodeObject.prototype.getChildren = function (sourceFile) { - if (!this._children) - this.createChildren(sourceFile); - return this._children; - }; - NodeObject.prototype.getFirstToken = function (sourceFile) { - var children = this.getChildren(); - for (var i = 0; i < children.length; i++) { - var child = children[i]; - if (child.kind < ts.SyntaxKind.FirstNode) { - return child; - } - return child.getFirstToken(sourceFile); - } - }; - NodeObject.prototype.getLastToken = function (sourceFile) { - var children = this.getChildren(sourceFile); - for (var i = children.length - 1; i >= 0; i--) { - var child = children[i]; - if (child.kind < ts.SyntaxKind.FirstNode) { - return child; - } - return child.getLastToken(sourceFile); - } - }; - return NodeObject; - })(); - var SymbolObject = (function () { - function SymbolObject(flags, name) { - this.flags = flags; - this.name = name; - } - SymbolObject.prototype.getFlags = function () { - return this.flags; - }; - SymbolObject.prototype.getName = function () { - return this.name; - }; - SymbolObject.prototype.getDeclarations = function () { - return this.declarations; - }; - SymbolObject.prototype.getDocumentationComment = function () { - if (this.documentationComment === undefined) { - this.documentationComment = getJsDocCommentsFromDeclarations(this.declarations, this.name, !(this.flags & ts.SymbolFlags.Property)); - } - return this.documentationComment; - }; - return SymbolObject; - })(); - function getJsDocCommentsFromDeclarations(declarations, name, canUseParsedParamTagComments) { - var documentationComment = []; - var docComments = getJsDocCommentsSeparatedByNewLines(); - ts.forEach(docComments, function (docComment) { - if (documentationComment.length) { - documentationComment.push(ts.lineBreakPart()); - } - documentationComment.push(docComment); - }); - return documentationComment; - function getJsDocCommentsSeparatedByNewLines() { - var paramTag = "@param"; - var jsDocCommentParts = []; - ts.forEach(declarations, function (declaration) { - var sourceFileOfDeclaration = ts.getSourceFileOfNode(declaration); - // If it is parameter - try and get the jsDoc comment with @param tag from function declaration's jsDoc comments - if (canUseParsedParamTagComments && declaration.kind === ts.SyntaxKind.Parameter) { - ts.forEach(getJsDocCommentTextRange(declaration.parent, sourceFileOfDeclaration), function (jsDocCommentTextRange) { - var cleanedParamJsDocComment = getCleanedParamJsDocComment(jsDocCommentTextRange.pos, jsDocCommentTextRange.end, sourceFileOfDeclaration); - if (cleanedParamJsDocComment) { - jsDocCommentParts.push.apply(jsDocCommentParts, cleanedParamJsDocComment); - } - }); - } - // If this is left side of dotted module declaration, there is no doc comments associated with this node - if (declaration.kind === ts.SyntaxKind.ModuleDeclaration && declaration.body.kind === ts.SyntaxKind.ModuleDeclaration) { - return; - } - while (declaration.kind === ts.SyntaxKind.ModuleDeclaration && declaration.parent.kind === ts.SyntaxKind.ModuleDeclaration) { - declaration = declaration.parent; - } - // Get the cleaned js doc comment text from the declaration - ts.forEach(getJsDocCommentTextRange(declaration.kind === ts.SyntaxKind.VariableDeclaration ? declaration.parent.parent : declaration, sourceFileOfDeclaration), function (jsDocCommentTextRange) { - var cleanedJsDocComment = getCleanedJsDocComment(jsDocCommentTextRange.pos, jsDocCommentTextRange.end, sourceFileOfDeclaration); - if (cleanedJsDocComment) { - jsDocCommentParts.push.apply(jsDocCommentParts, cleanedJsDocComment); - } - }); - }); - return jsDocCommentParts; - function getJsDocCommentTextRange(node, sourceFile) { - return ts.map(ts.getJsDocComments(node, sourceFile), function (jsDocComment) { - return { - pos: jsDocComment.pos + "/*".length, - end: jsDocComment.end - "*/".length // Trim off comment end indicator - }; - }); - } - function consumeWhiteSpacesOnTheLine(pos, end, sourceFile, maxSpacesToRemove) { - if (maxSpacesToRemove !== undefined) { - end = Math.min(end, pos + maxSpacesToRemove); - } - for (; pos < end; pos++) { - var ch = sourceFile.text.charCodeAt(pos); - if (!ts.isWhiteSpace(ch) || ts.isLineBreak(ch)) { - // Either found lineBreak or non whiteSpace - return pos; - } - } - return end; - } - function consumeLineBreaks(pos, end, sourceFile) { - while (pos < end && ts.isLineBreak(sourceFile.text.charCodeAt(pos))) { - pos++; - } - return pos; - } - function isName(pos, end, sourceFile, name) { - return pos + name.length < end && sourceFile.text.substr(pos, name.length) === name && (ts.isWhiteSpace(sourceFile.text.charCodeAt(pos + name.length)) || ts.isLineBreak(sourceFile.text.charCodeAt(pos + name.length))); - } - function isParamTag(pos, end, sourceFile) { - // If it is @param tag - return isName(pos, end, sourceFile, paramTag); - } - function pushDocCommentLineText(docComments, text, blankLineCount) { - while (blankLineCount--) - docComments.push(ts.textPart("")); - docComments.push(ts.textPart(text)); - } - function getCleanedJsDocComment(pos, end, sourceFile) { - var spacesToRemoveAfterAsterisk; - var docComments = []; - var blankLineCount = 0; - var isInParamTag = false; - while (pos < end) { - var docCommentTextOfLine = ""; - // First consume leading white space - pos = consumeWhiteSpacesOnTheLine(pos, end, sourceFile); - // If the comment starts with '*' consume the spaces on this line - if (pos < end && sourceFile.text.charCodeAt(pos) === ts.CharacterCodes.asterisk) { - var lineStartPos = pos + 1; - pos = consumeWhiteSpacesOnTheLine(pos + 1, end, sourceFile, spacesToRemoveAfterAsterisk); - // Set the spaces to remove after asterisk as margin if not already set - if (spacesToRemoveAfterAsterisk === undefined && pos < end && !ts.isLineBreak(sourceFile.text.charCodeAt(pos))) { - spacesToRemoveAfterAsterisk = pos - lineStartPos; - } - } - else if (spacesToRemoveAfterAsterisk === undefined) { - spacesToRemoveAfterAsterisk = 0; - } - while (pos < end && !ts.isLineBreak(sourceFile.text.charCodeAt(pos))) { - var ch = sourceFile.text.charAt(pos); - if (ch === "@") { - // If it is @param tag - if (isParamTag(pos, end, sourceFile)) { - isInParamTag = true; - pos += paramTag.length; - continue; - } - else { - isInParamTag = false; - } - } - // Add the ch to doc text if we arent in param tag - if (!isInParamTag) { - docCommentTextOfLine += ch; - } - // Scan next character - pos++; - } - // Continue with next line - pos = consumeLineBreaks(pos, end, sourceFile); - if (docCommentTextOfLine) { - pushDocCommentLineText(docComments, docCommentTextOfLine, blankLineCount); - blankLineCount = 0; - } - else if (!isInParamTag && docComments.length) { - // This is blank line when there is text already parsed - blankLineCount++; - } - } - return docComments; - } - function getCleanedParamJsDocComment(pos, end, sourceFile) { - var paramHelpStringMargin; - var paramDocComments = []; - while (pos < end) { - if (isParamTag(pos, end, sourceFile)) { - var blankLineCount = 0; - var recordedParamTag = false; - // Consume leading spaces - pos = consumeWhiteSpaces(pos + paramTag.length); - if (pos >= end) { - break; - } - // Ignore type expression - if (sourceFile.text.charCodeAt(pos) === ts.CharacterCodes.openBrace) { - pos++; - for (var curlies = 1; pos < end; pos++) { - var charCode = sourceFile.text.charCodeAt(pos); - // { character means we need to find another } to match the found one - if (charCode === ts.CharacterCodes.openBrace) { - curlies++; - continue; - } - // } char - if (charCode === ts.CharacterCodes.closeBrace) { - curlies--; - if (curlies === 0) { - // We do not have any more } to match the type expression is ignored completely - pos++; - break; - } - else { - continue; - } - } - // Found start of another tag - if (charCode === ts.CharacterCodes.at) { - break; - } - } - // Consume white spaces - pos = consumeWhiteSpaces(pos); - if (pos >= end) { - break; - } - } - // Parameter name - if (isName(pos, end, sourceFile, name)) { - // Found the parameter we are looking for consume white spaces - pos = consumeWhiteSpaces(pos + name.length); - if (pos >= end) { - break; - } - var paramHelpString = ""; - var firstLineParamHelpStringPos = pos; - while (pos < end) { - var ch = sourceFile.text.charCodeAt(pos); - // at line break, set this comment line text and go to next line - if (ts.isLineBreak(ch)) { - if (paramHelpString) { - pushDocCommentLineText(paramDocComments, paramHelpString, blankLineCount); - paramHelpString = ""; - blankLineCount = 0; - recordedParamTag = true; - } - else if (recordedParamTag) { - blankLineCount++; - } - // Get the pos after cleaning start of the line - setPosForParamHelpStringOnNextLine(firstLineParamHelpStringPos); - continue; - } - // Done scanning param help string - next tag found - if (ch === ts.CharacterCodes.at) { - break; - } - paramHelpString += sourceFile.text.charAt(pos); - // Go to next character - pos++; - } - // If there is param help text, add it top the doc comments - if (paramHelpString) { - pushDocCommentLineText(paramDocComments, paramHelpString, blankLineCount); - } - paramHelpStringMargin = undefined; - } - // If this is the start of another tag, continue with the loop in seach of param tag with symbol name - if (sourceFile.text.charCodeAt(pos) === ts.CharacterCodes.at) { - continue; - } - } - // Next character - pos++; - } - return paramDocComments; - function consumeWhiteSpaces(pos) { - while (pos < end && ts.isWhiteSpace(sourceFile.text.charCodeAt(pos))) { - pos++; - } - return pos; - } - function setPosForParamHelpStringOnNextLine(firstLineParamHelpStringPos) { - // Get the pos after consuming line breaks - pos = consumeLineBreaks(pos, end, sourceFile); - if (pos >= end) { - return; - } - if (paramHelpStringMargin === undefined) { - paramHelpStringMargin = sourceFile.getLineAndCharacterFromPosition(firstLineParamHelpStringPos).character - 1; - } - // Now consume white spaces max - var startOfLinePos = pos; - pos = consumeWhiteSpacesOnTheLine(pos, end, sourceFile, paramHelpStringMargin); - if (pos >= end) { - return; - } - var consumedSpaces = pos - startOfLinePos; - if (consumedSpaces < paramHelpStringMargin) { - var ch = sourceFile.text.charCodeAt(pos); - if (ch === ts.CharacterCodes.asterisk) { - // Consume more spaces after asterisk - pos = consumeWhiteSpacesOnTheLine(pos + 1, end, sourceFile, paramHelpStringMargin - consumedSpaces - 1); - } - } - } - } - } - } - var TypeObject = (function () { - function TypeObject(checker, flags) { - this.checker = checker; - this.flags = flags; - } - TypeObject.prototype.getFlags = function () { - return this.flags; - }; - TypeObject.prototype.getSymbol = function () { - return this.symbol; - }; - TypeObject.prototype.getProperties = function () { - return this.checker.getPropertiesOfType(this); - }; - TypeObject.prototype.getProperty = function (propertyName) { - return this.checker.getPropertyOfType(this, propertyName); - }; - TypeObject.prototype.getApparentProperties = function () { - return this.checker.getAugmentedPropertiesOfType(this); - }; - TypeObject.prototype.getCallSignatures = function () { - return this.checker.getSignaturesOfType(this, ts.SignatureKind.Call); - }; - TypeObject.prototype.getConstructSignatures = function () { - return this.checker.getSignaturesOfType(this, ts.SignatureKind.Construct); - }; - TypeObject.prototype.getStringIndexType = function () { - return this.checker.getIndexTypeOfType(this, ts.IndexKind.String); - }; - TypeObject.prototype.getNumberIndexType = function () { - return this.checker.getIndexTypeOfType(this, ts.IndexKind.Number); - }; - return TypeObject; - })(); - var SignatureObject = (function () { - function SignatureObject(checker) { - this.checker = checker; - } - SignatureObject.prototype.getDeclaration = function () { - return this.declaration; - }; - SignatureObject.prototype.getTypeParameters = function () { - return this.typeParameters; - }; - SignatureObject.prototype.getParameters = function () { - return this.parameters; - }; - SignatureObject.prototype.getReturnType = function () { - return this.checker.getReturnTypeOfSignature(this); - }; - SignatureObject.prototype.getDocumentationComment = function () { - if (this.documentationComment === undefined) { - this.documentationComment = this.declaration ? getJsDocCommentsFromDeclarations([this.declaration], undefined, false) : []; - } - return this.documentationComment; - }; - return SignatureObject; - })(); - var SourceFileObject = (function (_super) { - __extends(SourceFileObject, _super); - function SourceFileObject() { - _super.apply(this, arguments); - } - SourceFileObject.prototype.getNamedDeclarations = function () { - if (!this.namedDeclarations) { - var sourceFile = this; - var namedDeclarations = []; - ts.forEachChild(sourceFile, function visit(node) { - switch (node.kind) { - case ts.SyntaxKind.FunctionDeclaration: - case ts.SyntaxKind.MethodDeclaration: - case ts.SyntaxKind.MethodSignature: - var functionDeclaration = node; - if (functionDeclaration.name && functionDeclaration.name.getFullWidth() > 0) { - var lastDeclaration = namedDeclarations.length > 0 ? namedDeclarations[namedDeclarations.length - 1] : undefined; - // Check whether this declaration belongs to an "overload group". - if (lastDeclaration && functionDeclaration.symbol === lastDeclaration.symbol) { - // Overwrite the last declaration if it was an overload - // and this one is an implementation. - if (functionDeclaration.body && !lastDeclaration.body) { - namedDeclarations[namedDeclarations.length - 1] = functionDeclaration; - } - } - else { - namedDeclarations.push(functionDeclaration); - } - ts.forEachChild(node, visit); - } - break; - case ts.SyntaxKind.ClassDeclaration: - case ts.SyntaxKind.InterfaceDeclaration: - case ts.SyntaxKind.TypeAliasDeclaration: - case ts.SyntaxKind.EnumDeclaration: - case ts.SyntaxKind.ModuleDeclaration: - case ts.SyntaxKind.ImportDeclaration: - case ts.SyntaxKind.GetAccessor: - case ts.SyntaxKind.SetAccessor: - case ts.SyntaxKind.TypeLiteral: - if (node.name) { - namedDeclarations.push(node); - } - case ts.SyntaxKind.Constructor: - case ts.SyntaxKind.VariableStatement: - case ts.SyntaxKind.VariableDeclarationList: - case ts.SyntaxKind.ObjectBindingPattern: - case ts.SyntaxKind.ArrayBindingPattern: - case ts.SyntaxKind.ModuleBlock: - ts.forEachChild(node, visit); - break; - case ts.SyntaxKind.Block: - if (ts.isFunctionBlock(node)) { - ts.forEachChild(node, visit); - } - break; - case ts.SyntaxKind.Parameter: - // Only consider properties defined as constructor parameters - if (!(node.flags & ts.NodeFlags.AccessibilityModifier)) { - break; - } - case ts.SyntaxKind.VariableDeclaration: - case ts.SyntaxKind.BindingElement: - if (ts.isBindingPattern(node.name)) { - ts.forEachChild(node.name, visit); - break; - } - case ts.SyntaxKind.EnumMember: - case ts.SyntaxKind.PropertyDeclaration: - case ts.SyntaxKind.PropertySignature: - namedDeclarations.push(node); - break; - } - }); - this.namedDeclarations = namedDeclarations; - } - return this.namedDeclarations; - }; - return SourceFileObject; - })(NodeObject); - var TextChange = (function () { - function TextChange() { - } - return TextChange; - })(); - ts.TextChange = TextChange; - (function (SymbolDisplayPartKind) { - SymbolDisplayPartKind[SymbolDisplayPartKind["aliasName"] = 0] = "aliasName"; - SymbolDisplayPartKind[SymbolDisplayPartKind["className"] = 1] = "className"; - SymbolDisplayPartKind[SymbolDisplayPartKind["enumName"] = 2] = "enumName"; - SymbolDisplayPartKind[SymbolDisplayPartKind["fieldName"] = 3] = "fieldName"; - SymbolDisplayPartKind[SymbolDisplayPartKind["interfaceName"] = 4] = "interfaceName"; - SymbolDisplayPartKind[SymbolDisplayPartKind["keyword"] = 5] = "keyword"; - SymbolDisplayPartKind[SymbolDisplayPartKind["lineBreak"] = 6] = "lineBreak"; - SymbolDisplayPartKind[SymbolDisplayPartKind["numericLiteral"] = 7] = "numericLiteral"; - SymbolDisplayPartKind[SymbolDisplayPartKind["stringLiteral"] = 8] = "stringLiteral"; - SymbolDisplayPartKind[SymbolDisplayPartKind["localName"] = 9] = "localName"; - SymbolDisplayPartKind[SymbolDisplayPartKind["methodName"] = 10] = "methodName"; - SymbolDisplayPartKind[SymbolDisplayPartKind["moduleName"] = 11] = "moduleName"; - SymbolDisplayPartKind[SymbolDisplayPartKind["operator"] = 12] = "operator"; - SymbolDisplayPartKind[SymbolDisplayPartKind["parameterName"] = 13] = "parameterName"; - SymbolDisplayPartKind[SymbolDisplayPartKind["propertyName"] = 14] = "propertyName"; - SymbolDisplayPartKind[SymbolDisplayPartKind["punctuation"] = 15] = "punctuation"; - SymbolDisplayPartKind[SymbolDisplayPartKind["space"] = 16] = "space"; - SymbolDisplayPartKind[SymbolDisplayPartKind["text"] = 17] = "text"; - SymbolDisplayPartKind[SymbolDisplayPartKind["typeParameterName"] = 18] = "typeParameterName"; - SymbolDisplayPartKind[SymbolDisplayPartKind["enumMemberName"] = 19] = "enumMemberName"; - SymbolDisplayPartKind[SymbolDisplayPartKind["functionName"] = 20] = "functionName"; - SymbolDisplayPartKind[SymbolDisplayPartKind["regularExpressionLiteral"] = 21] = "regularExpressionLiteral"; - })(ts.SymbolDisplayPartKind || (ts.SymbolDisplayPartKind = {})); - var SymbolDisplayPartKind = ts.SymbolDisplayPartKind; - (function (TokenClass) { - TokenClass[TokenClass["Punctuation"] = 0] = "Punctuation"; - TokenClass[TokenClass["Keyword"] = 1] = "Keyword"; - TokenClass[TokenClass["Operator"] = 2] = "Operator"; - TokenClass[TokenClass["Comment"] = 3] = "Comment"; - TokenClass[TokenClass["Whitespace"] = 4] = "Whitespace"; - TokenClass[TokenClass["Identifier"] = 5] = "Identifier"; - TokenClass[TokenClass["NumberLiteral"] = 6] = "NumberLiteral"; - TokenClass[TokenClass["StringLiteral"] = 7] = "StringLiteral"; - TokenClass[TokenClass["RegExpLiteral"] = 8] = "RegExpLiteral"; - })(ts.TokenClass || (ts.TokenClass = {})); - var TokenClass = ts.TokenClass; - // TODO: move these to enums - var ScriptElementKind = (function () { - function ScriptElementKind() { - } - ScriptElementKind.unknown = ""; - // predefined type (void) or keyword (class) - ScriptElementKind.keyword = "keyword"; - // top level script node - ScriptElementKind.scriptElement = "script"; - // module foo {} - ScriptElementKind.moduleElement = "module"; - // class X {} - ScriptElementKind.classElement = "class"; - // interface Y {} - ScriptElementKind.interfaceElement = "interface"; - // type T = ... - ScriptElementKind.typeElement = "type"; - // enum E - ScriptElementKind.enumElement = "enum"; - // Inside module and script only - // var v = .. - ScriptElementKind.variableElement = "var"; - // Inside function - ScriptElementKind.localVariableElement = "local var"; - // Inside module and script only - // function f() { } - ScriptElementKind.functionElement = "function"; - // Inside function - ScriptElementKind.localFunctionElement = "local function"; - // class X { [public|private]* foo() {} } - ScriptElementKind.memberFunctionElement = "method"; - // class X { [public|private]* [get|set] foo:number; } - ScriptElementKind.memberGetAccessorElement = "getter"; - ScriptElementKind.memberSetAccessorElement = "setter"; - // class X { [public|private]* foo:number; } - // interface Y { foo:number; } - ScriptElementKind.memberVariableElement = "property"; - // class X { constructor() { } } - ScriptElementKind.constructorImplementationElement = "constructor"; - // interface Y { ():number; } - ScriptElementKind.callSignatureElement = "call"; - // interface Y { []:number; } - ScriptElementKind.indexSignatureElement = "index"; - // interface Y { new():Y; } - ScriptElementKind.constructSignatureElement = "construct"; - // function foo(*Y*: string) - ScriptElementKind.parameterElement = "parameter"; - ScriptElementKind.typeParameterElement = "type parameter"; - ScriptElementKind.primitiveType = "primitive type"; - ScriptElementKind.label = "label"; - ScriptElementKind.alias = "alias"; - ScriptElementKind.constElement = "const"; - ScriptElementKind.letElement = "let"; - return ScriptElementKind; - })(); - ts.ScriptElementKind = ScriptElementKind; - var ScriptElementKindModifier = (function () { - function ScriptElementKindModifier() { - } - ScriptElementKindModifier.none = ""; - ScriptElementKindModifier.publicMemberModifier = "public"; - ScriptElementKindModifier.privateMemberModifier = "private"; - ScriptElementKindModifier.protectedMemberModifier = "protected"; - ScriptElementKindModifier.exportedModifier = "export"; - ScriptElementKindModifier.ambientModifier = "declare"; - ScriptElementKindModifier.staticModifier = "static"; - return ScriptElementKindModifier; - })(); - ts.ScriptElementKindModifier = ScriptElementKindModifier; - var ClassificationTypeNames = (function () { - function ClassificationTypeNames() { - } - ClassificationTypeNames.comment = "comment"; - ClassificationTypeNames.identifier = "identifier"; - ClassificationTypeNames.keyword = "keyword"; - ClassificationTypeNames.numericLiteral = "number"; - ClassificationTypeNames.operator = "operator"; - ClassificationTypeNames.stringLiteral = "string"; - ClassificationTypeNames.whiteSpace = "whitespace"; - ClassificationTypeNames.text = "text"; - ClassificationTypeNames.punctuation = "punctuation"; - ClassificationTypeNames.className = "class name"; - ClassificationTypeNames.enumName = "enum name"; - ClassificationTypeNames.interfaceName = "interface name"; - ClassificationTypeNames.moduleName = "module name"; - ClassificationTypeNames.typeParameterName = "type parameter name"; - ClassificationTypeNames.typeAlias = "type alias name"; - return ClassificationTypeNames; - })(); - ts.ClassificationTypeNames = ClassificationTypeNames; - var MatchKind; - (function (MatchKind) { - MatchKind[MatchKind["none"] = 0] = "none"; - MatchKind[MatchKind["exact"] = 1] = "exact"; - MatchKind[MatchKind["substring"] = 2] = "substring"; - MatchKind[MatchKind["prefix"] = 3] = "prefix"; - })(MatchKind || (MatchKind = {})); - function displayPartsToString(displayParts) { - if (displayParts) { - return ts.map(displayParts, function (displayPart) { return displayPart.text; }).join(""); - } - return ""; - } - ts.displayPartsToString = displayPartsToString; - function isLocalVariableOrFunction(symbol) { - if (symbol.parent) { - return false; // This is exported symbol - } - return ts.forEach(symbol.declarations, function (declaration) { - // Function expressions are local - if (declaration.kind === ts.SyntaxKind.FunctionExpression) { - return true; - } - if (declaration.kind !== ts.SyntaxKind.VariableDeclaration && declaration.kind !== ts.SyntaxKind.FunctionDeclaration) { - return false; - } - for (var parent = declaration.parent; !ts.isFunctionBlock(parent); parent = parent.parent) { - // Reached source file or module block - if (parent.kind === ts.SyntaxKind.SourceFile || parent.kind === ts.SyntaxKind.ModuleBlock) { - return false; - } - } - // parent is in function block - return true; - }); - } - function getDefaultCompilerOptions() { - // Set "ScriptTarget.Latest" target by default for language service - return { - target: ts.ScriptTarget.Latest, - module: ts.ModuleKind.None, - }; - } - ts.getDefaultCompilerOptions = getDefaultCompilerOptions; - var OperationCanceledException = (function () { - function OperationCanceledException() { - } - return OperationCanceledException; - })(); - ts.OperationCanceledException = OperationCanceledException; - var CancellationTokenObject = (function () { - function CancellationTokenObject(cancellationToken) { - this.cancellationToken = cancellationToken; - } - CancellationTokenObject.prototype.isCancellationRequested = function () { - return this.cancellationToken && this.cancellationToken.isCancellationRequested(); - }; - CancellationTokenObject.prototype.throwIfCancellationRequested = function () { - if (this.isCancellationRequested()) { - throw new OperationCanceledException(); - } - }; - CancellationTokenObject.None = new CancellationTokenObject(null); - return CancellationTokenObject; - })(); - ts.CancellationTokenObject = CancellationTokenObject; - // Cache host information about scrip Should be refreshed - // at each language service public entry point, since we don't know when - // set of scripts handled by the host changes. - var HostCache = (function () { - function HostCache(host) { - this.host = host; - // script id => script index - this.filenameToEntry = {}; - var filenames = host.getScriptFileNames(); - for (var i = 0, n = filenames.length; i < n; i++) { - var filename = filenames[i]; - this.filenameToEntry[ts.normalizeSlashes(filename)] = { - filename: filename, - version: host.getScriptVersion(filename) - }; - } - this._compilationSettings = host.getCompilationSettings() || getDefaultCompilerOptions(); - } - HostCache.prototype.compilationSettings = function () { - return this._compilationSettings; - }; - HostCache.prototype.getEntry = function (filename) { - filename = ts.normalizeSlashes(filename); - return ts.lookUp(this.filenameToEntry, filename); - }; - HostCache.prototype.contains = function (filename) { - return !!this.getEntry(filename); - }; - HostCache.prototype.getHostfilename = function (filename) { - var hostCacheEntry = this.getEntry(filename); - if (hostCacheEntry) { - return hostCacheEntry.filename; - } - return filename; - }; - HostCache.prototype.getFilenames = function () { - var _this = this; - var fileNames = []; - ts.forEachKey(this.filenameToEntry, function (key) { - if (ts.hasProperty(_this.filenameToEntry, key)) - fileNames.push(key); - }); - return fileNames; - }; - HostCache.prototype.getVersion = function (filename) { - return this.getEntry(filename).version; - }; - HostCache.prototype.getScriptSnapshot = function (filename) { - var file = this.getEntry(filename); - if (!file.sourceText) { - file.sourceText = this.host.getScriptSnapshot(file.filename); - } - return file.sourceText; - }; - HostCache.prototype.getChangeRange = function (filename, lastKnownVersion, oldScriptSnapshot) { - var currentVersion = this.getVersion(filename); - if (lastKnownVersion === currentVersion) { - return ts.unchangedTextChangeRange; // "No changes" - } - var scriptSnapshot = this.getScriptSnapshot(filename); - return scriptSnapshot.getChangeRange(oldScriptSnapshot); - }; - return HostCache; - })(); - var SyntaxTreeCache = (function () { - function SyntaxTreeCache(host) { - this.host = host; - // For our syntactic only features, we also keep a cache of the syntax tree for the - // currently edited file. - this.currentFilename = ""; - this.currentFileVersion = null; - this.currentSourceFile = null; - } - SyntaxTreeCache.prototype.log = function (message) { - if (this.host.log) { - this.host.log(message); - } - }; - SyntaxTreeCache.prototype.initialize = function (filename) { - // ensure that both source file and syntax tree are either initialized or not initialized - var start = new Date().getTime(); - this.hostCache = new HostCache(this.host); - this.log("SyntaxTreeCache.Initialize: new HostCache: " + (new Date().getTime() - start)); - var version = this.hostCache.getVersion(filename); - var sourceFile; - if (this.currentFilename !== filename) { - var scriptSnapshot = this.hostCache.getScriptSnapshot(filename); - var start = new Date().getTime(); - sourceFile = createLanguageServiceSourceFile(filename, scriptSnapshot, ts.ScriptTarget.Latest, version, true); - this.log("SyntaxTreeCache.Initialize: createSourceFile: " + (new Date().getTime() - start)); - } - else if (this.currentFileVersion !== version) { - var scriptSnapshot = this.hostCache.getScriptSnapshot(filename); - var editRange = this.hostCache.getChangeRange(filename, this.currentFileVersion, this.currentSourceFile.scriptSnapshot); - var start = new Date().getTime(); - sourceFile = updateLanguageServiceSourceFile(this.currentSourceFile, scriptSnapshot, version, editRange); - this.log("SyntaxTreeCache.Initialize: updateSourceFile: " + (new Date().getTime() - start)); - } - if (sourceFile) { - // All done, ensure state is up to date - this.currentFileVersion = version; - this.currentFilename = filename; - this.currentSourceFile = sourceFile; - } - }; - SyntaxTreeCache.prototype.getCurrentSourceFile = function (filename) { - this.initialize(filename); - return this.currentSourceFile; - }; - SyntaxTreeCache.prototype.getCurrentScriptSnapshot = function (filename) { - return this.getCurrentSourceFile(filename).scriptSnapshot; - }; - return SyntaxTreeCache; - })(); - function setSourceFileFields(sourceFile, scriptSnapshot, version) { - sourceFile.version = version; - sourceFile.scriptSnapshot = scriptSnapshot; - } - function createLanguageServiceSourceFile(filename, scriptSnapshot, scriptTarget, version, setNodeParents) { - var sourceFile = ts.createSourceFile(filename, scriptSnapshot.getText(0, scriptSnapshot.getLength()), scriptTarget, setNodeParents); - setSourceFileFields(sourceFile, scriptSnapshot, version); - return sourceFile; - } - ts.createLanguageServiceSourceFile = createLanguageServiceSourceFile; - ts.disableIncrementalParsing = false; - function updateLanguageServiceSourceFile(sourceFile, scriptSnapshot, version, textChangeRange) { - if (textChangeRange && ts.Debug.shouldAssert(ts.AssertionLevel.Normal)) { - var oldText = sourceFile.scriptSnapshot; - var newText = scriptSnapshot; - ts.Debug.assert((oldText.getLength() - textChangeRange.span.length + textChangeRange.newLength) === newText.getLength()); - if (ts.Debug.shouldAssert(ts.AssertionLevel.VeryAggressive)) { - var oldTextPrefix = oldText.getText(0, textChangeRange.span.start); - var newTextPrefix = newText.getText(0, textChangeRange.span.start); - ts.Debug.assert(oldTextPrefix === newTextPrefix); - var oldTextSuffix = oldText.getText(ts.textSpanEnd(textChangeRange.span), oldText.getLength()); - var newTextSuffix = newText.getText(ts.textSpanEnd(ts.textChangeRangeNewSpan(textChangeRange)), newText.getLength()); - ts.Debug.assert(oldTextSuffix === newTextSuffix); - } - } - // If we were given a text change range, and our version or open-ness changed, then - // incrementally parse this file. - if (textChangeRange) { - if (version !== sourceFile.version) { - // Once incremental parsing is ready, then just call into this function. - if (!ts.disableIncrementalParsing) { - var newSourceFile = sourceFile.update(scriptSnapshot.getText(0, scriptSnapshot.getLength()), textChangeRange); - setSourceFileFields(newSourceFile, scriptSnapshot, version); - return newSourceFile; - } - } - } - // Otherwise, just create a new source file. - return createLanguageServiceSourceFile(sourceFile.filename, scriptSnapshot, sourceFile.languageVersion, version, true); - } - ts.updateLanguageServiceSourceFile = updateLanguageServiceSourceFile; - function createDocumentRegistry() { - var buckets = {}; - function getKeyFromCompilationSettings(settings) { - return "_" + settings.target; // + "|" + settings.propagateEnumConstantoString() - } - function getBucketForCompilationSettings(settings, createIfMissing) { - var key = getKeyFromCompilationSettings(settings); - var bucket = ts.lookUp(buckets, key); - if (!bucket && createIfMissing) { - buckets[key] = bucket = {}; - } - return bucket; - } - function reportStats() { - var bucketInfoArray = Object.keys(buckets).filter(function (name) { return name && name.charAt(0) === '_'; }).map(function (name) { - var entries = ts.lookUp(buckets, name); - var sourceFiles = []; - for (var i in entries) { - var entry = entries[i]; - sourceFiles.push({ - name: i, - refCount: entry.refCount, - references: entry.owners.slice(0) - }); - } - sourceFiles.sort(function (x, y) { return y.refCount - x.refCount; }); - return { - bucket: name, - sourceFiles - }; - }); - return JSON.stringify(bucketInfoArray, null, 2); - } - function acquireDocument(filename, compilationSettings, scriptSnapshot, version) { - var bucket = getBucketForCompilationSettings(compilationSettings, true); - var entry = ts.lookUp(bucket, filename); - if (!entry) { - var sourceFile = createLanguageServiceSourceFile(filename, scriptSnapshot, compilationSettings.target, version, false); - bucket[filename] = entry = { - sourceFile: sourceFile, - refCount: 0, - owners: [] - }; - } - entry.refCount++; - return entry.sourceFile; - } - function updateDocument(sourceFile, filename, compilationSettings, scriptSnapshot, version, textChangeRange) { - var bucket = getBucketForCompilationSettings(compilationSettings, false); - ts.Debug.assert(bucket !== undefined); - var entry = ts.lookUp(bucket, filename); - ts.Debug.assert(entry !== undefined); - entry.sourceFile = updateLanguageServiceSourceFile(entry.sourceFile, scriptSnapshot, version, textChangeRange); - return entry.sourceFile; - } - function releaseDocument(filename, compilationSettings) { - var bucket = getBucketForCompilationSettings(compilationSettings, false); - ts.Debug.assert(bucket !== undefined); - var entry = ts.lookUp(bucket, filename); - entry.refCount--; - ts.Debug.assert(entry.refCount >= 0); - if (entry.refCount === 0) { - delete bucket[filename]; - } - } - return { - acquireDocument, - updateDocument, - releaseDocument, - reportStats - }; - } - ts.createDocumentRegistry = createDocumentRegistry; - function preProcessFile(sourceText, readImportFiles = true) { - var referencedFiles = []; - var importedFiles = []; - var isNoDefaultLib = false; - function processTripleSlashDirectives() { - var commentRanges = ts.getLeadingCommentRanges(sourceText, 0); - ts.forEach(commentRanges, function (commentRange) { - var comment = sourceText.substring(commentRange.pos, commentRange.end); - var referencePathMatchResult = ts.getFileReferenceFromReferencePath(comment, commentRange); - if (referencePathMatchResult) { - isNoDefaultLib = referencePathMatchResult.isNoDefaultLib; - var fileReference = referencePathMatchResult.fileReference; - if (fileReference) { - referencedFiles.push(fileReference); - } - } - }); - } - function processImport() { - scanner.setText(sourceText); - var token = scanner.scan(); - while (token !== ts.SyntaxKind.EndOfFileToken) { - if (token === ts.SyntaxKind.ImportKeyword) { - token = scanner.scan(); - if (token === ts.SyntaxKind.Identifier) { - token = scanner.scan(); - if (token === ts.SyntaxKind.EqualsToken) { - token = scanner.scan(); - if (token === ts.SyntaxKind.RequireKeyword) { - token = scanner.scan(); - if (token === ts.SyntaxKind.OpenParenToken) { - token = scanner.scan(); - if (token === ts.SyntaxKind.StringLiteral) { - var importPath = scanner.getTokenValue(); - var pos = scanner.getTokenPos(); - importedFiles.push({ - filename: importPath, - pos: pos, - end: pos + importPath.length - }); - } - } - } - } - } - } - token = scanner.scan(); - } - scanner.setText(undefined); - } - if (readImportFiles) { - processImport(); - } - processTripleSlashDirectives(); - return { referencedFiles, importedFiles, isLibFile: isNoDefaultLib }; - } - ts.preProcessFile = preProcessFile; - /// Helpers - function getTargetLabel(referenceNode, labelName) { - while (referenceNode) { - if (referenceNode.kind === ts.SyntaxKind.LabeledStatement && referenceNode.label.text === labelName) { - return referenceNode.label; - } - referenceNode = referenceNode.parent; - } - return undefined; - } - function isJumpStatementTarget(node) { - return node.kind === ts.SyntaxKind.Identifier && (node.parent.kind === ts.SyntaxKind.BreakStatement || node.parent.kind === ts.SyntaxKind.ContinueStatement) && node.parent.label === node; - } - function isLabelOfLabeledStatement(node) { - return node.kind === ts.SyntaxKind.Identifier && node.parent.kind === ts.SyntaxKind.LabeledStatement && node.parent.label === node; - } - /** - * Whether or not a 'node' is preceded by a label of the given string. - * Note: 'node' cannot be a SourceFile. - */ - function isLabeledBy(node, labelName) { - for (var owner = node.parent; owner.kind === ts.SyntaxKind.LabeledStatement; owner = owner.parent) { - if (owner.label.text === labelName) { - return true; - } - } - return false; - } - function isLabelName(node) { - return isLabelOfLabeledStatement(node) || isJumpStatementTarget(node); - } - function isRightSideOfQualifiedName(node) { - return node.parent.kind === ts.SyntaxKind.QualifiedName && node.parent.right === node; - } - function isRightSideOfPropertyAccess(node) { - return node && node.parent && node.parent.kind === ts.SyntaxKind.PropertyAccessExpression && node.parent.name === node; - } - function isCallExpressionTarget(node) { - if (isRightSideOfPropertyAccess(node)) { - node = node.parent; - } - return node && node.parent && node.parent.kind === ts.SyntaxKind.CallExpression && node.parent.expression === node; - } - function isNewExpressionTarget(node) { - if (isRightSideOfPropertyAccess(node)) { - node = node.parent; - } - return node && node.parent && node.parent.kind === ts.SyntaxKind.NewExpression && node.parent.expression === node; - } - function isNameOfModuleDeclaration(node) { - return node.parent.kind === ts.SyntaxKind.ModuleDeclaration && node.parent.name === node; - } - function isNameOfFunctionDeclaration(node) { - return node.kind === ts.SyntaxKind.Identifier && ts.isAnyFunction(node.parent) && node.parent.name === node; - } - /** Returns true if node is a name of an object literal property, e.g. "a" in x = { "a": 1 } */ - function isNameOfPropertyAssignment(node) { - return (node.kind === ts.SyntaxKind.Identifier || node.kind === ts.SyntaxKind.StringLiteral || node.kind === ts.SyntaxKind.NumericLiteral) && (node.parent.kind === ts.SyntaxKind.PropertyAssignment || node.parent.kind === ts.SyntaxKind.ShorthandPropertyAssignment) && node.parent.name === node; - } - function isLiteralNameOfPropertyDeclarationOrIndexAccess(node) { - if (node.kind === ts.SyntaxKind.StringLiteral || node.kind === ts.SyntaxKind.NumericLiteral) { - switch (node.parent.kind) { - case ts.SyntaxKind.PropertyDeclaration: - case ts.SyntaxKind.PropertySignature: - case ts.SyntaxKind.PropertyAssignment: - case ts.SyntaxKind.EnumMember: - case ts.SyntaxKind.MethodDeclaration: - case ts.SyntaxKind.MethodSignature: - case ts.SyntaxKind.GetAccessor: - case ts.SyntaxKind.SetAccessor: - case ts.SyntaxKind.ModuleDeclaration: - return node.parent.name === node; - case ts.SyntaxKind.ElementAccessExpression: - return node.parent.argumentExpression === node; - } - } - return false; - } - function isNameOfExternalModuleImportOrDeclaration(node) { - if (node.kind === ts.SyntaxKind.StringLiteral) { - return isNameOfModuleDeclaration(node) || (ts.isExternalModuleImportDeclaration(node.parent.parent) && ts.getExternalModuleImportDeclarationExpression(node.parent.parent) === node); - } - return false; - } - /** Returns true if the position is within a comment */ - function isInsideComment(sourceFile, token, position) { - // The position has to be: 1. in the leading trivia (before token.getStart()), and 2. within a comment - return position <= token.getStart(sourceFile) && (isInsideCommentRange(ts.getTrailingCommentRanges(sourceFile.text, token.getFullStart())) || isInsideCommentRange(ts.getLeadingCommentRanges(sourceFile.text, token.getFullStart()))); - function isInsideCommentRange(comments) { - return ts.forEach(comments, function (comment) { - // either we are 1. completely inside the comment, or 2. at the end of the comment - if (comment.pos < position && position < comment.end) { - return true; - } - else if (position === comment.end) { - var text = sourceFile.text; - var width = comment.end - comment.pos; - // is single line comment or just /* - if (width <= 2 || text.charCodeAt(comment.pos + 1) === ts.CharacterCodes.slash) { - return true; - } - else { - // is unterminated multi-line comment - return !(text.charCodeAt(comment.end - 1) === ts.CharacterCodes.slash && text.charCodeAt(comment.end - 2) === ts.CharacterCodes.asterisk); - } - } - return false; - }); - } - } - // A cache of completion entries for keywords, these do not change between sessions - var keywordCompletions = []; - for (var i = ts.SyntaxKind.FirstKeyword; i <= ts.SyntaxKind.LastKeyword; i++) { - keywordCompletions.push({ - name: ts.tokenToString(i), - kind: ScriptElementKind.keyword, - kindModifiers: ScriptElementKindModifier.none - }); - } - function createLanguageService(host, documentRegistry) { - var syntaxTreeCache = new SyntaxTreeCache(host); - var ruleProvider; - var hostCache; // A cache of all the information about the files on the host side. - var program; - // this checker is used to answer all LS questions except errors - var typeInfoResolver; - var useCaseSensitivefilenames = false; - var sourceFilesByName = {}; - var documentRegistry = documentRegistry; - var cancellationToken = new CancellationTokenObject(host.getCancellationToken && host.getCancellationToken()); - var activeCompletionSession; // The current active completion session, used to get the completion entry details - // Check if the localized messages json is set, otherwise query the host for it - if (!ts.localizedDiagnosticMessages && host.getLocalizedDiagnosticMessages) { - ts.localizedDiagnosticMessages = host.getLocalizedDiagnosticMessages(); - } - function log(message) { - if (host.log) { - host.log(message); - } - } - function getCanonicalFileName(filename) { - return useCaseSensitivefilenames ? filename : filename.toLowerCase(); - } - function getSourceFile(filename) { - return ts.lookUp(sourceFilesByName, getCanonicalFileName(filename)); - } - function getDiagnosticsProducingTypeChecker() { - return program.getTypeChecker(true); - } - function getRuleProvider(options) { - // Ensure rules are initialized and up to date wrt to formatting options - if (!ruleProvider) { - ruleProvider = new ts.formatting.RulesProvider(); - } - ruleProvider.ensureUpToDate(options); - return ruleProvider; - } - function sourceFileUpToDate(sourceFile) { - return sourceFile && sourceFile.version === hostCache.getVersion(sourceFile.filename); - } - function programUpToDate() { - // If we haven't create a program yet, then it is not up-to-date - if (!program) { - return false; - } - // If number of files in the program do not match, it is not up-to-date - var hostFilenames = hostCache.getFilenames(); - if (program.getSourceFiles().length !== hostFilenames.length) { - return false; - } - for (var i = 0, n = hostFilenames.length; i < n; i++) { - if (!sourceFileUpToDate(program.getSourceFile(hostFilenames[i]))) { - return false; - } - } - // If the compilation settings do no match, then the program is not up-to-date - return ts.compareDataObjects(program.getCompilerOptions(), hostCache.compilationSettings()); - } - function synchronizeHostData() { - // Reset the cache at start of every refresh - hostCache = new HostCache(host); - // If the program is already up-to-date, we can reuse it - if (programUpToDate()) { - return; - } - var compilationSettings = hostCache.compilationSettings(); - // Now, remove any files from the compiler that are no longer in the host. - var oldProgram = program; - if (oldProgram) { - var oldSettings = program.getCompilerOptions(); - // If the language version changed, then that affects what types of things we parse. So - // we have to dump all syntax trees. - // TODO: handle propagateEnumConstants - // TODO: is module still needed - var settingsChangeAffectsSyntax = oldSettings.target !== compilationSettings.target || oldSettings.module !== compilationSettings.module; - var changesInCompilationSettingsAffectSyntax = oldSettings && compilationSettings && !ts.compareDataObjects(oldSettings, compilationSettings) && settingsChangeAffectsSyntax; - var oldSourceFiles = program.getSourceFiles(); - for (var i = 0, n = oldSourceFiles.length; i < n; i++) { - cancellationToken.throwIfCancellationRequested(); - var filename = oldSourceFiles[i].filename; - if (!hostCache.contains(filename) || changesInCompilationSettingsAffectSyntax) { - documentRegistry.releaseDocument(filename, oldSettings); - delete sourceFilesByName[getCanonicalFileName(filename)]; - } - } - } - // Now, for every file the host knows about, either add the file (if the compiler - // doesn't know about it.). Or notify the compiler about any changes (if it does - // know about it.) - var hostfilenames = hostCache.getFilenames(); - for (var i = 0, n = hostfilenames.length; i < n; i++) { - var filename = hostfilenames[i]; - var version = hostCache.getVersion(filename); - var scriptSnapshot = hostCache.getScriptSnapshot(filename); - var sourceFile = getSourceFile(filename); - if (sourceFile) { - // - // If the sourceFile is the same, assume no update - // - if (sourceFileUpToDate(sourceFile)) { - continue; - } - var textChangeRange = null; - textChangeRange = hostCache.getChangeRange(filename, sourceFile.version, sourceFile.scriptSnapshot); - sourceFile = documentRegistry.updateDocument(sourceFile, filename, compilationSettings, scriptSnapshot, version, textChangeRange); - } - else { - sourceFile = documentRegistry.acquireDocument(filename, compilationSettings, scriptSnapshot, version); - } - // Remember the new sourceFile - sourceFilesByName[getCanonicalFileName(filename)] = sourceFile; - } - // Now create a new compiler - program = ts.createProgram(hostfilenames, compilationSettings, { - getSourceFile: getSourceFile, - getCancellationToken: function () { return cancellationToken; }, - getCanonicalFileName: function (filename) { return useCaseSensitivefilenames ? filename : filename.toLowerCase(); }, - useCaseSensitiveFileNames: function () { return useCaseSensitivefilenames; }, - getNewLine: function () { return host.getNewLine ? host.getNewLine() : "\r\n"; }, - getDefaultLibFilename: ts.getDefaultLibraryFilename, - writeFile: function (filename, data, writeByteOrderMark) { - }, - getCurrentDirectory: function () { return host.getCurrentDirectory(); } - }); - typeInfoResolver = program.getTypeChecker(false); - } - /** - * Clean up any semantic caches that are not needed. - * The host can call this method if it wants to jettison unused memory. - * We will just dump the typeChecker and recreate a new one. this should have the effect of destroying all the semantic caches. - */ - function cleanupSemanticCache() { - if (program) { - typeInfoResolver = program.getTypeChecker(false); - } - } - function dispose() { - if (program) { - ts.forEach(program.getSourceFiles(), function (f) { - documentRegistry.releaseDocument(f.filename, program.getCompilerOptions()); - }); - } - } - /// Diagnostics - function getSyntacticDiagnostics(filename) { - synchronizeHostData(); - filename = ts.normalizeSlashes(filename); - return program.getDiagnostics(getSourceFile(filename)); - } - /** - * getSemanticDiagnostiscs return array of Diagnostics. If '-d' is not enabled, only report semantic errors - * If '-d' enabled, report both semantic and emitter errors - */ - function getSemanticDiagnostics(filename) { - synchronizeHostData(); - filename = ts.normalizeSlashes(filename); - var compilerOptions = program.getCompilerOptions(); - var checker = getDiagnosticsProducingTypeChecker(); - var targetSourceFile = getSourceFile(filename); - // Only perform the action per file regardless of '-out' flag as LanguageServiceHost is expected to call this function per file. - // Therefore only get diagnostics for given file. - var allDiagnostics = checker.getDiagnostics(targetSourceFile); - if (compilerOptions.declaration) { - // If '-d' is enabled, check for emitter error. One example of emitter error is export class implements non-export interface - allDiagnostics = allDiagnostics.concat(program.getDeclarationDiagnostics(targetSourceFile)); - } - return allDiagnostics; - } - function getCompilerOptionsDiagnostics() { - synchronizeHostData(); - return program.getGlobalDiagnostics(); - } - /// Completion - function getValidCompletionEntryDisplayName(symbol, target) { - var displayName = symbol.getName(); - if (displayName && displayName.length > 0) { - var firstCharCode = displayName.charCodeAt(0); - // First check of the displayName is not external module; if it is an external module, it is not valid entry - if ((symbol.flags & ts.SymbolFlags.Namespace) && (firstCharCode === ts.CharacterCodes.singleQuote || firstCharCode === ts.CharacterCodes.doubleQuote)) { - // If the symbol is external module, don't show it in the completion list - // (i.e declare module "http" { var x; } | // <= request completion here, "http" should not be there) - return undefined; - } - if (displayName && displayName.length >= 2 && firstCharCode === displayName.charCodeAt(displayName.length - 1) && (firstCharCode === ts.CharacterCodes.singleQuote || firstCharCode === ts.CharacterCodes.doubleQuote)) { - // If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an - // invalid identifier name. We need to check if whatever was inside the quotes is actually a valid identifier name. - displayName = displayName.substring(1, displayName.length - 1); - } - var isValid = ts.isIdentifierStart(displayName.charCodeAt(0), target); - for (var i = 1, n = displayName.length; isValid && i < n; i++) { - isValid = ts.isIdentifierPart(displayName.charCodeAt(i), target); - } - if (isValid) { - return ts.unescapeIdentifier(displayName); - } - } - return undefined; - } - function createCompletionEntry(symbol, typeChecker, location) { - // 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 = getValidCompletionEntryDisplayName(symbol, program.getCompilerOptions().target); - if (!displayName) { - return undefined; - } - // TODO(drosen): Right now we just permit *all* semantic meanings when calling 'getSymbolKind' - // which is permissible given that it is backwards compatible; but really we should consider - // passing the meaning for the node so that we don't report that a suggestion for a value is an interface. - // We COULD also just do what 'getSymbolModifiers' does, which is to use the first declaration. - return { - name: displayName, - kind: getSymbolKind(symbol, typeChecker, location), - kindModifiers: getSymbolModifiers(symbol) - }; - } - function getCompletionsAtPosition(filename, position) { - synchronizeHostData(); - filename = ts.normalizeSlashes(filename); - var syntacticStart = new Date().getTime(); - var sourceFile = getSourceFile(filename); - var start = new Date().getTime(); - var currentToken = ts.getTokenAtPosition(sourceFile, position); - log("getCompletionsAtPosition: Get current token: " + (new Date().getTime() - start)); - var start = new Date().getTime(); - // Completion not allowed inside comments, bail out if this is the case - var insideComment = isInsideComment(sourceFile, currentToken, position); - log("getCompletionsAtPosition: Is inside comment: " + (new Date().getTime() - start)); - if (insideComment) { - log("Returning an empty list because completion was inside a comment."); - return undefined; - } - // The decision to provide completion depends on the previous token, so find it - // Note: previousToken can be undefined if we are the beginning of the file - var start = new Date().getTime(); - var previousToken = ts.findPrecedingToken(position, sourceFile); - log("getCompletionsAtPosition: Get previous token 1: " + (new Date().getTime() - start)); - // The caret is at the end of an identifier; this is a partial identifier that we want to complete: e.g. a.toS| - // Skip this partial identifier to the previous token - if (previousToken && position <= previousToken.end && previousToken.kind === ts.SyntaxKind.Identifier) { - var start = new Date().getTime(); - previousToken = ts.findPrecedingToken(previousToken.pos, sourceFile); - log("getCompletionsAtPosition: Get previous token 2: " + (new Date().getTime() - start)); - } - // Check if this is a valid completion location - if (previousToken && isCompletionListBlocker(previousToken)) { - log("Returning an empty list because completion was requested in an invalid position."); - return undefined; - } - // Find the node where completion is requested on, in the case of a completion after a dot, it is the member access expression - // other wise, it is a request for all visible symbols in the scope, and the node is the current location - var node; - var isRightOfDot; - if (previousToken && previousToken.kind === ts.SyntaxKind.DotToken && previousToken.parent.kind === ts.SyntaxKind.PropertyAccessExpression) { - node = previousToken.parent.expression; - isRightOfDot = true; - } - else if (previousToken && previousToken.kind === ts.SyntaxKind.DotToken && previousToken.parent.kind === ts.SyntaxKind.QualifiedName) { - node = previousToken.parent.left; - isRightOfDot = true; - } - else { - node = currentToken; - isRightOfDot = false; - } - // Clear the current activeCompletionSession for this session - activeCompletionSession = { - filename: filename, - position: position, - entries: [], - symbols: {}, - typeChecker: typeInfoResolver - }; - log("getCompletionsAtPosition: Syntactic work: " + (new Date().getTime() - syntacticStart)); - var location = ts.getTouchingPropertyName(sourceFile, position); - // Populate the completion list - var semanticStart = new Date().getTime(); - if (isRightOfDot) { - // Right of dot member completion list - var symbols = []; - var isMemberCompletion = true; - if (node.kind === ts.SyntaxKind.Identifier || node.kind === ts.SyntaxKind.QualifiedName || node.kind === ts.SyntaxKind.PropertyAccessExpression) { - var symbol = typeInfoResolver.getSymbolAtLocation(node); - // This is an alias, follow what it aliases - if (symbol && symbol.flags & ts.SymbolFlags.Import) { - symbol = typeInfoResolver.getAliasedSymbol(symbol); - } - if (symbol && symbol.flags & ts.SymbolFlags.HasExports) { - // Extract module or enum members - ts.forEachValue(symbol.exports, function (symbol) { - if (typeInfoResolver.isValidPropertyAccess((node.parent), symbol.name)) { - symbols.push(symbol); - } - }); - } - } - var type = typeInfoResolver.getTypeAtLocation(node); - if (type) { - // Filter private properties - ts.forEach(type.getApparentProperties(), function (symbol) { - if (typeInfoResolver.isValidPropertyAccess((node.parent), symbol.name)) { - symbols.push(symbol); - } - }); - } - getCompletionEntriesFromSymbols(symbols, activeCompletionSession); - } - else { - var containingObjectLiteral = getContainingObjectLiteralApplicableForCompletion(previousToken); - if (containingObjectLiteral) { - // Object literal expression, look up possible property names from contextual type - isMemberCompletion = true; - var contextualType = typeInfoResolver.getContextualType(containingObjectLiteral); - if (!contextualType) { - return undefined; - } - var contextualTypeMembers = typeInfoResolver.getPropertiesOfType(contextualType); - if (contextualTypeMembers && contextualTypeMembers.length > 0) { - // Add filtered items to the completion list - var filteredMembers = filterContextualMembersList(contextualTypeMembers, containingObjectLiteral.properties); - getCompletionEntriesFromSymbols(filteredMembers, activeCompletionSession); - } - } - else { - // Get scope members - isMemberCompletion = false; - /// TODO filter meaning based on the current context - var symbolMeanings = ts.SymbolFlags.Type | ts.SymbolFlags.Value | ts.SymbolFlags.Namespace | ts.SymbolFlags.Import; - var symbols = typeInfoResolver.getSymbolsInScope(node, symbolMeanings); - getCompletionEntriesFromSymbols(symbols, activeCompletionSession); - } - } - // Add keywords if this is not a member completion list - if (!isMemberCompletion) { - Array.prototype.push.apply(activeCompletionSession.entries, keywordCompletions); - } - log("getCompletionsAtPosition: Semantic work: " + (new Date().getTime() - semanticStart)); - return { - isMemberCompletion, - entries: activeCompletionSession.entries - }; - function getCompletionEntriesFromSymbols(symbols, session) { - var start = new Date().getTime(); - ts.forEach(symbols, function (symbol) { - var entry = createCompletionEntry(symbol, session.typeChecker, location); - if (entry) { - var id = ts.escapeIdentifier(entry.name); - if (!ts.lookUp(session.symbols, id)) { - session.entries.push(entry); - session.symbols[id] = symbol; - } - } - }); - log("getCompletionsAtPosition: getCompletionEntriesFromSymbols: " + (new Date().getTime() - start)); - } - function isCompletionListBlocker(previousToken) { - var start = new Date().getTime(); - var result = isInStringOrRegularExpressionOrTemplateLiteral(previousToken) || isIdentifierDefinitionLocation(previousToken) || isRightOfIllegalDot(previousToken); - log("getCompletionsAtPosition: isCompletionListBlocker: " + (new Date().getTime() - start)); - return result; - } - function isInStringOrRegularExpressionOrTemplateLiteral(previousToken) { - if (previousToken.kind === ts.SyntaxKind.StringLiteral || previousToken.kind === ts.SyntaxKind.RegularExpressionLiteral || ts.isTemplateLiteralKind(previousToken.kind)) { - // The position has to be either: 1. entirely within the token text, or - // 2. at the end position of an unterminated token. - var start = previousToken.getStart(); - var end = previousToken.getEnd(); - if (start < position && position < end) { - return true; - } - else if (position === end) { - return !!previousToken.isUnterminated; - } - } - return false; - } - function getContainingObjectLiteralApplicableForCompletion(previousToken) { - // The locations in an object literal expression that are applicable for completion are property name definition locations. - if (previousToken) { - var parent = previousToken.parent; - switch (previousToken.kind) { - case ts.SyntaxKind.OpenBraceToken: - case ts.SyntaxKind.CommaToken: - if (parent && parent.kind === ts.SyntaxKind.ObjectLiteralExpression) { - return parent; - } - break; - } - } - return undefined; - } - function isFunction(kind) { - switch (kind) { - case ts.SyntaxKind.FunctionExpression: - case ts.SyntaxKind.ArrowFunction: - case ts.SyntaxKind.FunctionDeclaration: - case ts.SyntaxKind.MethodDeclaration: - case ts.SyntaxKind.MethodSignature: - case ts.SyntaxKind.Constructor: - case ts.SyntaxKind.GetAccessor: - case ts.SyntaxKind.SetAccessor: - case ts.SyntaxKind.CallSignature: - case ts.SyntaxKind.ConstructSignature: - case ts.SyntaxKind.IndexSignature: - return true; - } - return false; - } - function isIdentifierDefinitionLocation(previousToken) { - if (previousToken) { - var containingNodeKind = previousToken.parent.kind; - switch (previousToken.kind) { - case ts.SyntaxKind.CommaToken: - return containingNodeKind === ts.SyntaxKind.VariableDeclaration || containingNodeKind === ts.SyntaxKind.VariableDeclarationList || containingNodeKind === ts.SyntaxKind.VariableStatement || containingNodeKind === ts.SyntaxKind.EnumDeclaration || isFunction(containingNodeKind); - case ts.SyntaxKind.OpenParenToken: - return containingNodeKind === ts.SyntaxKind.CatchClause || isFunction(containingNodeKind); - case ts.SyntaxKind.OpenBraceToken: - return containingNodeKind === ts.SyntaxKind.EnumDeclaration || containingNodeKind === ts.SyntaxKind.InterfaceDeclaration; - case ts.SyntaxKind.SemicolonToken: - return containingNodeKind === ts.SyntaxKind.PropertySignature && previousToken.parent.parent.kind === ts.SyntaxKind.InterfaceDeclaration; - case ts.SyntaxKind.PublicKeyword: - case ts.SyntaxKind.PrivateKeyword: - case ts.SyntaxKind.StaticKeyword: - case ts.SyntaxKind.DotDotDotToken: - return containingNodeKind === ts.SyntaxKind.Parameter; - case ts.SyntaxKind.ClassKeyword: - case ts.SyntaxKind.ModuleKeyword: - case ts.SyntaxKind.EnumKeyword: - case ts.SyntaxKind.InterfaceKeyword: - case ts.SyntaxKind.FunctionKeyword: - case ts.SyntaxKind.VarKeyword: - case ts.SyntaxKind.GetKeyword: - case ts.SyntaxKind.SetKeyword: - case ts.SyntaxKind.ImportKeyword: - return true; - } - switch (previousToken.getText()) { - case "class": - case "interface": - case "enum": - case "module": - case "function": - case "var": - // TODO: add let and const - return true; - } - } - return false; - } - function isRightOfIllegalDot(previousToken) { - if (previousToken && previousToken.kind === ts.SyntaxKind.NumericLiteral) { - var text = previousToken.getFullText(); - return text.charAt(text.length - 1) === "."; - } - return false; - } - function filterContextualMembersList(contextualMemberSymbols, existingMembers) { - if (!existingMembers || existingMembers.length === 0) { - return contextualMemberSymbols; - } - var existingMemberNames = {}; - ts.forEach(existingMembers, function (m) { - if (m.kind !== ts.SyntaxKind.PropertyAssignment && m.kind !== ts.SyntaxKind.ShorthandPropertyAssignment) { - // Ignore omitted expressions for missing members in the object literal - return; - } - if (m.getStart() <= position && position <= m.getEnd()) { - // If this is the current item we are editing right now, do not filter it out - return; - } - // TODO(jfreeman): Account for computed property name - existingMemberNames[m.name.text] = true; - }); - var filteredMembers = []; - ts.forEach(contextualMemberSymbols, function (s) { - if (!existingMemberNames[s.name]) { - filteredMembers.push(s); - } - }); - return filteredMembers; - } - } - function getCompletionEntryDetails(filename, position, entryName) { - // Note: No need to call synchronizeHostData, as we have captured all the data we need - // in the getCompletionsAtPosition earlier - filename = ts.normalizeSlashes(filename); - var sourceFile = getSourceFile(filename); - var session = 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 = ts.lookUp(activeCompletionSession.symbols, ts.escapeIdentifier(entryName)); - if (symbol) { - var location = ts.getTouchingPropertyName(sourceFile, position); - var completionEntry = createCompletionEntry(symbol, session.typeChecker, location); - // TODO(drosen): Right now we just permit *all* semantic meanings when calling 'getSymbolKind' - // which is permissible given that it is backwards compatible; but really we should consider - // passing the meaning for the node so that we don't report that a suggestion for a value is an interface. - // We COULD also just do what 'getSymbolModifiers' does, which is to use the first declaration. - ts.Debug.assert(session.typeChecker.getTypeOfSymbolAtLocation(symbol, location) !== undefined, "Could not find type for symbol"); - var displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getSourceFile(filename), location, session.typeChecker, location, 7 /* All */); - return { - name: entryName, - kind: displayPartsDocumentationsAndSymbolKind.symbolKind, - kindModifiers: completionEntry.kindModifiers, - displayParts: displayPartsDocumentationsAndSymbolKind.displayParts, - documentation: displayPartsDocumentationsAndSymbolKind.documentation - }; - } - else { - // No symbol, it is a keyword - return { - name: entryName, - kind: ScriptElementKind.keyword, - kindModifiers: ScriptElementKindModifier.none, - displayParts: [ts.displayPart(entryName, 5 /* keyword */)], - documentation: undefined - }; - } - } - function getContainerNode(node) { - while (true) { - node = node.parent; - if (!node) { - return undefined; - } - switch (node.kind) { - case ts.SyntaxKind.SourceFile: - case ts.SyntaxKind.MethodDeclaration: - case ts.SyntaxKind.MethodSignature: - case ts.SyntaxKind.FunctionDeclaration: - case ts.SyntaxKind.FunctionExpression: - case ts.SyntaxKind.GetAccessor: - case ts.SyntaxKind.SetAccessor: - case ts.SyntaxKind.ClassDeclaration: - case ts.SyntaxKind.InterfaceDeclaration: - case ts.SyntaxKind.EnumDeclaration: - case ts.SyntaxKind.ModuleDeclaration: - return node; - } - } - } - // TODO(drosen): use contextual SemanticMeaning. - function getSymbolKind(symbol, typeResolver, location) { - var flags = symbol.getFlags(); - if (flags & ts.SymbolFlags.Class) - return ScriptElementKind.classElement; - if (flags & ts.SymbolFlags.Enum) - return ScriptElementKind.enumElement; - if (flags & ts.SymbolFlags.TypeAlias) - return ScriptElementKind.typeElement; - if (flags & ts.SymbolFlags.Interface) - return ScriptElementKind.interfaceElement; - if (flags & ts.SymbolFlags.TypeParameter) - return ScriptElementKind.typeParameterElement; - var result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, flags, typeResolver, location); - if (result === ScriptElementKind.unknown) { - if (flags & ts.SymbolFlags.TypeParameter) - return ScriptElementKind.typeParameterElement; - if (flags & ts.SymbolFlags.EnumMember) - return ScriptElementKind.variableElement; - if (flags & ts.SymbolFlags.Import) - return ScriptElementKind.alias; - if (flags & ts.SymbolFlags.Module) - return ScriptElementKind.moduleElement; - } - return result; - } - function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, flags, typeResolver, location) { - if (typeResolver.isUndefinedSymbol(symbol)) { - return ScriptElementKind.variableElement; - } - if (typeResolver.isArgumentsSymbol(symbol)) { - return ScriptElementKind.localVariableElement; - } - if (flags & ts.SymbolFlags.Variable) { - if (ts.isFirstDeclarationOfSymbolParameter(symbol)) { - return ScriptElementKind.parameterElement; - } - else if (symbol.valueDeclaration && ts.isConst(symbol.valueDeclaration)) { - return ScriptElementKind.constElement; - } - else if (ts.forEach(symbol.declarations, ts.isLet)) { - return ScriptElementKind.letElement; - } - return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localVariableElement : ScriptElementKind.variableElement; - } - if (flags & ts.SymbolFlags.Function) - return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localFunctionElement : ScriptElementKind.functionElement; - if (flags & ts.SymbolFlags.GetAccessor) - return ScriptElementKind.memberGetAccessorElement; - if (flags & ts.SymbolFlags.SetAccessor) - return ScriptElementKind.memberSetAccessorElement; - if (flags & ts.SymbolFlags.Method) - return ScriptElementKind.memberFunctionElement; - if (flags & ts.SymbolFlags.Constructor) - return ScriptElementKind.constructorImplementationElement; - if (flags & ts.SymbolFlags.Property) { - if (flags & ts.SymbolFlags.UnionProperty) { - // If union property is result of union of non method (property/accessors/variables), it is labeled as property - var unionPropertyKind = ts.forEach(typeInfoResolver.getRootSymbols(symbol), function (rootSymbol) { - var rootSymbolFlags = rootSymbol.getFlags(); - if (rootSymbolFlags & (ts.SymbolFlags.PropertyOrAccessor | ts.SymbolFlags.Variable)) { - return ScriptElementKind.memberVariableElement; - } - ts.Debug.assert(!!(rootSymbolFlags & ts.SymbolFlags.Method)); - }); - if (!unionPropertyKind) { - // If this was union of all methods, - //make sure it has call signatures before we can label it as method - var typeOfUnionProperty = typeInfoResolver.getTypeOfSymbolAtLocation(symbol, location); - if (typeOfUnionProperty.getCallSignatures().length) { - return ScriptElementKind.memberFunctionElement; - } - return ScriptElementKind.memberVariableElement; - } - return unionPropertyKind; - } - return ScriptElementKind.memberVariableElement; - } - return ScriptElementKind.unknown; - } - function getTypeKind(type) { - 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; - } - function getNodeKind(node) { - switch (node.kind) { - case ts.SyntaxKind.ModuleDeclaration: return ScriptElementKind.moduleElement; - case ts.SyntaxKind.ClassDeclaration: return ScriptElementKind.classElement; - case ts.SyntaxKind.InterfaceDeclaration: return ScriptElementKind.interfaceElement; - case ts.SyntaxKind.TypeAliasDeclaration: return ScriptElementKind.typeElement; - case ts.SyntaxKind.EnumDeclaration: return ScriptElementKind.enumElement; - case ts.SyntaxKind.VariableDeclaration: - return ts.isConst(node) ? ScriptElementKind.constElement : ts.isLet(node) ? ScriptElementKind.letElement : ScriptElementKind.variableElement; - case ts.SyntaxKind.FunctionDeclaration: return ScriptElementKind.functionElement; - case ts.SyntaxKind.GetAccessor: return ScriptElementKind.memberGetAccessorElement; - case ts.SyntaxKind.SetAccessor: return ScriptElementKind.memberSetAccessorElement; - case ts.SyntaxKind.MethodDeclaration: - case ts.SyntaxKind.MethodSignature: - return ScriptElementKind.memberFunctionElement; - case ts.SyntaxKind.PropertyDeclaration: - case ts.SyntaxKind.PropertySignature: - return ScriptElementKind.memberVariableElement; - case ts.SyntaxKind.IndexSignature: return ScriptElementKind.indexSignatureElement; - case ts.SyntaxKind.ConstructSignature: return ScriptElementKind.constructSignatureElement; - case ts.SyntaxKind.CallSignature: return ScriptElementKind.callSignatureElement; - case ts.SyntaxKind.Constructor: return ScriptElementKind.constructorImplementationElement; - case ts.SyntaxKind.TypeParameter: return ScriptElementKind.typeParameterElement; - case ts.SyntaxKind.EnumMember: return ScriptElementKind.variableElement; - case ts.SyntaxKind.Parameter: return (node.flags & ts.NodeFlags.AccessibilityModifier) ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement; - } - return ScriptElementKind.unknown; - } - function getSymbolModifiers(symbol) { - return symbol && symbol.declarations && symbol.declarations.length > 0 ? ts.getNodeModifiers(symbol.declarations[0]) : ScriptElementKindModifier.none; - } - function getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, sourceFile, enclosingDeclaration, typeResolver, location, - // TODO(drosen): Currently completion entry details passes the SemanticMeaning.All instead of using semanticMeaning of location - semanticMeaning = getMeaningFromLocation(location)) { - var displayParts = []; - var documentation; - var symbolFlags = symbol.flags; - var symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, symbolFlags, typeResolver, location); - var hasAddedSymbolInfo; - // Class at constructor site need to be shown as constructor apart from property,method, vars - if (symbolKind !== ScriptElementKind.unknown || symbolFlags & ts.SymbolFlags.Class || symbolFlags & ts.SymbolFlags.Import) { - // If it is accessor they are allowed only if location is at name of the accessor - if (symbolKind === ScriptElementKind.memberGetAccessorElement || symbolKind === ScriptElementKind.memberSetAccessorElement) { - symbolKind = ScriptElementKind.memberVariableElement; - } - var type = typeResolver.getTypeOfSymbolAtLocation(symbol, location); - if (type) { - if (location.parent && location.parent.kind === ts.SyntaxKind.PropertyAccessExpression) { - var right = location.parent.name; - // Either the location is on the right of a property access, or on the left and the right is missing - if (right === location || (right && right.getFullWidth() === 0)) { - location = location.parent; - } - } - // try get the call/construct signature from the type if it matches - var callExpression; - if (location.kind === ts.SyntaxKind.CallExpression || location.kind === ts.SyntaxKind.NewExpression) { - callExpression = location; - } - else if (isCallExpressionTarget(location) || isNewExpressionTarget(location)) { - callExpression = location.parent; - } - if (callExpression) { - var candidateSignatures = []; - signature = typeResolver.getResolvedSignature(callExpression, candidateSignatures); - if (!signature && candidateSignatures.length) { - // Use the first candidate: - signature = candidateSignatures[0]; - } - var useConstructSignatures = callExpression.kind === ts.SyntaxKind.NewExpression || callExpression.expression.kind === ts.SyntaxKind.SuperKeyword; - var allSignatures = useConstructSignatures ? type.getConstructSignatures() : type.getCallSignatures(); - if (!ts.contains(allSignatures, signature.target || signature)) { - // Get the first signature if there - signature = allSignatures.length ? allSignatures[0] : undefined; - } - if (signature) { - if (useConstructSignatures && (symbolFlags & ts.SymbolFlags.Class)) { - // Constructor - symbolKind = ScriptElementKind.constructorImplementationElement; - addPrefixForAnyFunctionOrVar(type.symbol, symbolKind); - } - else if (symbolFlags & ts.SymbolFlags.Import) { - symbolKind = ScriptElementKind.alias; - displayParts.push(ts.punctuationPart(ts.SyntaxKind.OpenParenToken)); - displayParts.push(ts.textPart(symbolKind)); - displayParts.push(ts.punctuationPart(ts.SyntaxKind.CloseParenToken)); - displayParts.push(ts.spacePart()); - if (useConstructSignatures) { - displayParts.push(ts.keywordPart(ts.SyntaxKind.NewKeyword)); - displayParts.push(ts.spacePart()); - } - addFullSymbolName(symbol); - } - else { - addPrefixForAnyFunctionOrVar(symbol, symbolKind); - } - switch (symbolKind) { - case ScriptElementKind.memberVariableElement: - case ScriptElementKind.variableElement: - case ScriptElementKind.constElement: - case ScriptElementKind.letElement: - case ScriptElementKind.parameterElement: - case ScriptElementKind.localVariableElement: - // If it is call or construct signature of lambda's write type name - displayParts.push(ts.punctuationPart(ts.SyntaxKind.ColonToken)); - displayParts.push(ts.spacePart()); - if (useConstructSignatures) { - displayParts.push(ts.keywordPart(ts.SyntaxKind.NewKeyword)); - displayParts.push(ts.spacePart()); - } - if (!(type.flags & ts.TypeFlags.Anonymous)) { - displayParts.push.apply(displayParts, ts.symbolToDisplayParts(typeResolver, type.symbol, enclosingDeclaration, undefined, ts.SymbolFormatFlags.WriteTypeParametersOrArguments)); - } - addSignatureDisplayParts(signature, allSignatures, ts.TypeFormatFlags.WriteArrowStyleSignature); - break; - default: - // Just signature - addSignatureDisplayParts(signature, allSignatures); - } - hasAddedSymbolInfo = true; - } - } - else if ((isNameOfFunctionDeclaration(location) && !(symbol.flags & ts.SymbolFlags.Accessor)) || (location.kind === ts.SyntaxKind.ConstructorKeyword && location.parent.kind === ts.SyntaxKind.Constructor)) { - // get the signature from the declaration and write it - var signature; - var functionDeclaration = location.parent; - var allSignatures = functionDeclaration.kind === ts.SyntaxKind.Constructor ? type.getConstructSignatures() : type.getCallSignatures(); - if (!typeResolver.isImplementationOfOverload(functionDeclaration)) { - signature = typeResolver.getSignatureFromDeclaration(functionDeclaration); - } - else { - signature = allSignatures[0]; - } - if (functionDeclaration.kind === ts.SyntaxKind.Constructor) { - // show (constructor) Type(...) signature - symbolKind = ScriptElementKind.constructorImplementationElement; - addPrefixForAnyFunctionOrVar(type.symbol, symbolKind); - } - else { - // (function/method) symbol(..signature) - addPrefixForAnyFunctionOrVar(functionDeclaration.kind === ts.SyntaxKind.CallSignature && !(type.symbol.flags & ts.SymbolFlags.TypeLiteral || type.symbol.flags & ts.SymbolFlags.ObjectLiteral) ? type.symbol : symbol, symbolKind); - } - addSignatureDisplayParts(signature, allSignatures); - hasAddedSymbolInfo = true; - } - } - } - if (symbolFlags & ts.SymbolFlags.Class && !hasAddedSymbolInfo) { - displayParts.push(ts.keywordPart(ts.SyntaxKind.ClassKeyword)); - displayParts.push(ts.spacePart()); - addFullSymbolName(symbol); - writeTypeParametersOfSymbol(symbol, sourceFile); - } - if ((symbolFlags & ts.SymbolFlags.Interface) && (semanticMeaning & 2 /* Type */)) { - addNewLineIfDisplayPartsExist(); - displayParts.push(ts.keywordPart(ts.SyntaxKind.InterfaceKeyword)); - displayParts.push(ts.spacePart()); - addFullSymbolName(symbol); - writeTypeParametersOfSymbol(symbol, sourceFile); - } - if (symbolFlags & ts.SymbolFlags.TypeAlias) { - addNewLineIfDisplayPartsExist(); - displayParts.push(ts.keywordPart(ts.SyntaxKind.TypeKeyword)); - displayParts.push(ts.spacePart()); - addFullSymbolName(symbol); - displayParts.push(ts.spacePart()); - displayParts.push(ts.operatorPart(ts.SyntaxKind.EqualsToken)); - displayParts.push(ts.spacePart()); - displayParts.push.apply(displayParts, ts.typeToDisplayParts(typeResolver, typeResolver.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration)); - } - if (symbolFlags & ts.SymbolFlags.Enum) { - addNewLineIfDisplayPartsExist(); - if (ts.forEach(symbol.declarations, ts.isConstEnumDeclaration)) { - displayParts.push(ts.keywordPart(ts.SyntaxKind.ConstKeyword)); - displayParts.push(ts.spacePart()); - } - displayParts.push(ts.keywordPart(ts.SyntaxKind.EnumKeyword)); - displayParts.push(ts.spacePart()); - addFullSymbolName(symbol); - } - if (symbolFlags & ts.SymbolFlags.Module) { - addNewLineIfDisplayPartsExist(); - displayParts.push(ts.keywordPart(ts.SyntaxKind.ModuleKeyword)); - displayParts.push(ts.spacePart()); - addFullSymbolName(symbol); - } - if ((symbolFlags & ts.SymbolFlags.TypeParameter) && (semanticMeaning & 2 /* Type */)) { - addNewLineIfDisplayPartsExist(); - displayParts.push(ts.punctuationPart(ts.SyntaxKind.OpenParenToken)); - displayParts.push(ts.textPart("type parameter")); - displayParts.push(ts.punctuationPart(ts.SyntaxKind.CloseParenToken)); - displayParts.push(ts.spacePart()); - addFullSymbolName(symbol); - displayParts.push(ts.spacePart()); - displayParts.push(ts.keywordPart(ts.SyntaxKind.InKeyword)); - displayParts.push(ts.spacePart()); - if (symbol.parent) { - // Class/Interface type parameter - addFullSymbolName(symbol.parent, enclosingDeclaration); - writeTypeParametersOfSymbol(symbol.parent, enclosingDeclaration); - } - else { - // Method/function type parameter - var signatureDeclaration = ts.getDeclarationOfKind(symbol, ts.SyntaxKind.TypeParameter).parent; - var signature = typeResolver.getSignatureFromDeclaration(signatureDeclaration); - if (signatureDeclaration.kind === ts.SyntaxKind.ConstructSignature) { - displayParts.push(ts.keywordPart(ts.SyntaxKind.NewKeyword)); - displayParts.push(ts.spacePart()); - } - else if (signatureDeclaration.kind !== ts.SyntaxKind.CallSignature && signatureDeclaration.name) { - addFullSymbolName(signatureDeclaration.symbol); - } - displayParts.push.apply(displayParts, ts.signatureToDisplayParts(typeResolver, signature, sourceFile, ts.TypeFormatFlags.WriteTypeArgumentsOfSignature)); - } - } - if (symbolFlags & ts.SymbolFlags.EnumMember) { - addPrefixForAnyFunctionOrVar(symbol, "enum member"); - var declaration = symbol.declarations[0]; - if (declaration.kind === ts.SyntaxKind.EnumMember) { - var constantValue = typeResolver.getEnumMemberValue(declaration); - if (constantValue !== undefined) { - displayParts.push(ts.spacePart()); - displayParts.push(ts.operatorPart(ts.SyntaxKind.EqualsToken)); - displayParts.push(ts.spacePart()); - displayParts.push(ts.displayPart(constantValue.toString(), 7 /* numericLiteral */)); - } - } - } - if (symbolFlags & ts.SymbolFlags.Import) { - addNewLineIfDisplayPartsExist(); - displayParts.push(ts.keywordPart(ts.SyntaxKind.ImportKeyword)); - displayParts.push(ts.spacePart()); - addFullSymbolName(symbol); - ts.forEach(symbol.declarations, function (declaration) { - if (declaration.kind === ts.SyntaxKind.ImportDeclaration) { - var importDeclaration = declaration; - if (ts.isExternalModuleImportDeclaration(importDeclaration)) { - displayParts.push(ts.spacePart()); - displayParts.push(ts.operatorPart(ts.SyntaxKind.EqualsToken)); - displayParts.push(ts.spacePart()); - displayParts.push(ts.keywordPart(ts.SyntaxKind.RequireKeyword)); - displayParts.push(ts.punctuationPart(ts.SyntaxKind.OpenParenToken)); - displayParts.push(ts.displayPart(ts.getTextOfNode(ts.getExternalModuleImportDeclarationExpression(importDeclaration)), 8 /* stringLiteral */)); - displayParts.push(ts.punctuationPart(ts.SyntaxKind.CloseParenToken)); - } - else { - var internalAliasSymbol = typeResolver.getSymbolAtLocation(importDeclaration.moduleReference); - if (internalAliasSymbol) { - displayParts.push(ts.spacePart()); - displayParts.push(ts.operatorPart(ts.SyntaxKind.EqualsToken)); - displayParts.push(ts.spacePart()); - addFullSymbolName(internalAliasSymbol, enclosingDeclaration); - } - } - return true; - } - }); - } - if (!hasAddedSymbolInfo) { - if (symbolKind !== ScriptElementKind.unknown) { - if (type) { - addPrefixForAnyFunctionOrVar(symbol, symbolKind); - // For properties, variables and local vars: show the type - if (symbolKind === ScriptElementKind.memberVariableElement || symbolFlags & ts.SymbolFlags.Variable || symbolKind === ScriptElementKind.localVariableElement) { - displayParts.push(ts.punctuationPart(ts.SyntaxKind.ColonToken)); - displayParts.push(ts.spacePart()); - // If the type is type parameter, format it specially - if (type.symbol && type.symbol.flags & ts.SymbolFlags.TypeParameter) { - var typeParameterParts = ts.mapToDisplayParts(function (writer) { - typeResolver.getSymbolDisplayBuilder().buildTypeParameterDisplay(type, writer, enclosingDeclaration); - }); - displayParts.push.apply(displayParts, typeParameterParts); - } - else { - displayParts.push.apply(displayParts, ts.typeToDisplayParts(typeResolver, type, enclosingDeclaration)); - } - } - else if (symbolFlags & ts.SymbolFlags.Function || symbolFlags & ts.SymbolFlags.Method || symbolFlags & ts.SymbolFlags.Constructor || symbolFlags & ts.SymbolFlags.Signature || symbolFlags & ts.SymbolFlags.Accessor || symbolKind === ScriptElementKind.memberFunctionElement) { - var allSignatures = type.getCallSignatures(); - addSignatureDisplayParts(allSignatures[0], allSignatures); - } - } - } - else { - symbolKind = getSymbolKind(symbol, typeResolver, location); - } - } - if (!documentation) { - documentation = symbol.getDocumentationComment(); - } - return { displayParts, documentation, symbolKind }; - function addNewLineIfDisplayPartsExist() { - if (displayParts.length) { - displayParts.push(ts.lineBreakPart()); - } - } - function addFullSymbolName(symbol, enclosingDeclaration) { - var fullSymbolDisplayParts = ts.symbolToDisplayParts(typeResolver, symbol, enclosingDeclaration || sourceFile, undefined, ts.SymbolFormatFlags.WriteTypeParametersOrArguments | ts.SymbolFormatFlags.UseOnlyExternalAliasing); - displayParts.push.apply(displayParts, fullSymbolDisplayParts); - } - function addPrefixForAnyFunctionOrVar(symbol, symbolKind) { - addNewLineIfDisplayPartsExist(); - if (symbolKind) { - displayParts.push(ts.punctuationPart(ts.SyntaxKind.OpenParenToken)); - displayParts.push(ts.textPart(symbolKind)); - displayParts.push(ts.punctuationPart(ts.SyntaxKind.CloseParenToken)); - displayParts.push(ts.spacePart()); - addFullSymbolName(symbol); - } - } - function addSignatureDisplayParts(signature, allSignatures, flags) { - displayParts.push.apply(displayParts, ts.signatureToDisplayParts(typeResolver, signature, enclosingDeclaration, flags | ts.TypeFormatFlags.WriteTypeArgumentsOfSignature)); - if (allSignatures.length > 1) { - displayParts.push(ts.spacePart()); - displayParts.push(ts.punctuationPart(ts.SyntaxKind.OpenParenToken)); - displayParts.push(ts.operatorPart(ts.SyntaxKind.PlusToken)); - displayParts.push(ts.displayPart((allSignatures.length - 1).toString(), 7 /* numericLiteral */)); - displayParts.push(ts.spacePart()); - displayParts.push(ts.textPart(allSignatures.length === 2 ? "overload" : "overloads")); - displayParts.push(ts.punctuationPart(ts.SyntaxKind.CloseParenToken)); - } - documentation = signature.getDocumentationComment(); - } - function writeTypeParametersOfSymbol(symbol, enclosingDeclaration) { - var typeParameterParts = ts.mapToDisplayParts(function (writer) { - typeResolver.getSymbolDisplayBuilder().buildTypeParameterDisplayFromSymbol(symbol, writer, enclosingDeclaration); - }); - displayParts.push.apply(displayParts, typeParameterParts); - } - } - function getQuickInfoAtPosition(fileName, position) { - synchronizeHostData(); - fileName = ts.normalizeSlashes(fileName); - var sourceFile = getSourceFile(fileName); - var node = ts.getTouchingPropertyName(sourceFile, position); - if (!node) { - return undefined; - } - var symbol = typeInfoResolver.getSymbolAtLocation(node); - if (!symbol) { - switch (node.kind) { - case ts.SyntaxKind.Identifier: - case ts.SyntaxKind.PropertyAccessExpression: - case ts.SyntaxKind.QualifiedName: - case ts.SyntaxKind.ThisKeyword: - case ts.SyntaxKind.SuperKeyword: - // For the identifiers/this/super etc get the type at position - var type = typeInfoResolver.getTypeAtLocation(node); - if (type) { - return { - kind: ScriptElementKind.unknown, - kindModifiers: ScriptElementKindModifier.none, - textSpan: ts.createTextSpan(node.getStart(), node.getWidth()), - displayParts: ts.typeToDisplayParts(typeInfoResolver, type, getContainerNode(node)), - documentation: type.symbol ? type.symbol.getDocumentationComment() : undefined - }; - } - } - return undefined; - } - var displayPartsDocumentationsAndKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, sourceFile, getContainerNode(node), typeInfoResolver, node); - return { - kind: displayPartsDocumentationsAndKind.symbolKind, - kindModifiers: getSymbolModifiers(symbol), - textSpan: ts.createTextSpan(node.getStart(), node.getWidth()), - displayParts: displayPartsDocumentationsAndKind.displayParts, - documentation: displayPartsDocumentationsAndKind.documentation - }; - } - /// Goto definition - function getDefinitionAtPosition(filename, position) { - synchronizeHostData(); - filename = ts.normalizeSlashes(filename); - var sourceFile = getSourceFile(filename); - var node = ts.getTouchingPropertyName(sourceFile, position); - if (!node) { - return undefined; - } - // Labels - if (isJumpStatementTarget(node)) { - var labelName = node.text; - var label = getTargetLabel(node.parent, node.text); - return label ? [getDefinitionInfo(label, ScriptElementKind.label, labelName, undefined)] : undefined; - } - /// Triple slash reference comments - var comment = ts.forEach(sourceFile.referencedFiles, function (r) { return (r.pos <= position && position < r.end) ? r : undefined; }); - if (comment) { - var referenceFile = ts.tryResolveScriptReference(program, sourceFile, comment); - if (referenceFile) { - return [{ - fileName: referenceFile.filename, - textSpan: ts.createTextSpanFromBounds(0, 0), - kind: ScriptElementKind.scriptElement, - name: comment.filename, - containerName: undefined, - containerKind: undefined - }]; - } - return undefined; - } - var symbol = typeInfoResolver.getSymbolAtLocation(node); - // Could not find a symbol e.g. node is string or number keyword, - // or the symbol was an internal symbol and does not have a declaration e.g. undefined symbol - if (!symbol) { - return undefined; - } - var result = []; - // Because name in short-hand property assignment has two different meanings: property name and property value, - // using go-to-definition at such position should go to the variable declaration of the property value rather than - // go to the declaration of the property name (in this case stay at the same position). However, if go-to-definition - // is performed at the location of property access, we would like to go to definition of the property in the short-hand - // assignment. This case and others are handled by the following code. - if (node.parent.kind === ts.SyntaxKind.ShorthandPropertyAssignment) { - var shorthandSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(symbol.valueDeclaration); - var shorthandDeclarations = shorthandSymbol.getDeclarations(); - var shorthandSymbolKind = getSymbolKind(shorthandSymbol, typeInfoResolver, node); - var shorthandSymbolName = typeInfoResolver.symbolToString(shorthandSymbol); - var shorthandContainerName = typeInfoResolver.symbolToString(symbol.parent, node); - ts.forEach(shorthandDeclarations, function (declaration) { - result.push(getDefinitionInfo(declaration, shorthandSymbolKind, shorthandSymbolName, shorthandContainerName)); - }); - return result; - } - var declarations = symbol.getDeclarations(); - var symbolName = typeInfoResolver.symbolToString(symbol); // Do not get scoped name, just the name of the symbol - var symbolKind = getSymbolKind(symbol, typeInfoResolver, node); - var containerSymbol = symbol.parent; - var containerName = containerSymbol ? typeInfoResolver.symbolToString(containerSymbol, node) : ""; - if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) && !tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) { - // Just add all the declarations. - ts.forEach(declarations, function (declaration) { - result.push(getDefinitionInfo(declaration, symbolKind, symbolName, containerName)); - }); - } - return result; - function getDefinitionInfo(node, symbolKind, symbolName, containerName) { - return { - fileName: node.getSourceFile().filename, - textSpan: ts.createTextSpanFromBounds(node.getStart(), node.getEnd()), - kind: symbolKind, - name: symbolName, - containerKind: undefined, - containerName - }; - } - function tryAddSignature(signatureDeclarations, selectConstructors, symbolKind, symbolName, containerName, result) { - var declarations = []; - var definition; - ts.forEach(signatureDeclarations, function (d) { - if ((selectConstructors && d.kind === ts.SyntaxKind.Constructor) || (!selectConstructors && (d.kind === ts.SyntaxKind.FunctionDeclaration || d.kind === ts.SyntaxKind.MethodDeclaration || d.kind === ts.SyntaxKind.MethodSignature))) { - declarations.push(d); - if (d.body) - definition = d; - } - }); - if (definition) { - result.push(getDefinitionInfo(definition, symbolKind, symbolName, containerName)); - return true; - } - else if (declarations.length) { - result.push(getDefinitionInfo(declarations[declarations.length - 1], symbolKind, symbolName, containerName)); - return true; - } - return false; - } - function tryAddConstructSignature(symbol, location, symbolKind, symbolName, containerName, result) { - // Applicable only if we are in a new expression, or we are on a constructor declaration - // and in either case the symbol has a construct signature definition, i.e. class - if (isNewExpressionTarget(location) || location.kind === ts.SyntaxKind.ConstructorKeyword) { - if (symbol.flags & ts.SymbolFlags.Class) { - var classDeclaration = symbol.getDeclarations()[0]; - ts.Debug.assert(classDeclaration && classDeclaration.kind === ts.SyntaxKind.ClassDeclaration); - return tryAddSignature(classDeclaration.members, true, symbolKind, symbolName, containerName, result); - } - } - return false; - } - function tryAddCallSignature(symbol, location, symbolKind, symbolName, containerName, result) { - if (isCallExpressionTarget(location) || isNewExpressionTarget(location) || isNameOfFunctionDeclaration(location)) { - return tryAddSignature(symbol.declarations, false, symbolKind, symbolName, containerName, result); - } - return false; - } - } - /// References and Occurrences - function getOccurrencesAtPosition(filename, position) { - synchronizeHostData(); - filename = ts.normalizeSlashes(filename); - var sourceFile = getSourceFile(filename); - var node = ts.getTouchingWord(sourceFile, position); - if (!node) { - return undefined; - } - if (node.kind === ts.SyntaxKind.Identifier || node.kind === ts.SyntaxKind.ThisKeyword || node.kind === ts.SyntaxKind.SuperKeyword || isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || isNameOfExternalModuleImportOrDeclaration(node)) { - return getReferencesForNode(node, [sourceFile], false, false); - } - switch (node.kind) { - case ts.SyntaxKind.IfKeyword: - case ts.SyntaxKind.ElseKeyword: - if (hasKind(node.parent, ts.SyntaxKind.IfStatement)) { - return getIfElseOccurrences(node.parent); - } - break; - case ts.SyntaxKind.ReturnKeyword: - if (hasKind(node.parent, ts.SyntaxKind.ReturnStatement)) { - return getReturnOccurrences(node.parent); - } - break; - case ts.SyntaxKind.ThrowKeyword: - if (hasKind(node.parent, ts.SyntaxKind.ThrowStatement)) { - return getThrowOccurrences(node.parent); - } - break; - case ts.SyntaxKind.CatchKeyword: - if (hasKind(parent(parent(node)), ts.SyntaxKind.TryStatement)) { - return getTryCatchFinallyOccurrences(node.parent.parent); - } - break; - case ts.SyntaxKind.TryKeyword: - case ts.SyntaxKind.FinallyKeyword: - if (hasKind(parent(node), ts.SyntaxKind.TryStatement)) { - return getTryCatchFinallyOccurrences(node.parent); - } - break; - case ts.SyntaxKind.SwitchKeyword: - if (hasKind(node.parent, ts.SyntaxKind.SwitchStatement)) { - return getSwitchCaseDefaultOccurrences(node.parent); - } - break; - case ts.SyntaxKind.CaseKeyword: - case ts.SyntaxKind.DefaultKeyword: - if (hasKind(parent(parent(node)), ts.SyntaxKind.SwitchStatement)) { - return getSwitchCaseDefaultOccurrences(node.parent.parent); - } - break; - case ts.SyntaxKind.BreakKeyword: - case ts.SyntaxKind.ContinueKeyword: - if (hasKind(node.parent, ts.SyntaxKind.BreakStatement) || hasKind(node.parent, ts.SyntaxKind.ContinueStatement)) { - return getBreakOrContinueStatementOccurences(node.parent); - } - break; - case ts.SyntaxKind.ForKeyword: - if (hasKind(node.parent, ts.SyntaxKind.ForStatement) || hasKind(node.parent, ts.SyntaxKind.ForInStatement)) { - return getLoopBreakContinueOccurrences(node.parent); - } - break; - case ts.SyntaxKind.WhileKeyword: - case ts.SyntaxKind.DoKeyword: - if (hasKind(node.parent, ts.SyntaxKind.WhileStatement) || hasKind(node.parent, ts.SyntaxKind.DoStatement)) { - return getLoopBreakContinueOccurrences(node.parent); - } - break; - case ts.SyntaxKind.ConstructorKeyword: - if (hasKind(node.parent, ts.SyntaxKind.Constructor)) { - return getConstructorOccurrences(node.parent); - } - break; - case ts.SyntaxKind.GetKeyword: - case ts.SyntaxKind.SetKeyword: - if (hasKind(node.parent, ts.SyntaxKind.GetAccessor) || hasKind(node.parent, ts.SyntaxKind.SetAccessor)) { - return getGetAndSetOccurrences(node.parent); - } - default: - if (ts.isModifier(node.kind) && node.parent && (ts.isDeclaration(node.parent) || node.parent.kind === ts.SyntaxKind.VariableStatement)) { - return getModifierOccurrences(node.kind, node.parent); - } - } - return undefined; - function getIfElseOccurrences(ifStatement) { - var keywords = []; - while (hasKind(ifStatement.parent, ts.SyntaxKind.IfStatement) && ifStatement.parent.elseStatement === ifStatement) { - ifStatement = ifStatement.parent; - } - while (ifStatement) { - var children = ifStatement.getChildren(); - pushKeywordIf(keywords, children[0], ts.SyntaxKind.IfKeyword); - for (var i = children.length - 1; i >= 0; i--) { - if (pushKeywordIf(keywords, children[i], ts.SyntaxKind.ElseKeyword)) { - break; - } - } - if (!hasKind(ifStatement.elseStatement, ts.SyntaxKind.IfStatement)) { - break; - } - ifStatement = ifStatement.elseStatement; - } - var result = []; - for (var i = 0; i < keywords.length; i++) { - if (keywords[i].kind === ts.SyntaxKind.ElseKeyword && i < keywords.length - 1) { - var elseKeyword = keywords[i]; - var ifKeyword = keywords[i + 1]; // this *should* always be an 'if' keyword. - var shouldHighlightNextKeyword = true; - for (var j = ifKeyword.getStart() - 1; j >= elseKeyword.end; j--) { - if (!ts.isWhiteSpace(sourceFile.text.charCodeAt(j))) { - shouldHighlightNextKeyword = false; - break; - } - } - if (shouldHighlightNextKeyword) { - result.push({ - fileName: filename, - textSpan: ts.createTextSpanFromBounds(elseKeyword.getStart(), ifKeyword.end), - isWriteAccess: false - }); - i++; // skip the next keyword - continue; - } - } - // Ordinary case: just highlight the keyword. - result.push(getReferenceEntryFromNode(keywords[i])); - } - return result; - } - function getReturnOccurrences(returnStatement) { - var func = ts.getContainingFunction(returnStatement); - // If we didn't find a containing function with a block body, bail out. - if (!(func && hasKind(func.body, ts.SyntaxKind.Block))) { - return undefined; - } - var keywords = []; - ts.forEachReturnStatement(func.body, function (returnStatement) { - pushKeywordIf(keywords, returnStatement.getFirstToken(), ts.SyntaxKind.ReturnKeyword); - }); - // Include 'throw' statements that do not occur within a try block. - ts.forEach(aggregateOwnedThrowStatements(func.body), function (throwStatement) { - pushKeywordIf(keywords, throwStatement.getFirstToken(), ts.SyntaxKind.ThrowKeyword); - }); - return ts.map(keywords, getReferenceEntryFromNode); - } - function getThrowOccurrences(throwStatement) { - var owner = getThrowStatementOwner(throwStatement); - if (!owner) { - return undefined; - } - var keywords = []; - ts.forEach(aggregateOwnedThrowStatements(owner), function (throwStatement) { - pushKeywordIf(keywords, throwStatement.getFirstToken(), ts.SyntaxKind.ThrowKeyword); - }); - // If the "owner" is a function, then we equate 'return' and 'throw' statements in their - // ability to "jump out" of the function, and include occurrences for both. - if (ts.isFunctionBlock(owner)) { - ts.forEachReturnStatement(owner, function (returnStatement) { - pushKeywordIf(keywords, returnStatement.getFirstToken(), ts.SyntaxKind.ReturnKeyword); - }); - } - return ts.map(keywords, getReferenceEntryFromNode); - } - /** - * Aggregates all throw-statements within this node *without* crossing - * into function boundaries and try-blocks with catch-clauses. - */ - function aggregateOwnedThrowStatements(node) { - var statementAccumulator = []; - aggregate(node); - return statementAccumulator; - function aggregate(node) { - if (node.kind === ts.SyntaxKind.ThrowStatement) { - statementAccumulator.push(node); - } - else if (node.kind === ts.SyntaxKind.TryStatement) { - var tryStatement = node; - if (tryStatement.catchClause) { - aggregate(tryStatement.catchClause); - } - else { - // Exceptions thrown within a try block lacking a catch clause - // are "owned" in the current context. - aggregate(tryStatement.tryBlock); - } - if (tryStatement.finallyBlock) { - aggregate(tryStatement.finallyBlock); - } - } - else if (!ts.isAnyFunction(node)) { - ts.forEachChild(node, aggregate); - } - } - ; - } - /** - * For lack of a better name, this function takes a throw statement and returns the - * nearest ancestor that is a try-block (whose try statement has a catch clause), - * function-block, or source file. - */ - function getThrowStatementOwner(throwStatement) { - var child = throwStatement; - while (child.parent) { - var parent = child.parent; - if (ts.isFunctionBlock(parent) || parent.kind === ts.SyntaxKind.SourceFile) { - return parent; - } - // A throw-statement is only owned by a try-statement if the try-statement has - // a catch clause, and if the throw-statement occurs within the try block. - if (parent.kind === ts.SyntaxKind.TryStatement) { - var tryStatement = parent; - if (tryStatement.tryBlock === child && tryStatement.catchClause) { - return child; - } - } - child = parent; - } - return undefined; - } - function getTryCatchFinallyOccurrences(tryStatement) { - var keywords = []; - pushKeywordIf(keywords, tryStatement.getFirstToken(), ts.SyntaxKind.TryKeyword); - if (tryStatement.catchClause) { - pushKeywordIf(keywords, tryStatement.catchClause.getFirstToken(), ts.SyntaxKind.CatchKeyword); - } - if (tryStatement.finallyBlock) { - var finallyKeyword = ts.findChildOfKind(tryStatement, ts.SyntaxKind.FinallyKeyword, sourceFile); - pushKeywordIf(keywords, finallyKeyword, ts.SyntaxKind.FinallyKeyword); - } - return ts.map(keywords, getReferenceEntryFromNode); - } - function getLoopBreakContinueOccurrences(loopNode) { - var keywords = []; - if (pushKeywordIf(keywords, loopNode.getFirstToken(), ts.SyntaxKind.ForKeyword, ts.SyntaxKind.WhileKeyword, ts.SyntaxKind.DoKeyword)) { - // If we succeeded and got a do-while loop, then start looking for a 'while' keyword. - if (loopNode.kind === ts.SyntaxKind.DoStatement) { - var loopTokens = loopNode.getChildren(); - for (var i = loopTokens.length - 1; i >= 0; i--) { - if (pushKeywordIf(keywords, loopTokens[i], ts.SyntaxKind.WhileKeyword)) { - break; - } - } - } - } - var breaksAndContinues = aggregateAllBreakAndContinueStatements(loopNode.statement); - ts.forEach(breaksAndContinues, function (statement) { - if (ownsBreakOrContinueStatement(loopNode, statement)) { - pushKeywordIf(keywords, statement.getFirstToken(), ts.SyntaxKind.BreakKeyword, ts.SyntaxKind.ContinueKeyword); - } - }); - return ts.map(keywords, getReferenceEntryFromNode); - } - function getSwitchCaseDefaultOccurrences(switchStatement) { - var keywords = []; - pushKeywordIf(keywords, switchStatement.getFirstToken(), ts.SyntaxKind.SwitchKeyword); - // Go through each clause in the switch statement, collecting the 'case'/'default' keywords. - ts.forEach(switchStatement.clauses, function (clause) { - pushKeywordIf(keywords, clause.getFirstToken(), ts.SyntaxKind.CaseKeyword, ts.SyntaxKind.DefaultKeyword); - var breaksAndContinues = aggregateAllBreakAndContinueStatements(clause); - ts.forEach(breaksAndContinues, function (statement) { - if (ownsBreakOrContinueStatement(switchStatement, statement)) { - pushKeywordIf(keywords, statement.getFirstToken(), ts.SyntaxKind.BreakKeyword); - } - }); - }); - return ts.map(keywords, getReferenceEntryFromNode); - } - function getBreakOrContinueStatementOccurences(breakOrContinueStatement) { - var owner = getBreakOrContinueOwner(breakOrContinueStatement); - if (owner) { - switch (owner.kind) { - case ts.SyntaxKind.ForStatement: - case ts.SyntaxKind.ForInStatement: - case ts.SyntaxKind.DoStatement: - case ts.SyntaxKind.WhileStatement: - return getLoopBreakContinueOccurrences(owner); - case ts.SyntaxKind.SwitchStatement: - return getSwitchCaseDefaultOccurrences(owner); - } - } - return undefined; - } - function aggregateAllBreakAndContinueStatements(node) { - var statementAccumulator = []; - aggregate(node); - return statementAccumulator; - function aggregate(node) { - if (node.kind === ts.SyntaxKind.BreakStatement || node.kind === ts.SyntaxKind.ContinueStatement) { - statementAccumulator.push(node); - } - else if (!ts.isAnyFunction(node)) { - ts.forEachChild(node, aggregate); - } - } - ; - } - function ownsBreakOrContinueStatement(owner, statement) { - var actualOwner = getBreakOrContinueOwner(statement); - return actualOwner && actualOwner === owner; - } - function getBreakOrContinueOwner(statement) { - for (var node = statement.parent; node; node = node.parent) { - switch (node.kind) { - case ts.SyntaxKind.SwitchStatement: - if (statement.kind === ts.SyntaxKind.ContinueStatement) { - continue; - } - case ts.SyntaxKind.ForStatement: - case ts.SyntaxKind.ForInStatement: - case ts.SyntaxKind.WhileStatement: - case ts.SyntaxKind.DoStatement: - if (!statement.label || isLabeledBy(node, statement.label.text)) { - return node; - } - break; - default: - // Don't cross function boundaries. - if (ts.isAnyFunction(node)) { - return undefined; - } - break; - } - } - return undefined; - } - function getConstructorOccurrences(constructorDeclaration) { - var declarations = constructorDeclaration.symbol.getDeclarations(); - var keywords = []; - ts.forEach(declarations, function (declaration) { - ts.forEach(declaration.getChildren(), function (token) { - return pushKeywordIf(keywords, token, ts.SyntaxKind.ConstructorKeyword); - }); - }); - return ts.map(keywords, getReferenceEntryFromNode); - } - function getGetAndSetOccurrences(accessorDeclaration) { - var keywords = []; - tryPushAccessorKeyword(accessorDeclaration.symbol, ts.SyntaxKind.GetAccessor); - tryPushAccessorKeyword(accessorDeclaration.symbol, ts.SyntaxKind.SetAccessor); - return ts.map(keywords, getReferenceEntryFromNode); - function tryPushAccessorKeyword(accessorSymbol, accessorKind) { - var accessor = ts.getDeclarationOfKind(accessorSymbol, accessorKind); - if (accessor) { - ts.forEach(accessor.getChildren(), function (child) { return pushKeywordIf(keywords, child, ts.SyntaxKind.GetKeyword, ts.SyntaxKind.SetKeyword); }); - } - } - } - function getModifierOccurrences(modifier, declaration) { - var container = declaration.parent; - // Make sure we only highlight the keyword when it makes sense to do so. - if (declaration.flags & ts.NodeFlags.AccessibilityModifier) { - if (!(container.kind === ts.SyntaxKind.ClassDeclaration || (declaration.kind === ts.SyntaxKind.Parameter && hasKind(container, ts.SyntaxKind.Constructor)))) { - return undefined; - } - } - else if (declaration.flags & ts.NodeFlags.Static) { - if (container.kind !== ts.SyntaxKind.ClassDeclaration) { - return undefined; - } - } - else if (declaration.flags & (ts.NodeFlags.Export | ts.NodeFlags.Ambient)) { - if (!(container.kind === ts.SyntaxKind.ModuleBlock || container.kind === ts.SyntaxKind.SourceFile)) { - return undefined; - } - } - else { - // unsupported modifier - return undefined; - } - var keywords = []; - var modifierFlag = getFlagFromModifier(modifier); - var nodes; - switch (container.kind) { - case ts.SyntaxKind.ModuleBlock: - case ts.SyntaxKind.SourceFile: - nodes = container.statements; - break; - case ts.SyntaxKind.Constructor: - nodes = container.parameters.concat(container.parent.members); - break; - case ts.SyntaxKind.ClassDeclaration: - nodes = container.members; - // If we're an accessibility modifier, we're in an instance member and should search - // the constructor's parameter list for instance members as well. - if (modifierFlag & ts.NodeFlags.AccessibilityModifier) { - var constructor = ts.forEach(container.members, function (member) { - return member.kind === ts.SyntaxKind.Constructor && member; - }); - if (constructor) { - nodes = nodes.concat(constructor.parameters); - } - } - break; - default: - ts.Debug.fail("Invalid container kind."); - } - ts.forEach(nodes, function (node) { - if (node.modifiers && node.flags & modifierFlag) { - ts.forEach(node.modifiers, function (child) { return pushKeywordIf(keywords, child, modifier); }); - } - }); - return ts.map(keywords, getReferenceEntryFromNode); - function getFlagFromModifier(modifier) { - switch (modifier) { - case ts.SyntaxKind.PublicKeyword: - return ts.NodeFlags.Public; - case ts.SyntaxKind.PrivateKeyword: - return ts.NodeFlags.Private; - case ts.SyntaxKind.ProtectedKeyword: - return ts.NodeFlags.Protected; - case ts.SyntaxKind.StaticKeyword: - return ts.NodeFlags.Static; - case ts.SyntaxKind.ExportKeyword: - return ts.NodeFlags.Export; - case ts.SyntaxKind.DeclareKeyword: - return ts.NodeFlags.Ambient; - default: - ts.Debug.fail(); - } - } - } - // returns true if 'node' is defined and has a matching 'kind'. - function hasKind(node, kind) { - return node !== undefined && node.kind === kind; - } - // Null-propagating 'parent' function. - function parent(node) { - return node && node.parent; - } - function pushKeywordIf(keywordList, token, ...expected) { - if (token && ts.contains(expected, token.kind)) { - keywordList.push(token); - return true; - } - return false; - } - } - function findRenameLocations(fileName, position, findInStrings, findInComments) { - return findReferences(fileName, position, findInStrings, findInComments); - } - function getReferencesAtPosition(fileName, position) { - return findReferences(fileName, position, false, false); - } - function findReferences(fileName, position, findInStrings, findInComments) { - synchronizeHostData(); - fileName = ts.normalizeSlashes(fileName); - var sourceFile = getSourceFile(fileName); - var node = ts.getTouchingPropertyName(sourceFile, position); - if (!node) { - return undefined; - } - if (node.kind !== ts.SyntaxKind.Identifier && !isLiteralNameOfPropertyDeclarationOrIndexAccess(node) && !isNameOfExternalModuleImportOrDeclaration(node)) { - return undefined; - } - ts.Debug.assert(node.kind === ts.SyntaxKind.Identifier || node.kind === ts.SyntaxKind.NumericLiteral || node.kind === ts.SyntaxKind.StringLiteral); - return getReferencesForNode(node, program.getSourceFiles(), findInStrings, findInComments); - } - function getReferencesForNode(node, sourceFiles, findInStrings, findInComments) { - // Labels - if (isLabelName(node)) { - if (isJumpStatementTarget(node)) { - var labelDefinition = getTargetLabel(node.parent, node.text); - // if we have a label definition, look within its statement for references, if not, then - // the label is undefined, just return a set of one for the current node. - return labelDefinition ? getLabelReferencesInNode(labelDefinition.parent, labelDefinition) : [getReferenceEntryFromNode(node)]; - } - else { - // it is a label definition and not a target, search within the parent labeledStatement - return getLabelReferencesInNode(node.parent, node); - } - } - if (node.kind === ts.SyntaxKind.ThisKeyword) { - return getReferencesForThisKeyword(node, sourceFiles); - } - if (node.kind === ts.SyntaxKind.SuperKeyword) { - return getReferencesForSuperKeyword(node); - } - var symbol = typeInfoResolver.getSymbolAtLocation(node); - // Could not find a symbol e.g. unknown identifier - if (!symbol) { - // Even if we did not find a symbol, we have an identifier, so there is at least - // one reference that we know of. return that instead of undefined. - return [getReferenceEntryFromNode(node)]; - } - var declarations = symbol.declarations; - // The symbol was an internal symbol and does not have a declaration e.g.undefined symbol - if (!declarations || !declarations.length) { - return undefined; - } - var result; - // Compute the meaning from the location and the symbol it references - var searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), declarations); - // Get the text to search for, we need to normalize it as external module names will have quote - var declaredName = getDeclaredName(symbol); - // Try to get the smallest valid scope that we can limit our search to; - // otherwise we'll need to search globally (i.e. include each file). - var scope = getSymbolScope(symbol); - if (scope) { - result = []; - getReferencesInNode(scope, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result); - } - else { - var internedName = getInternedName(symbol, declarations); - ts.forEach(sourceFiles, function (sourceFile) { - cancellationToken.throwIfCancellationRequested(); - if (ts.lookUp(sourceFile.identifiers, internedName)) { - result = result || []; - getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result); - } - }); - } - return result; - function getDeclaredName(symbol) { - var name = typeInfoResolver.symbolToString(symbol); - return stripQuotes(name); - } - function getInternedName(symbol, declarations) { - // Special case for function expressions, whose names are solely local to their bodies. - var functionExpression = ts.forEach(declarations, function (d) { return d.kind === ts.SyntaxKind.FunctionExpression ? d : undefined; }); - // When a name gets interned into a SourceFile's 'identifiers' Map, - // its name is escaped and stored in the same way its symbol name/identifier - // name should be stored. Function expressions, however, are a special case, - // because despite sometimes having a name, the binder unconditionally binds them - // to a symbol with the name "__function". - if (functionExpression && functionExpression.name) { - var name = functionExpression.name.text; - } - else { - var name = symbol.name; - } - return stripQuotes(name); - } - function stripQuotes(name) { - var length = name.length; - if (length >= 2 && name.charCodeAt(0) === ts.CharacterCodes.doubleQuote && name.charCodeAt(length - 1) === ts.CharacterCodes.doubleQuote) { - return name.substring(1, length - 1); - } - ; - return name; - } - function getSymbolScope(symbol) { - // If this is private property or method, the scope is the containing class - if (symbol.getFlags() && (ts.SymbolFlags.Property | ts.SymbolFlags.Method)) { - var privateDeclaration = ts.forEach(symbol.getDeclarations(), function (d) { return (d.flags & ts.NodeFlags.Private) ? d : undefined; }); - if (privateDeclaration) { - return ts.getAncestor(privateDeclaration, ts.SyntaxKind.ClassDeclaration); - } - } - // if this symbol is visible from its parent container, e.g. exported, then bail out - if (symbol.parent) { - return undefined; - } - var scope = undefined; - var declarations = symbol.getDeclarations(); - if (declarations) { - for (var i = 0, n = declarations.length; i < n; i++) { - var container = getContainerNode(declarations[i]); - if (!container) { - return undefined; - } - if (scope && scope !== container) { - // Different declarations have different containers, bail out - return undefined; - } - if (container.kind === ts.SyntaxKind.SourceFile && !ts.isExternalModule(container)) { - // This is a global variable and not an external module, any declaration defined - // within this scope is visible outside the file - return undefined; - } - // The search scope is the container node - scope = container; - } - } - return scope; - } - function getPossibleSymbolReferencePositions(sourceFile, symbolName, start, end) { - var positions = []; - /// TODO: Cache symbol existence for files to save text search - // Also, need to make this work for unicode escapes. - // Be resilient in the face of a symbol with no name or zero length name - if (!symbolName || !symbolName.length) { - return positions; - } - var text = sourceFile.text; - var sourceLength = text.length; - var symbolNameLength = symbolName.length; - var position = text.indexOf(symbolName, start); - while (position >= 0) { - cancellationToken.throwIfCancellationRequested(); - // If we are past the end, stop looking - if (position > end) - break; - // We found a match. Make sure it's not part of a larger word (i.e. the char - // before and after it have to be a non-identifier char). - var endPosition = position + symbolNameLength; - if ((position === 0 || !ts.isIdentifierPart(text.charCodeAt(position - 1), ts.ScriptTarget.Latest)) && (endPosition === sourceLength || !ts.isIdentifierPart(text.charCodeAt(endPosition), ts.ScriptTarget.Latest))) { - // Found a real match. Keep searching. - positions.push(position); - } - position = text.indexOf(symbolName, position + symbolNameLength + 1); - } - return positions; - } - function getLabelReferencesInNode(container, targetLabel) { - var result = []; - var sourceFile = container.getSourceFile(); - var labelName = targetLabel.text; - var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, labelName, container.getStart(), container.getEnd()); - ts.forEach(possiblePositions, function (position) { - cancellationToken.throwIfCancellationRequested(); - var node = ts.getTouchingWord(sourceFile, position); - if (!node || node.getWidth() !== labelName.length) { - return; - } - // Only pick labels that are either the target label, or have a target that is the target label - if (node === targetLabel || (isJumpStatementTarget(node) && getTargetLabel(node, labelName) === targetLabel)) { - result.push(getReferenceEntryFromNode(node)); - } - }); - return result; - } - function isValidReferencePosition(node, searchSymbolName) { - if (node) { - switch (node.kind) { - case ts.SyntaxKind.Identifier: - return node.getWidth() === searchSymbolName.length; - case ts.SyntaxKind.StringLiteral: - if (isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || isNameOfExternalModuleImportOrDeclaration(node)) { - // For string literals we have two additional chars for the quotes - return node.getWidth() === searchSymbolName.length + 2; - } - break; - case ts.SyntaxKind.NumericLiteral: - if (isLiteralNameOfPropertyDeclarationOrIndexAccess(node)) { - return node.getWidth() === searchSymbolName.length; - } - break; - } - } - return false; - } - /** Search within node "container" for references for a search value, where the search value is defined as a - * tuple of(searchSymbol, searchText, searchLocation, and searchMeaning). - * searchLocation: a node where the search value - */ - function getReferencesInNode(container, searchSymbol, searchText, searchLocation, searchMeaning, findInStrings, findInComments, result) { - var sourceFile = container.getSourceFile(); - var tripleSlashDirectivePrefixRegex = /^\/\/\/\s*= 0) { - result.push(getReferenceEntryFromNode(referenceSymbolDeclaration.name)); - } - } - }); - } - function isInString(position) { - var token = ts.getTokenAtPosition(sourceFile, position); - return token && token.kind === ts.SyntaxKind.StringLiteral && position > token.getStart(); - } - function isInComment(position) { - var token = ts.getTokenAtPosition(sourceFile, position); - if (token && position < token.getStart()) { - // First, we have to see if this position actually landed in a comment. - var commentRanges = ts.getLeadingCommentRanges(sourceFile.text, token.pos); - // Then we want to make sure that it wasn't in a "///<" directive comment - // We don't want to unintentionally update a file name. - return ts.forEach(commentRanges, function (c) { - if (c.pos < position && position < c.end) { - var commentText = sourceFile.text.substring(c.pos, c.end); - if (!tripleSlashDirectivePrefixRegex.test(commentText)) { - return true; - } - } - }); - } - return false; - } - } - function getReferencesForSuperKeyword(superKeyword) { - var searchSpaceNode = ts.getSuperContainer(superKeyword); - if (!searchSpaceNode) { - return undefined; - } - // Whether 'super' occurs in a static context within a class. - var staticFlag = ts.NodeFlags.Static; - switch (searchSpaceNode.kind) { - case ts.SyntaxKind.PropertyDeclaration: - case ts.SyntaxKind.PropertySignature: - case ts.SyntaxKind.MethodDeclaration: - case ts.SyntaxKind.MethodSignature: - case ts.SyntaxKind.Constructor: - case ts.SyntaxKind.GetAccessor: - case ts.SyntaxKind.SetAccessor: - staticFlag &= searchSpaceNode.flags; - searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class - break; - default: - return undefined; - } - var result = []; - var sourceFile = searchSpaceNode.getSourceFile(); - var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "super", searchSpaceNode.getStart(), searchSpaceNode.getEnd()); - ts.forEach(possiblePositions, function (position) { - cancellationToken.throwIfCancellationRequested(); - var node = ts.getTouchingWord(sourceFile, position); - if (!node || node.kind !== ts.SyntaxKind.SuperKeyword) { - return; - } - var container = ts.getSuperContainer(node); - // If we have a 'super' container, we must have an enclosing class. - // Now make sure the owning class is the same as the search-space - // and has the same static qualifier as the original 'super's owner. - if (container && (ts.NodeFlags.Static & container.flags) === staticFlag && container.parent.symbol === searchSpaceNode.symbol) { - result.push(getReferenceEntryFromNode(node)); - } - }); - return result; - } - function getReferencesForThisKeyword(thisOrSuperKeyword, sourceFiles) { - var searchSpaceNode = ts.getThisContainer(thisOrSuperKeyword, false); - // Whether 'this' occurs in a static context within a class. - var staticFlag = ts.NodeFlags.Static; - switch (searchSpaceNode.kind) { - case ts.SyntaxKind.MethodDeclaration: - case ts.SyntaxKind.MethodSignature: - if (ts.isObjectLiteralMethod(searchSpaceNode)) { - break; - } - case ts.SyntaxKind.PropertyDeclaration: - case ts.SyntaxKind.PropertySignature: - case ts.SyntaxKind.Constructor: - case ts.SyntaxKind.GetAccessor: - case ts.SyntaxKind.SetAccessor: - staticFlag &= searchSpaceNode.flags; - searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class - break; - case ts.SyntaxKind.SourceFile: - if (ts.isExternalModule(searchSpaceNode)) { - return undefined; - } - case ts.SyntaxKind.FunctionDeclaration: - case ts.SyntaxKind.FunctionExpression: - break; - default: - return undefined; - } - var result = []; - if (searchSpaceNode.kind === ts.SyntaxKind.SourceFile) { - ts.forEach(sourceFiles, function (sourceFile) { - var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "this", sourceFile.getStart(), sourceFile.getEnd()); - getThisReferencesInFile(sourceFile, sourceFile, possiblePositions, result); - }); - } - else { - var sourceFile = searchSpaceNode.getSourceFile(); - var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "this", searchSpaceNode.getStart(), searchSpaceNode.getEnd()); - getThisReferencesInFile(sourceFile, searchSpaceNode, possiblePositions, result); - } - return result; - function getThisReferencesInFile(sourceFile, searchSpaceNode, possiblePositions, result) { - ts.forEach(possiblePositions, function (position) { - cancellationToken.throwIfCancellationRequested(); - var node = ts.getTouchingWord(sourceFile, position); - if (!node || node.kind !== ts.SyntaxKind.ThisKeyword) { - return; - } - var container = ts.getThisContainer(node, false); - switch (searchSpaceNode.kind) { - case ts.SyntaxKind.FunctionExpression: - case ts.SyntaxKind.FunctionDeclaration: - if (searchSpaceNode.symbol === container.symbol) { - result.push(getReferenceEntryFromNode(node)); - } - break; - case ts.SyntaxKind.MethodDeclaration: - case ts.SyntaxKind.MethodSignature: - if (ts.isObjectLiteralMethod(searchSpaceNode) && searchSpaceNode.symbol === container.symbol) { - result.push(getReferenceEntryFromNode(node)); - } - break; - case ts.SyntaxKind.ClassDeclaration: - // Make sure the container belongs to the same class - // and has the appropriate static modifier from the original container. - if (container.parent && searchSpaceNode.symbol === container.parent.symbol && (container.flags & ts.NodeFlags.Static) === staticFlag) { - result.push(getReferenceEntryFromNode(node)); - } - break; - case ts.SyntaxKind.SourceFile: - if (container.kind === ts.SyntaxKind.SourceFile && !ts.isExternalModule(container)) { - result.push(getReferenceEntryFromNode(node)); - } - break; - } - }); - } - } - function populateSearchSymbolSet(symbol, location) { - // The search set contains at least the current symbol - var result = [symbol]; - // If the location is in a context sensitive location (i.e. in an object literal) try - // to get a contextual type for it, and add the property symbol from the contextual - // type to the search set - if (isNameOfPropertyAssignment(location)) { - ts.forEach(getPropertySymbolsFromContextualType(location), function (contextualSymbol) { - result.push.apply(result, typeInfoResolver.getRootSymbols(contextualSymbol)); - }); - /* Because in short-hand property assignment, location has two meaning : property name and as value of the property - * When we do findAllReference at the position of the short-hand property assignment, we would want to have references to position of - * property name and variable declaration of the identifier. - * Like in below example, when querying for all references for an identifier 'name', of the property assignment, the language service - * should show both 'name' in 'obj' and 'name' in variable declaration - * var name = "Foo"; - * var obj = { name }; - * In order to do that, we will populate the search set with the value symbol of the identifier as a value of the property assignment - * so that when matching with potential reference symbol, both symbols from property declaration and variable declaration - * will be included correctly. - */ - var shorthandValueSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(location.parent); - if (shorthandValueSymbol) { - result.push(shorthandValueSymbol); - } - } - // If this is a union property, add all the symbols from all its source symbols in all unioned types. - // If the symbol is an instantiation from a another symbol (e.g. widened symbol) , add the root the list - ts.forEach(typeInfoResolver.getRootSymbols(symbol), function (rootSymbol) { - if (rootSymbol !== symbol) { - result.push(rootSymbol); - } - // Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions - if (rootSymbol.parent && rootSymbol.parent.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Interface)) { - getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result); - } - }); - return result; - } - function getPropertySymbolsFromBaseTypes(symbol, propertyName, result) { - if (symbol && symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Interface)) { - ts.forEach(symbol.getDeclarations(), function (declaration) { - if (declaration.kind === ts.SyntaxKind.ClassDeclaration) { - getPropertySymbolFromTypeReference(ts.getClassBaseTypeNode(declaration)); - ts.forEach(ts.getClassImplementedTypeNodes(declaration), getPropertySymbolFromTypeReference); - } - else if (declaration.kind === ts.SyntaxKind.InterfaceDeclaration) { - ts.forEach(ts.getInterfaceBaseTypeNodes(declaration), getPropertySymbolFromTypeReference); - } - }); - } - return; - function getPropertySymbolFromTypeReference(typeReference) { - if (typeReference) { - var type = typeInfoResolver.getTypeAtLocation(typeReference); - if (type) { - var propertySymbol = typeInfoResolver.getPropertyOfType(type, propertyName); - if (propertySymbol) { - result.push(propertySymbol); - } - // Visit the typeReference as well to see if it directly or indirectly use that property - getPropertySymbolsFromBaseTypes(type.symbol, propertyName, result); - } - } - } - } - function isRelatableToSearchSet(searchSymbols, referenceSymbol, referenceLocation) { - if (searchSymbols.indexOf(referenceSymbol) >= 0) { - return true; - } - // If the reference location is in an object literal, try to get the contextual type for the - // object literal, lookup the property symbol in the contextual type, and use this symbol to - // compare to our searchSymbol - if (isNameOfPropertyAssignment(referenceLocation)) { - return ts.forEach(getPropertySymbolsFromContextualType(referenceLocation), function (contextualSymbol) { - return ts.forEach(typeInfoResolver.getRootSymbols(contextualSymbol), function (s) { return searchSymbols.indexOf(s) >= 0; }); - }); - } - // Unwrap symbols to get to the root (e.g. transient symbols as a result of widening) - // Or a union property, use its underlying unioned symbols - return ts.forEach(typeInfoResolver.getRootSymbols(referenceSymbol), function (rootSymbol) { - // if it is in the list, then we are done - if (searchSymbols.indexOf(rootSymbol) >= 0) { - return true; - } - // Finally, try all properties with the same name in any type the containing type extended or implemented, and - // see if any is in the list - if (rootSymbol.parent && rootSymbol.parent.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Interface)) { - var result = []; - getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result); - return ts.forEach(result, function (s) { return searchSymbols.indexOf(s) >= 0; }); - } - return false; - }); - } - function getPropertySymbolsFromContextualType(node) { - if (isNameOfPropertyAssignment(node)) { - var objectLiteral = node.parent.parent; - var contextualType = typeInfoResolver.getContextualType(objectLiteral); - var name = node.text; - if (contextualType) { - if (contextualType.flags & ts.TypeFlags.Union) { - // This is a union type, first see if the property we are looking for is a union property (i.e. exists in all types) - // if not, search the constituent types for the property - var unionProperty = contextualType.getProperty(name); - if (unionProperty) { - return [unionProperty]; - } - else { - var result = []; - ts.forEach(contextualType.types, function (t) { - var symbol = t.getProperty(name); - if (symbol) { - result.push(symbol); - } - }); - return result; - } - } - else { - var symbol = contextualType.getProperty(name); - if (symbol) { - return [symbol]; - } - } - } - } - return undefined; - } - /** Given an initial searchMeaning, extracted from a location, widen the search scope based on the declarations - * of the corresponding symbol. e.g. if we are searching for "Foo" in value position, but "Foo" references a class - * then we need to widen the search to include type positions as well. - * On the contrary, if we are searching for "Bar" in type position and we trace bar to an interface, and an uninstantiated - * module, we want to keep the search limited to only types, as the two declarations (interface and uninstantiated module) - * do not intersect in any of the three spaces. - */ - function getIntersectingMeaningFromDeclarations(meaning, declarations) { - if (declarations) { - do { - // The result is order-sensitive, for instance if initialMeaning === Namespace, and declarations = [class, instantiated module] - // we need to consider both as they initialMeaning intersects with the module in the namespace space, and the module - // intersects with the class in the value space. - // To achieve that we will keep iterating until the result stabilizes. - // Remember the last meaning - var lastIterationMeaning = meaning; - for (var i = 0, n = declarations.length; i < n; i++) { - var declarationMeaning = getMeaningFromDeclaration(declarations[i]); - if (declarationMeaning & meaning) { - meaning |= declarationMeaning; - } - } - } while (meaning !== lastIterationMeaning); - } - return meaning; - } - } - function getReferenceEntryFromNode(node) { - var start = node.getStart(); - var end = node.getEnd(); - if (node.kind === ts.SyntaxKind.StringLiteral) { - start += 1; - end -= 1; - } - return { - fileName: node.getSourceFile().filename, - textSpan: ts.createTextSpanFromBounds(start, end), - isWriteAccess: isWriteAccess(node) - }; - } - /** A node is considered a writeAccess iff it is a name of a declaration or a target of an assignment */ - function isWriteAccess(node) { - if (node.kind === ts.SyntaxKind.Identifier && ts.isDeclarationOrFunctionExpressionOrCatchVariableName(node)) { - return true; - } - var parent = node.parent; - if (parent) { - if (parent.kind === ts.SyntaxKind.PostfixUnaryExpression || parent.kind === ts.SyntaxKind.PrefixUnaryExpression) { - return true; - } - else if (parent.kind === ts.SyntaxKind.BinaryExpression && parent.left === node) { - var operator = parent.operator; - return ts.SyntaxKind.FirstAssignment <= operator && operator <= ts.SyntaxKind.LastAssignment; - } - } - return false; - } - /// NavigateTo - function getNavigateToItems(searchValue) { - synchronizeHostData(); - // Split search value in terms array - var terms = searchValue.split(" "); - // default NavigateTo approach: if search term contains only lower-case chars - use case-insensitive search, otherwise switch to case-sensitive version - var searchTerms = ts.map(terms, function (t) { return ({ caseSensitive: hasAnyUpperCaseCharacter(t), term: t }); }); - var items = []; - // Search the declarations in all files and output matched NavigateToItem into array of NavigateToItem[] - ts.forEach(program.getSourceFiles(), function (sourceFile) { - cancellationToken.throwIfCancellationRequested(); - var filename = sourceFile.filename; - var declarations = sourceFile.getNamedDeclarations(); - for (var i = 0, n = declarations.length; i < n; i++) { - var declaration = declarations[i]; - // TODO(jfreeman): Skip this declaration if it has a computed name - var name = declaration.name.text; - var matchKind = getMatchKind(searchTerms, name); - if (matchKind !== 0 /* none */) { - var container = getContainerNode(declaration); - items.push({ - name: name, - kind: getNodeKind(declaration), - kindModifiers: ts.getNodeModifiers(declaration), - matchKind: MatchKind[matchKind], - fileName: filename, - textSpan: ts.createTextSpanFromBounds(declaration.getStart(), declaration.getEnd()), - // TODO(jfreeman): What should be the containerName when the container has a computed name? - containerName: container && container.name ? container.name.text : "", - containerKind: container && container.name ? getNodeKind(container) : "" - }); - } - } - }); - return items; - function hasAnyUpperCaseCharacter(s) { - for (var i = 0, n = s.length; i < n; i++) { - var c = s.charCodeAt(i); - if ((ts.CharacterCodes.A <= c && c <= ts.CharacterCodes.Z) || (c >= ts.CharacterCodes.maxAsciiCharacter && s.charAt(i).toLocaleLowerCase() !== s.charAt(i))) { - return true; - } - } - return false; - } - function getMatchKind(searchTerms, name) { - var matchKind = 0 /* none */; - if (name) { - for (var j = 0, n = searchTerms.length; j < n; j++) { - var searchTerm = searchTerms[j]; - var nameToSearch = searchTerm.caseSensitive ? name : name.toLocaleLowerCase(); - // in case of case-insensitive search searchTerm.term will already be lower-cased - var index = nameToSearch.indexOf(searchTerm.term); - if (index < 0) { - // Didn't match. - return 0 /* none */; - } - var termKind = 2 /* substring */; - if (index === 0) { - // here we know that match occur at the beginning of the string. - // if search term and declName has the same length - we have an exact match, otherwise declName have longer length and this will be prefix match - termKind = name.length === searchTerm.term.length ? 1 /* exact */ : 3 /* prefix */; - } - // Update our match kind if we don't have one, or if this match is better. - if (matchKind === 0 /* none */ || termKind < matchKind) { - matchKind = termKind; - } - } - } - return matchKind; - } - } - function containErrors(diagnostics) { - return ts.forEach(diagnostics, function (diagnostic) { return diagnostic.category === ts.DiagnosticCategory.Error; }); - } - function getEmitOutput(filename) { - synchronizeHostData(); - filename = ts.normalizeSlashes(filename); - var sourceFile = getSourceFile(filename); - var outputFiles = []; - function writeFile(filename, data, writeByteOrderMark) { - outputFiles.push({ - name: filename, - writeByteOrderMark: writeByteOrderMark, - text: data - }); - } - // Get an emit host from our program, but override the writeFile functionality to - // call our local writer function. - var emitHost = ts.createEmitHostFromProgram(program); - emitHost.writeFile = writeFile; - var emitOutput = ts.emitFiles(getDiagnosticsProducingTypeChecker().getEmitResolver(), emitHost, sourceFile); - return { - outputFiles, - emitOutputStatus: emitOutput.emitResultStatus - }; - } - function getMeaningFromDeclaration(node) { - switch (node.kind) { - case ts.SyntaxKind.Parameter: - case ts.SyntaxKind.VariableDeclaration: - case ts.SyntaxKind.BindingElement: - case ts.SyntaxKind.PropertyDeclaration: - case ts.SyntaxKind.PropertySignature: - case ts.SyntaxKind.PropertyAssignment: - case ts.SyntaxKind.ShorthandPropertyAssignment: - case ts.SyntaxKind.EnumMember: - case ts.SyntaxKind.MethodDeclaration: - case ts.SyntaxKind.MethodSignature: - case ts.SyntaxKind.Constructor: - case ts.SyntaxKind.GetAccessor: - case ts.SyntaxKind.SetAccessor: - case ts.SyntaxKind.FunctionDeclaration: - case ts.SyntaxKind.FunctionExpression: - case ts.SyntaxKind.ArrowFunction: - case ts.SyntaxKind.CatchClause: - return 1 /* Value */; - case ts.SyntaxKind.TypeParameter: - case ts.SyntaxKind.InterfaceDeclaration: - case ts.SyntaxKind.TypeAliasDeclaration: - case ts.SyntaxKind.TypeLiteral: - return 2 /* Type */; - case ts.SyntaxKind.ClassDeclaration: - case ts.SyntaxKind.EnumDeclaration: - return 1 /* Value */ | 2 /* Type */; - case ts.SyntaxKind.ModuleDeclaration: - if (node.name.kind === ts.SyntaxKind.StringLiteral) { - return 4 /* Namespace */ | 1 /* Value */; - } - else if (ts.getModuleInstanceState(node) === ts.ModuleInstanceState.Instantiated) { - return 4 /* Namespace */ | 1 /* Value */; - } - else { - return 4 /* Namespace */; - } - case ts.SyntaxKind.ImportDeclaration: - return 1 /* Value */ | 2 /* Type */ | 4 /* Namespace */; - case ts.SyntaxKind.SourceFile: - return 4 /* Namespace */ | 1 /* Value */; - } - ts.Debug.fail("Unknown declaration type"); - } - function isTypeReference(node) { - if (isRightSideOfQualifiedName(node)) { - node = node.parent; - } - return node.parent.kind === ts.SyntaxKind.TypeReference; - } - function isNamespaceReference(node) { - var root = node; - var isLastClause = true; - if (root.parent.kind === ts.SyntaxKind.QualifiedName) { - while (root.parent && root.parent.kind === ts.SyntaxKind.QualifiedName) - root = root.parent; - isLastClause = root.right === node; - } - return root.parent.kind === ts.SyntaxKind.TypeReference && !isLastClause; - } - function isInRightSideOfImport(node) { - while (node.parent.kind === ts.SyntaxKind.QualifiedName) { - node = node.parent; - } - return ts.isInternalModuleImportDeclaration(node.parent) && node.parent.moduleReference === node; - } - function getMeaningFromRightHandSideOfImport(node) { - ts.Debug.assert(node.kind === ts.SyntaxKind.Identifier); - // import a = |b|; // Namespace - // import a = |b.c|; // Value, type, namespace - // import a = |b.c|.d; // Namespace - if (node.parent.kind === ts.SyntaxKind.QualifiedName && node.parent.right === node && node.parent.parent.kind === ts.SyntaxKind.ImportDeclaration) { - return 1 /* Value */ | 2 /* Type */ | 4 /* Namespace */; - } - return 4 /* Namespace */; - } - function getMeaningFromLocation(node) { - if (node.parent.kind === ts.SyntaxKind.ExportAssignment) { - return 1 /* Value */ | 2 /* Type */ | 4 /* Namespace */; - } - else if (isInRightSideOfImport(node)) { - return getMeaningFromRightHandSideOfImport(node); - } - else if (ts.isDeclarationOrFunctionExpressionOrCatchVariableName(node)) { - return getMeaningFromDeclaration(node.parent); - } - else if (isTypeReference(node)) { - return 2 /* Type */; - } - else if (isNamespaceReference(node)) { - return 4 /* Namespace */; - } - else { - return 1 /* Value */; - } - } - // Signature help - /** - * This is a semantic operation. - */ - function getSignatureHelpItems(fileName, position) { - synchronizeHostData(); - fileName = ts.normalizeSlashes(fileName); - var sourceFile = getSourceFile(fileName); - return ts.SignatureHelp.getSignatureHelpItems(sourceFile, position, typeInfoResolver, cancellationToken); - } - /// Syntactic features - function getCurrentSourceFile(filename) { - filename = ts.normalizeSlashes(filename); - var currentSourceFile = syntaxTreeCache.getCurrentSourceFile(filename); - return currentSourceFile; - } - function getNameOrDottedNameSpan(filename, startPos, endPos) { - filename = ts.normalizeSlashes(filename); - // Get node at the location - var node = ts.getTouchingPropertyName(getCurrentSourceFile(filename), startPos); - if (!node) { - return; - } - switch (node.kind) { - case ts.SyntaxKind.PropertyAccessExpression: - case ts.SyntaxKind.QualifiedName: - case ts.SyntaxKind.StringLiteral: - case ts.SyntaxKind.FalseKeyword: - case ts.SyntaxKind.TrueKeyword: - case ts.SyntaxKind.NullKeyword: - case ts.SyntaxKind.SuperKeyword: - case ts.SyntaxKind.ThisKeyword: - case ts.SyntaxKind.Identifier: - break; - default: - return; - } - var nodeForStartPos = node; - while (true) { - if (isRightSideOfPropertyAccess(nodeForStartPos) || isRightSideOfQualifiedName(nodeForStartPos)) { - // If on the span is in right side of the the property or qualified name, return the span from the qualified name pos to end of this node - nodeForStartPos = nodeForStartPos.parent; - } - else if (isNameOfModuleDeclaration(nodeForStartPos)) { - // If this is name of a module declarations, check if this is right side of dotted module name - // If parent of the module declaration which is parent of this node is module declaration and its body is the module declaration that this node is name of - // Then this name is name from dotted module - if (nodeForStartPos.parent.parent.kind === ts.SyntaxKind.ModuleDeclaration && nodeForStartPos.parent.parent.body === nodeForStartPos.parent) { - // Use parent module declarations name for start pos - nodeForStartPos = nodeForStartPos.parent.parent.name; - } - else { - break; - } - } - else { - break; - } - } - return ts.createTextSpanFromBounds(nodeForStartPos.getStart(), node.getEnd()); - } - function getBreakpointStatementAtPosition(filename, position) { - // doesn't use compiler - no need to synchronize with host - filename = ts.normalizeSlashes(filename); - return ts.BreakpointResolver.spanInSourceFileAtLocation(getCurrentSourceFile(filename), position); - } - function getNavigationBarItems(filename) { - filename = ts.normalizeSlashes(filename); - return ts.NavigationBar.getNavigationBarItems(getCurrentSourceFile(filename)); - } - function getSemanticClassifications(fileName, span) { - synchronizeHostData(); - fileName = ts.normalizeSlashes(fileName); - var sourceFile = getSourceFile(fileName); - var result = []; - processNode(sourceFile); - return result; - function classifySymbol(symbol, meaningAtPosition) { - var flags = symbol.getFlags(); - if (flags & ts.SymbolFlags.Class) { - return ClassificationTypeNames.className; - } - else if (flags & ts.SymbolFlags.Enum) { - return ClassificationTypeNames.enumName; - } - else if (flags & ts.SymbolFlags.TypeAlias) { - return ClassificationTypeNames.typeAlias; - } - else if (meaningAtPosition & 2 /* Type */) { - if (flags & ts.SymbolFlags.Interface) { - return ClassificationTypeNames.interfaceName; - } - else if (flags & ts.SymbolFlags.TypeParameter) { - return ClassificationTypeNames.typeParameterName; - } - } - else if (flags & ts.SymbolFlags.Module) { - // Only classify a module as such if - // - It appears in a namespace context. - // - There exists a module declaration which actually impacts the value side. - if (meaningAtPosition & 4 /* Namespace */ || (meaningAtPosition & 1 /* Value */ && hasValueSideModule(symbol))) { - return ClassificationTypeNames.moduleName; - } - } - return undefined; - /** - * Returns true if there exists a module that introduces entities on the value side. - */ - function hasValueSideModule(symbol) { - return ts.forEach(symbol.declarations, function (declaration) { - return declaration.kind === ts.SyntaxKind.ModuleDeclaration && ts.getModuleInstanceState(declaration) == ts.ModuleInstanceState.Instantiated; - }); - } - } - function processNode(node) { - // Only walk into nodes that intersect the requested span. - if (node && ts.textSpanIntersectsWith(span, node.getStart(), node.getWidth())) { - if (node.kind === ts.SyntaxKind.Identifier && node.getWidth() > 0) { - var symbol = typeInfoResolver.getSymbolAtLocation(node); - if (symbol) { - var type = classifySymbol(symbol, getMeaningFromLocation(node)); - if (type) { - result.push({ - textSpan: ts.createTextSpan(node.getStart(), node.getWidth()), - classificationType: type - }); - } - } - } - ts.forEachChild(node, processNode); - } - } - } - function getSyntacticClassifications(fileName, span) { - // doesn't use compiler - no need to synchronize with host - fileName = ts.normalizeSlashes(fileName); - var sourceFile = getCurrentSourceFile(fileName); - // Make a scanner we can get trivia from. - var triviaScanner = ts.createScanner(ts.ScriptTarget.Latest, false, sourceFile.text); - var mergeConflictScanner = ts.createScanner(ts.ScriptTarget.Latest, false, sourceFile.text); - var result = []; - processElement(sourceFile); - return result; - function classifyLeadingTrivia(token) { - var tokenStart = ts.skipTrivia(sourceFile.text, token.pos, false); - if (tokenStart === token.pos) { - return; - } - // token has trivia. Classify them appropriately. - triviaScanner.setTextPos(token.pos); - while (true) { - var start = triviaScanner.getTextPos(); - var kind = triviaScanner.scan(); - var end = triviaScanner.getTextPos(); - var width = end - start; - if (ts.textSpanIntersectsWith(span, start, width)) { - if (!ts.isTrivia(kind)) { - return; - } - if (ts.isComment(kind)) { - // Simple comment. Just add as is. - result.push({ - textSpan: ts.createTextSpan(start, width), - classificationType: ClassificationTypeNames.comment - }); - continue; - } - if (kind === ts.SyntaxKind.ConflictMarkerTrivia) { - var text = sourceFile.text; - var ch = text.charCodeAt(start); - // for the <<<<<<< and >>>>>>> markers, we just add them in as comments - // in the classification stream. - if (ch === ts.CharacterCodes.lessThan || ch === ts.CharacterCodes.greaterThan) { - result.push({ - textSpan: ts.createTextSpan(start, width), - classificationType: ClassificationTypeNames.comment - }); - continue; - } - // for the ======== add a comment for the first line, and then lex all - // subsequent lines up until the end of the conflict marker. - ts.Debug.assert(ch === ts.CharacterCodes.equals); - classifyDisabledMergeCode(text, start, end); - } - } - } - } - function classifyDisabledMergeCode(text, start, end) { - for (var i = start; i < end; i++) { - if (ts.isLineBreak(text.charCodeAt(i))) { - break; - } - } - result.push({ - textSpan: ts.createTextSpanFromBounds(start, i), - classificationType: ClassificationTypeNames.comment - }); - mergeConflictScanner.setTextPos(i); - while (mergeConflictScanner.getTextPos() < end) { - classifyDisabledCodeToken(); - } - } - function classifyDisabledCodeToken() { - var start = mergeConflictScanner.getTextPos(); - var tokenKind = mergeConflictScanner.scan(); - var end = mergeConflictScanner.getTextPos(); - var type = classifyTokenType(tokenKind); - if (type) { - result.push({ - textSpan: ts.createTextSpanFromBounds(start, end), - classificationType: type - }); - } - } - function classifyToken(token) { - classifyLeadingTrivia(token); - if (token.getWidth() > 0) { - var type = classifyTokenType(token.kind, token); - if (type) { - result.push({ - textSpan: ts.createTextSpan(token.getStart(), token.getWidth()), - classificationType: type - }); - } - } - } - // for accurate classification, the actual token should be passed in. however, for - // cases like 'disabled merge code' classification, we just get the token kind and - // classify based on that instead. - function classifyTokenType(tokenKind, token) { - if (ts.isKeyword(tokenKind)) { - return ClassificationTypeNames.keyword; - } - // Special case < and > If they appear in a generic context they are punctuation, - // not operators. - if (tokenKind === ts.SyntaxKind.LessThanToken || tokenKind === ts.SyntaxKind.GreaterThanToken) { - // If the node owning the token has a type argument list or type parameter list, then - // we can effectively assume that a '<' and '>' belong to those lists. - if (token && ts.getTypeArgumentOrTypeParameterList(token.parent)) { - return ClassificationTypeNames.punctuation; - } - } - if (ts.isPunctuation(tokenKind)) { - if (token) { - if (tokenKind === ts.SyntaxKind.EqualsToken) { - // the '=' in a variable declaration is special cased here. - if (token.parent.kind === ts.SyntaxKind.VariableDeclaration || token.parent.kind === ts.SyntaxKind.PropertyDeclaration || token.parent.kind === ts.SyntaxKind.Parameter) { - return ClassificationTypeNames.operator; - } - } - if (token.parent.kind === ts.SyntaxKind.BinaryExpression || token.parent.kind === ts.SyntaxKind.PrefixUnaryExpression || token.parent.kind === ts.SyntaxKind.PostfixUnaryExpression || token.parent.kind === ts.SyntaxKind.ConditionalExpression) { - return ClassificationTypeNames.operator; - } - } - return ClassificationTypeNames.punctuation; - } - else if (tokenKind === ts.SyntaxKind.NumericLiteral) { - return ClassificationTypeNames.numericLiteral; - } - else if (tokenKind === ts.SyntaxKind.StringLiteral) { - return ClassificationTypeNames.stringLiteral; - } - else if (tokenKind === ts.SyntaxKind.RegularExpressionLiteral) { - // TODO: we should get another classification type for these literals. - return ClassificationTypeNames.stringLiteral; - } - else if (ts.isTemplateLiteralKind(tokenKind)) { - // TODO (drosen): we should *also* get another classification type for these literals. - return ClassificationTypeNames.stringLiteral; - } - else if (tokenKind === ts.SyntaxKind.Identifier) { - if (token) { - switch (token.parent.kind) { - case ts.SyntaxKind.ClassDeclaration: - if (token.parent.name === token) { - return ClassificationTypeNames.className; - } - return; - case ts.SyntaxKind.TypeParameter: - if (token.parent.name === token) { - return ClassificationTypeNames.typeParameterName; - } - return; - case ts.SyntaxKind.InterfaceDeclaration: - if (token.parent.name === token) { - return ClassificationTypeNames.interfaceName; - } - return; - case ts.SyntaxKind.EnumDeclaration: - if (token.parent.name === token) { - return ClassificationTypeNames.enumName; - } - return; - case ts.SyntaxKind.ModuleDeclaration: - if (token.parent.name === token) { - return ClassificationTypeNames.moduleName; - } - return; - } - } - return ClassificationTypeNames.text; - } - } - function processElement(element) { - // Ignore nodes that don't intersect the original span to classify. - if (ts.textSpanIntersectsWith(span, element.getFullStart(), element.getFullWidth())) { - var children = element.getChildren(); - for (var i = 0, n = children.length; i < n; i++) { - var child = children[i]; - if (ts.isToken(child)) { - classifyToken(child); - } - else { - // Recurse into our child nodes. - processElement(child); - } - } - } - } - } - function getOutliningSpans(filename) { - // doesn't use compiler - no need to synchronize with host - filename = ts.normalizeSlashes(filename); - var sourceFile = getCurrentSourceFile(filename); - return ts.OutliningElementsCollector.collectElements(sourceFile); - } - function getBraceMatchingAtPosition(filename, position) { - var sourceFile = getCurrentSourceFile(filename); - var result = []; - var token = ts.getTouchingToken(sourceFile, position); - if (token.getStart(sourceFile) === position) { - var matchKind = getMatchingTokenKind(token); - // Ensure that there is a corresponding token to match ours. - if (matchKind) { - var parentElement = token.parent; - var childNodes = parentElement.getChildren(sourceFile); - for (var i = 0, n = childNodes.length; i < n; i++) { - 33; - var current = childNodes[i]; - if (current.kind === matchKind) { - var range1 = ts.createTextSpan(token.getStart(sourceFile), token.getWidth(sourceFile)); - var range2 = ts.createTextSpan(current.getStart(sourceFile), current.getWidth(sourceFile)); - // We want to order the braces when we return the result. - if (range1.start < range2.start) { - result.push(range1, range2); - } - else { - result.push(range2, range1); - } - break; - } - } - } - } - return result; - function getMatchingTokenKind(token) { - switch (token.kind) { - case ts.SyntaxKind.OpenBraceToken: return ts.SyntaxKind.CloseBraceToken; - case ts.SyntaxKind.OpenParenToken: return ts.SyntaxKind.CloseParenToken; - case ts.SyntaxKind.OpenBracketToken: return ts.SyntaxKind.CloseBracketToken; - case ts.SyntaxKind.LessThanToken: return ts.SyntaxKind.GreaterThanToken; - case ts.SyntaxKind.CloseBraceToken: return ts.SyntaxKind.OpenBraceToken; - case ts.SyntaxKind.CloseParenToken: return ts.SyntaxKind.OpenParenToken; - case ts.SyntaxKind.CloseBracketToken: return ts.SyntaxKind.OpenBracketToken; - case ts.SyntaxKind.GreaterThanToken: return ts.SyntaxKind.LessThanToken; - } - return undefined; - } - } - function getIndentationAtPosition(filename, position, editorOptions) { - filename = ts.normalizeSlashes(filename); - var start = new Date().getTime(); - var sourceFile = getCurrentSourceFile(filename); - log("getIndentationAtPosition: getCurrentSourceFile: " + (new Date().getTime() - start)); - var start = new Date().getTime(); - var result = ts.formatting.SmartIndenter.getIndentation(position, sourceFile, editorOptions); - log("getIndentationAtPosition: computeIndentation : " + (new Date().getTime() - start)); - return result; - } - function getFormattingEditsForRange(fileName, start, end, options) { - fileName = ts.normalizeSlashes(fileName); - var sourceFile = getCurrentSourceFile(fileName); - return ts.formatting.formatSelection(start, end, sourceFile, getRuleProvider(options), options); - } - function getFormattingEditsForDocument(fileName, options) { - fileName = ts.normalizeSlashes(fileName); - var sourceFile = getCurrentSourceFile(fileName); - return ts.formatting.formatDocument(sourceFile, getRuleProvider(options), options); - } - function getFormattingEditsAfterKeystroke(fileName, position, key, options) { - fileName = ts.normalizeSlashes(fileName); - var sourceFile = getCurrentSourceFile(fileName); - if (key === "}") { - return ts.formatting.formatOnClosingCurly(position, sourceFile, getRuleProvider(options), options); - } - else if (key === ";") { - return ts.formatting.formatOnSemicolon(position, sourceFile, getRuleProvider(options), options); - } - else if (key === "\n") { - return ts.formatting.formatOnEnter(position, sourceFile, getRuleProvider(options), options); - } - return []; - } - function getTodoComments(filename, descriptors) { - // Note: while getting todo comments seems like a syntactic operation, we actually - // treat it as a semantic operation here. This is because we expect our host to call - // this on every single file. If we treat this syntactically, then that will cause - // us to populate and throw away the tree in our syntax tree cache for each file. By - // treating this as a semantic operation, we can access any tree without throwing - // anything away. - synchronizeHostData(); - filename = ts.normalizeSlashes(filename); - var sourceFile = getSourceFile(filename); - cancellationToken.throwIfCancellationRequested(); - var fileContents = sourceFile.text; - cancellationToken.throwIfCancellationRequested(); - var result = []; - if (descriptors.length > 0) { - var regExp = getTodoCommentsRegExp(); - var matchArray; - while (matchArray = regExp.exec(fileContents)) { - cancellationToken.throwIfCancellationRequested(); - // If we got a match, here is what the match array will look like. Say the source text is: - // - // " // hack 1" - // - // The result array with the regexp: will be: - // - // ["// hack 1", "// ", "hack 1", undefined, "hack"] - // - // Here are the relevant capture groups: - // 0) The full match for the entire regexp. - // 1) The preamble to the message portion. - // 2) The message portion. - // 3...N) The descriptor that was matched - by index. 'undefined' for each - // descriptor that didn't match. an actual value if it did match. - // - // i.e. 'undefined' in position 3 above means TODO(jason) didn't match. - // "hack" in position 4 means HACK did match. - var firstDescriptorCaptureIndex = 3; - ts.Debug.assert(matchArray.length === descriptors.length + firstDescriptorCaptureIndex); - var preamble = matchArray[1]; - var matchPosition = matchArray.index + preamble.length; - // OK, we have found a match in the file. This is only an acceptable match if - // it is contained within a comment. - var token = ts.getTokenAtPosition(sourceFile, matchPosition); - if (!isInsideComment(sourceFile, token, matchPosition)) { - continue; - } - var descriptor = undefined; - for (var i = 0, n = descriptors.length; i < n; i++) { - if (matchArray[i + firstDescriptorCaptureIndex]) { - descriptor = descriptors[i]; - } - } - ts.Debug.assert(descriptor !== undefined); - // We don't want to match something like 'TODOBY', so we make sure a non - // letter/digit follows the match. - if (isLetterOrDigit(fileContents.charCodeAt(matchPosition + descriptor.text.length))) { - continue; - } - var message = matchArray[2]; - result.push({ - descriptor: descriptor, - message: message, - position: matchPosition - }); - } - } - return result; - function escapeRegExp(str) { - return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); - } - function getTodoCommentsRegExp() { - // NOTE: ?: means 'non-capture group'. It allows us to have groups without having to - // filter them out later in the final result array. - // TODO comments can appear in one of the following forms: - // - // 1) // TODO or /////////// TODO - // - // 2) /* TODO or /********** TODO - // - // 3) /* - // * TODO - // */ - // - // The following three regexps are used to match the start of the text up to the TODO - // comment portion. - var singleLineCommentStart = /(?:\/\/+\s*)/.source; - var multiLineCommentStart = /(?:\/\*+\s*)/.source; - var anyNumberOfSpacesAndAsterixesAtStartOfLine = /(?:^(?:\s|\*)*)/.source; - // Match any of the above three TODO comment start regexps. - // Note that the outermost group *is* a capture group. We want to capture the preamble - // so that we can determine the starting position of the TODO comment match. - var preamble = "(" + anyNumberOfSpacesAndAsterixesAtStartOfLine + "|" + singleLineCommentStart + "|" + multiLineCommentStart + ")"; - // Takes the descriptors and forms a regexp that matches them as if they were literals. - // For example, if the descriptors are "TODO(jason)" and "HACK", then this will be: - // - // (?:(TODO\(jason\))|(HACK)) - // - // Note that the outermost group is *not* a capture group, but the innermost groups - // *are* capture groups. By capturing the inner literals we can determine after - // matching which descriptor we are dealing with. - var literals = "(?:" + ts.map(descriptors, function (d) { return "(" + escapeRegExp(d.text) + ")"; }).join("|") + ")"; - // After matching a descriptor literal, the following regexp matches the rest of the - // text up to the end of the line (or */). - var endOfLineOrEndOfComment = /(?:$|\*\/)/.source; - var messageRemainder = /(?:.*?)/.source; - // This is the portion of the match we'll return as part of the TODO comment result. We - // match the literal portion up to the end of the line or end of comment. - var messagePortion = "(" + literals + messageRemainder + ")"; - var regExpString = preamble + messagePortion + endOfLineOrEndOfComment; - // The final regexp will look like this: - // /((?:\/\/+\s*)|(?:\/\*+\s*)|(?:^(?:\s|\*)*))((?:(TODO\(jason\))|(HACK))(?:.*?))(?:$|\*\/)/gim - // The flags of the regexp are important here. - // 'g' is so that we are doing a global search and can find matches several times - // in the input. - // - // 'i' is for case insensitivity (We do this to match C# TODO comment code). - // - // 'm' is so we can find matches in a multi-line input. - return new RegExp(regExpString, "gim"); - } - function isLetterOrDigit(char) { - return (char >= ts.CharacterCodes.a && char <= ts.CharacterCodes.z) || (char >= ts.CharacterCodes.A && char <= ts.CharacterCodes.Z) || (char >= ts.CharacterCodes._0 && char <= ts.CharacterCodes._9); - } - } - function getRenameInfo(fileName, position) { - synchronizeHostData(); - fileName = ts.normalizeSlashes(fileName); - var sourceFile = getSourceFile(fileName); - var node = ts.getTouchingWord(sourceFile, position); - // Can only rename an identifier. - if (node && node.kind === ts.SyntaxKind.Identifier) { - var symbol = typeInfoResolver.getSymbolAtLocation(node); - // Only allow a symbol to be renamed if it actually has at least one declaration. - if (symbol && symbol.getDeclarations() && symbol.getDeclarations().length > 0) { - var kind = getSymbolKind(symbol, typeInfoResolver, node); - if (kind) { - return getRenameInfo(symbol.name, typeInfoResolver.getFullyQualifiedName(symbol), kind, getSymbolModifiers(symbol), ts.createTextSpan(node.getStart(), node.getWidth())); - } - } - } - return getRenameInfoError(ts.getLocaleSpecificMessage(ts.Diagnostics.You_cannot_rename_this_element.key)); - function getRenameInfoError(localizedErrorMessage) { - return { - canRename: false, - localizedErrorMessage: ts.getLocaleSpecificMessage(ts.Diagnostics.You_cannot_rename_this_element.key), - displayName: undefined, - fullDisplayName: undefined, - kind: undefined, - kindModifiers: undefined, - triggerSpan: undefined - }; - } - function getRenameInfo(displayName, fullDisplayName, kind, kindModifiers, triggerSpan) { - return { - canRename: true, - localizedErrorMessage: undefined, - displayName, - fullDisplayName, - kind, - kindModifiers, - triggerSpan - }; - } - } - return { - dispose, - cleanupSemanticCache, - getSyntacticDiagnostics, - getSemanticDiagnostics, - getCompilerOptionsDiagnostics, - getSyntacticClassifications, - getSemanticClassifications, - getCompletionsAtPosition, - getCompletionEntryDetails, - getSignatureHelpItems, - getQuickInfoAtPosition, - getDefinitionAtPosition, - getReferencesAtPosition, - getOccurrencesAtPosition, - getNameOrDottedNameSpan, - getBreakpointStatementAtPosition, - getNavigateToItems, - getRenameInfo, - findRenameLocations, - getNavigationBarItems, - getOutliningSpans, - getTodoComments, - getBraceMatchingAtPosition, - getIndentationAtPosition, - getFormattingEditsForRange, - getFormattingEditsForDocument, - getFormattingEditsAfterKeystroke, - getEmitOutput, - getSourceFile: getCurrentSourceFile, - }; - } - ts.createLanguageService = createLanguageService; - /// Classifier - function createClassifier() { - var scanner = ts.createScanner(ts.ScriptTarget.Latest, false); - /// We do not have a full parser support to know when we should parse a regex or not - /// If we consider every slash token to be a regex, we could be missing cases like "1/2/3", where - /// we have a series of divide operator. this list allows us to be more accurate by ruling out - /// locations where a regexp cannot exist. - var noRegexTable = []; - noRegexTable[ts.SyntaxKind.Identifier] = true; - noRegexTable[ts.SyntaxKind.StringLiteral] = true; - noRegexTable[ts.SyntaxKind.NumericLiteral] = true; - noRegexTable[ts.SyntaxKind.RegularExpressionLiteral] = true; - noRegexTable[ts.SyntaxKind.ThisKeyword] = true; - noRegexTable[ts.SyntaxKind.PlusPlusToken] = true; - noRegexTable[ts.SyntaxKind.MinusMinusToken] = true; - noRegexTable[ts.SyntaxKind.CloseParenToken] = true; - noRegexTable[ts.SyntaxKind.CloseBracketToken] = true; - noRegexTable[ts.SyntaxKind.CloseBraceToken] = true; - noRegexTable[ts.SyntaxKind.TrueKeyword] = true; - noRegexTable[ts.SyntaxKind.FalseKeyword] = true; - function isAccessibilityModifier(kind) { - switch (kind) { - case ts.SyntaxKind.PublicKeyword: - case ts.SyntaxKind.PrivateKeyword: - case ts.SyntaxKind.ProtectedKeyword: - return true; - } - return false; - } - /** Returns true if 'keyword2' can legally follow 'keyword1' in any language construct. */ - function canFollow(keyword1, keyword2) { - if (isAccessibilityModifier(keyword1)) { - if (keyword2 === ts.SyntaxKind.GetKeyword || keyword2 === ts.SyntaxKind.SetKeyword || keyword2 === ts.SyntaxKind.ConstructorKeyword || keyword2 === ts.SyntaxKind.StaticKeyword) { - // Allow things like "public get", "public constructor" and "public static". - // These are all legal. - return true; - } - // Any other keyword following "public" is actually an identifier an not a real - // keyword. - return false; - } - // Assume any other keyword combination is legal. This can be refined in the future - // if there are more cases we want the classifier to be better at. - return true; - } - // 'classifyKeywordsInGenerics' should be 'true' when a syntactic classifier is not present. - function getClassificationsForLine(text, lexState, classifyKeywordsInGenerics) { - var offset = 0; - var token = ts.SyntaxKind.Unknown; - var lastNonTriviaToken = ts.SyntaxKind.Unknown; - switch (lexState) { - case 3 /* InDoubleQuoteStringLiteral */: - text = '"\\\n' + text; - offset = 3; - break; - case 2 /* InSingleQuoteStringLiteral */: - text = "'\\\n" + text; - offset = 3; - break; - case 1 /* InMultiLineCommentTrivia */: - text = "/*\n" + text; - offset = 3; - break; - } - scanner.setText(text); - var result = { - finalLexState: 0 /* Start */, - entries: [] - }; - // We can run into an unfortunate interaction between the lexical and syntactic classifier - // when the user is typing something generic. Consider the case where the user types: - // - // Foo tokens. It's a weak heuristic, but should - // work well enough in practice. - var angleBracketStack = 0; - do { - token = scanner.scan(); - if (!ts.isTrivia(token)) { - if ((token === ts.SyntaxKind.SlashToken || token === ts.SyntaxKind.SlashEqualsToken) && !noRegexTable[lastNonTriviaToken]) { - if (scanner.reScanSlashToken() === ts.SyntaxKind.RegularExpressionLiteral) { - token = ts.SyntaxKind.RegularExpressionLiteral; - } - } - else if (lastNonTriviaToken === ts.SyntaxKind.DotToken && isKeyword(token)) { - token = ts.SyntaxKind.Identifier; - } - else if (isKeyword(lastNonTriviaToken) && isKeyword(token) && !canFollow(lastNonTriviaToken, token)) { - // We have two keywords in a row. Only treat the second as a keyword if - // it's a sequence that could legally occur in the language. Otherwise - // treat it as an identifier. This way, if someone writes "private var" - // we recognize that 'var' is actually an identifier here. - token = ts.SyntaxKind.Identifier; - } - else if (lastNonTriviaToken === ts.SyntaxKind.Identifier && token === ts.SyntaxKind.LessThanToken) { - // Could be the start of something generic. Keep track of that by bumping - // up the current count of generic contexts we may be in. - angleBracketStack++; - } - else if (token === ts.SyntaxKind.GreaterThanToken && angleBracketStack > 0) { - // If we think we're currently in something generic, then mark that that - // generic entity is complete. - angleBracketStack--; - } - else if (token === ts.SyntaxKind.AnyKeyword || token === ts.SyntaxKind.StringKeyword || token === ts.SyntaxKind.NumberKeyword || token === ts.SyntaxKind.BooleanKeyword) { - if (angleBracketStack > 0 && !classifyKeywordsInGenerics) { - // If it looks like we're could be in something generic, don't classify this - // as a keyword. We may just get overwritten by the syntactic classifier, - // causing a noisy experience for the user. - token = ts.SyntaxKind.Identifier; - } - } - lastNonTriviaToken = token; - } - processToken(); - } while (token !== ts.SyntaxKind.EndOfFileToken); - return result; - function processToken() { - var start = scanner.getTokenPos(); - var end = scanner.getTextPos(); - addResult(end - start, classFromKind(token)); - if (end >= text.length) { - if (token === ts.SyntaxKind.StringLiteral) { - // Check to see if we finished up on a multiline string literal. - var tokenText = scanner.getTokenText(); - if (scanner.isUnterminated()) { - var lastCharIndex = tokenText.length - 1; - var numBackslashes = 0; - while (tokenText.charCodeAt(lastCharIndex - numBackslashes) === ts.CharacterCodes.backslash) { - numBackslashes++; - } - // If we have an odd number of backslashes, then the multiline string is unclosed - if (numBackslashes & 1) { - var quoteChar = tokenText.charCodeAt(0); - result.finalLexState = quoteChar === ts.CharacterCodes.doubleQuote ? 3 /* InDoubleQuoteStringLiteral */ : 2 /* InSingleQuoteStringLiteral */; - } - } - } - else if (token === ts.SyntaxKind.MultiLineCommentTrivia) { - // Check to see if the multiline comment was unclosed. - if (scanner.isUnterminated()) { - result.finalLexState = 1 /* InMultiLineCommentTrivia */; - } - } - } - } - function addResult(length, classification) { - if (length > 0) { - // If this is the first classification we're adding to the list, then remove any - // offset we have if we were continuing a construct from the previous line. - if (result.entries.length === 0) { - length -= offset; - } - result.entries.push({ length: length, classification: classification }); - } - } - } - function isBinaryExpressionOperatorToken(token) { - switch (token) { - case ts.SyntaxKind.AsteriskToken: - case ts.SyntaxKind.SlashToken: - case ts.SyntaxKind.PercentToken: - case ts.SyntaxKind.PlusToken: - case ts.SyntaxKind.MinusToken: - case ts.SyntaxKind.LessThanLessThanToken: - case ts.SyntaxKind.GreaterThanGreaterThanToken: - case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: - case ts.SyntaxKind.LessThanToken: - case ts.SyntaxKind.GreaterThanToken: - case ts.SyntaxKind.LessThanEqualsToken: - case ts.SyntaxKind.GreaterThanEqualsToken: - case ts.SyntaxKind.InstanceOfKeyword: - case ts.SyntaxKind.InKeyword: - case ts.SyntaxKind.EqualsEqualsToken: - case ts.SyntaxKind.ExclamationEqualsToken: - case ts.SyntaxKind.EqualsEqualsEqualsToken: - case ts.SyntaxKind.ExclamationEqualsEqualsToken: - case ts.SyntaxKind.AmpersandToken: - case ts.SyntaxKind.CaretToken: - case ts.SyntaxKind.BarToken: - case ts.SyntaxKind.AmpersandAmpersandToken: - case ts.SyntaxKind.BarBarToken: - case ts.SyntaxKind.BarEqualsToken: - case ts.SyntaxKind.AmpersandEqualsToken: - case ts.SyntaxKind.CaretEqualsToken: - case ts.SyntaxKind.LessThanLessThanEqualsToken: - case ts.SyntaxKind.GreaterThanGreaterThanEqualsToken: - case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: - case ts.SyntaxKind.PlusEqualsToken: - case ts.SyntaxKind.MinusEqualsToken: - case ts.SyntaxKind.AsteriskEqualsToken: - case ts.SyntaxKind.SlashEqualsToken: - case ts.SyntaxKind.PercentEqualsToken: - case ts.SyntaxKind.EqualsToken: - case ts.SyntaxKind.CommaToken: - return true; - default: return false; - } - } - function isPrefixUnaryExpressionOperatorToken(token) { - switch (token) { - case ts.SyntaxKind.PlusToken: - case ts.SyntaxKind.MinusToken: - case ts.SyntaxKind.TildeToken: - case ts.SyntaxKind.ExclamationToken: - case ts.SyntaxKind.PlusPlusToken: - case ts.SyntaxKind.MinusMinusToken: - return true; - default: - return false; - } - } - function isKeyword(token) { - return token >= ts.SyntaxKind.FirstKeyword && token <= ts.SyntaxKind.LastKeyword; - } - function classFromKind(token) { - if (isKeyword(token)) { - return 1 /* Keyword */; - } - else if (isBinaryExpressionOperatorToken(token) || isPrefixUnaryExpressionOperatorToken(token)) { - return 2 /* Operator */; - } - else if (token >= ts.SyntaxKind.FirstPunctuation && token <= ts.SyntaxKind.LastPunctuation) { - return 0 /* Punctuation */; - } - switch (token) { - case ts.SyntaxKind.NumericLiteral: - return 6 /* NumberLiteral */; - case ts.SyntaxKind.StringLiteral: - return 7 /* StringLiteral */; - case ts.SyntaxKind.RegularExpressionLiteral: - return 8 /* RegExpLiteral */; - case ts.SyntaxKind.ConflictMarkerTrivia: - case ts.SyntaxKind.MultiLineCommentTrivia: - case ts.SyntaxKind.SingleLineCommentTrivia: - return 3 /* Comment */; - case ts.SyntaxKind.WhitespaceTrivia: - return 4 /* Whitespace */; - case ts.SyntaxKind.Identifier: - default: - return 5 /* Identifier */; - } - } - return { getClassificationsForLine }; - } - ts.createClassifier = createClassifier; - /** - * Get the path of the default library file (lib.d.ts) as distributed with the typescript - * node package. - * The functionality is not supported if the ts module is consumed outside of a node module. - */ - function getDefaultLibraryFilePath(options) { - if (typeof module !== "undefined" && module.exports) { - return __dirname + ts.directorySeparator + ts.getDefaultLibraryFilename(options); - } - throw new Error("getDefaultLibraryFilename is only supported when consumed as a node module. "); - } - ts.getDefaultLibraryFilePath = getDefaultLibraryFilePath; - function initializeServices() { - ts.objectAllocator = { - getNodeConstructor: function (kind) { - function Node() { - } - var proto = kind === ts.SyntaxKind.SourceFile ? new SourceFileObject() : new NodeObject(); - proto.kind = kind; - proto.pos = 0; - proto.end = 0; - proto.flags = 0; - proto.parent = undefined; - Node.prototype = proto; - return Node; - }, - getSymbolConstructor: function () { return SymbolObject; }, - getTypeConstructor: function () { return TypeObject; }, - getSignatureConstructor: function () { return SignatureObject; }, - }; - } - initializeServices(); -})(ts || (ts = {}));