mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Merge pull request #708 from Microsoft/classifiedQuickInfo
Initial work on classified quick info.
This commit is contained in:
commit
8be8e1f5be
@ -23,6 +23,28 @@ module ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
interface SymbolWriter {
|
||||
writeKind(text: string, kind: SymbolDisplayPartKind): void;
|
||||
writeSymbol(text: string, symbol: Symbol): void;
|
||||
writeLine(): void;
|
||||
increaseIndent(): void;
|
||||
decreaseIndent(): void;
|
||||
clear(): void;
|
||||
|
||||
// Called when the symbol writer encounters a symbol to write. Currently only used by the
|
||||
// declaration emitter to help determine if it should patch up the final declaration file
|
||||
// with import statements it previously saw (but chose not to emit).
|
||||
trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void;
|
||||
}
|
||||
|
||||
interface DisplayPartsSymbolWriter extends SymbolWriter {
|
||||
displayParts(): SymbolDisplayPart[];
|
||||
}
|
||||
|
||||
interface StringSymbolWriter extends SymbolWriter {
|
||||
string(): string;
|
||||
}
|
||||
|
||||
/// fullTypeCheck denotes if this instance of the typechecker will be used to get semantic diagnostics.
|
||||
/// If fullTypeCheck === true, then the typechecker should do every possible check to produce all errors
|
||||
/// If fullTypeCheck === false, the typechecker can take shortcuts and skip checks that only produce errors.
|
||||
@ -62,11 +84,14 @@ module ts {
|
||||
getTypeOfNode: getTypeOfNode,
|
||||
getApparentType: getApparentType,
|
||||
typeToString: typeToString,
|
||||
typeToDisplayParts: typeToDisplayParts,
|
||||
symbolToString: symbolToString,
|
||||
symbolToDisplayParts: symbolToDisplayParts,
|
||||
getAugmentedPropertiesOfApparentType: getAugmentedPropertiesOfApparentType,
|
||||
getRootSymbol: getRootSymbol,
|
||||
getContextualType: getContextualType,
|
||||
getFullyQualifiedName: getFullyQualifiedName
|
||||
getFullyQualifiedName: getFullyQualifiedName,
|
||||
getEnumMemberValue: getEnumMemberValue
|
||||
};
|
||||
|
||||
var undefinedSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "undefined");
|
||||
@ -895,106 +920,238 @@ module ts {
|
||||
{ accessibility: SymbolAccessibility.NotAccessible, errorSymbolName: firstIdentifierName };
|
||||
}
|
||||
|
||||
// Pool writers to avoid needing to allocate them for every symbol we write.
|
||||
var displayPartWriters: DisplayPartsSymbolWriter[] = [];
|
||||
var stringWriters: StringSymbolWriter[] = [];
|
||||
|
||||
function displayPartKind(symbol: Symbol): SymbolDisplayPartKind {
|
||||
var flags = symbol.flags;
|
||||
|
||||
if (flags & SymbolFlags.Variable) {
|
||||
return symbol.declarations && symbol.declarations.length > 0 && symbol.declarations[0].kind === SyntaxKind.Parameter
|
||||
? SymbolDisplayPartKind.parameterName
|
||||
: SymbolDisplayPartKind.localName;
|
||||
}
|
||||
else if (flags & SymbolFlags.Property) { return SymbolDisplayPartKind.propertyName; }
|
||||
else if (flags & SymbolFlags.EnumMember) { return SymbolDisplayPartKind.enumMemberName; }
|
||||
else if (flags & SymbolFlags.Function) { return SymbolDisplayPartKind.functionName; }
|
||||
else if (flags & SymbolFlags.Class) { return SymbolDisplayPartKind.className; }
|
||||
else if (flags & SymbolFlags.Interface) { return SymbolDisplayPartKind.interfaceName; }
|
||||
else if (flags & SymbolFlags.Enum) { return SymbolDisplayPartKind.enumName; }
|
||||
else if (flags & SymbolFlags.Module) { return SymbolDisplayPartKind.moduleName; }
|
||||
else if (flags & SymbolFlags.Method) { return SymbolDisplayPartKind.methodName; }
|
||||
else if (flags & SymbolFlags.TypeParameter) { return SymbolDisplayPartKind.typeParameterName; }
|
||||
|
||||
return SymbolDisplayPartKind.text;
|
||||
}
|
||||
|
||||
function getDisplayPartWriter(): DisplayPartsSymbolWriter {
|
||||
if (displayPartWriters.length == 0) {
|
||||
var displayParts: SymbolDisplayPart[] = [];
|
||||
return {
|
||||
displayParts: () => displayParts,
|
||||
writeKind: (text, kind) => displayParts.push(new SymbolDisplayPart(text, kind, undefined)),
|
||||
writeSymbol: (text, symbol) => displayParts.push(new SymbolDisplayPart(text, displayPartKind(symbol), symbol)),
|
||||
|
||||
// Completely ignore indentation for display part writers. And map newlines to
|
||||
// a single space.
|
||||
writeLine: () => displayParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined)),
|
||||
increaseIndent: () => { },
|
||||
decreaseIndent: () => { },
|
||||
clear: () => displayParts = [],
|
||||
trackSymbol: () => { }
|
||||
};
|
||||
}
|
||||
|
||||
return displayPartWriters.pop();
|
||||
}
|
||||
|
||||
function getStringWriter(): StringSymbolWriter {
|
||||
if (stringWriters.length == 0) {
|
||||
var str = "";
|
||||
|
||||
return {
|
||||
string: () => str,
|
||||
writeKind: text => str += text,
|
||||
writeSymbol: text => str += text,
|
||||
|
||||
// Completely ignore indentation for string writers. And map newlines to
|
||||
// a single space.
|
||||
writeLine: () => str += " ",
|
||||
increaseIndent: () => { },
|
||||
decreaseIndent: () => { },
|
||||
clear: () => str = "",
|
||||
trackSymbol: () => { }
|
||||
};
|
||||
}
|
||||
|
||||
return stringWriters.pop();
|
||||
}
|
||||
|
||||
function releaseDisplayPartWriter(writer: DisplayPartsSymbolWriter) {
|
||||
writer.clear();
|
||||
displayPartWriters.push(writer);
|
||||
}
|
||||
|
||||
function releaseStringWriter(writer: StringSymbolWriter) {
|
||||
writer.clear()
|
||||
stringWriters.push(writer);
|
||||
}
|
||||
|
||||
function writeKeyword(writer: SymbolWriter, kind: SyntaxKind) {
|
||||
writer.writeKind(tokenToString(kind), SymbolDisplayPartKind.keyword);
|
||||
}
|
||||
|
||||
function writePunctuation(writer: SymbolWriter, kind: SyntaxKind) {
|
||||
writer.writeKind(tokenToString(kind), SymbolDisplayPartKind.punctuation);
|
||||
}
|
||||
|
||||
function writeOperator(writer: SymbolWriter, kind: SyntaxKind) {
|
||||
writer.writeKind(tokenToString(kind), SymbolDisplayPartKind.operator);
|
||||
}
|
||||
|
||||
function writeSpace(writer: SymbolWriter) {
|
||||
writer.writeKind(" ", SymbolDisplayPartKind.space);
|
||||
}
|
||||
|
||||
function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string {
|
||||
var writer = getStringWriter();
|
||||
writeSymbol(symbol, writer, enclosingDeclaration, meaning);
|
||||
|
||||
var result = writer.string();
|
||||
releaseStringWriter(writer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function symbolToDisplayParts(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): SymbolDisplayPart[] {
|
||||
var writer = getDisplayPartWriter();
|
||||
writeSymbol(symbol, writer, enclosingDeclaration, meaning);
|
||||
|
||||
var result = writer.displayParts();
|
||||
releaseDisplayPartWriter(writer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Enclosing declaration is optional when we don't want to get qualified name in the enclosing declaration scope
|
||||
// Meaning needs to be specified if the enclosing declaration is given
|
||||
function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
|
||||
function getSymbolName(symbol: Symbol) {
|
||||
function writeSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags): void {
|
||||
function writeSymbolName(symbol: Symbol): void {
|
||||
if (symbol.declarations && symbol.declarations.length > 0) {
|
||||
var declaration = symbol.declarations[0];
|
||||
if (declaration.name) {
|
||||
return identifierToString(declaration.name);
|
||||
writer.writeSymbol(identifierToString(declaration.name), symbol);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
writer.writeSymbol(symbol.name, symbol);
|
||||
}
|
||||
|
||||
// Let the writer know we just wrote out a symbol. The declarationemitter writer uses
|
||||
// this to determine if an import it has previously seen (and not writter out) needs
|
||||
// to be written to the file once the walk of the tree is complete.
|
||||
//
|
||||
// NOTE(cyrusn): This approach feels somewhat unfortunate. A simple pass over the tree
|
||||
// up front (for example, during checking) could determien if we need to emit the imports
|
||||
// and we could then access that data during declaration emit.
|
||||
writer.trackSymbol(symbol, enclosingDeclaration, meaning);
|
||||
|
||||
var needsDot = false;
|
||||
function walkSymbol(symbol: Symbol, meaning: SymbolFlags): void {
|
||||
if (symbol) {
|
||||
var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning);
|
||||
|
||||
if (!accessibleSymbolChain ||
|
||||
needsQualification(accessibleSymbolChain[0], enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) {
|
||||
|
||||
// Go up and add our parent.
|
||||
walkSymbol(
|
||||
getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol),
|
||||
getQualifiedLeftMeaning(meaning));
|
||||
}
|
||||
|
||||
if (accessibleSymbolChain) {
|
||||
for (var i = 0, n = accessibleSymbolChain.length; i < n; i++) {
|
||||
if (needsDot) {
|
||||
writePunctuation(writer, SyntaxKind.DotToken);
|
||||
}
|
||||
|
||||
writeSymbolName(accessibleSymbolChain[i]);
|
||||
needsDot = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If we didn't find accessible symbol chain for this symbol, break if this is external module
|
||||
if (!needsDot && ts.forEach(symbol.declarations, declaration => hasExternalModuleSymbol(declaration))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (needsDot) {
|
||||
writePunctuation(writer, SyntaxKind.DotToken);
|
||||
}
|
||||
|
||||
writeSymbolName(symbol);
|
||||
needsDot = true;
|
||||
}
|
||||
}
|
||||
return symbol.name;
|
||||
}
|
||||
|
||||
// Get qualified name
|
||||
if (enclosingDeclaration &&
|
||||
// TypeParameters do not need qualification
|
||||
!(symbol.flags & SymbolFlags.TypeParameter)) {
|
||||
var symbolName: string;
|
||||
while (symbol) {
|
||||
var isFirstName = !symbolName;
|
||||
var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning);
|
||||
|
||||
var currentSymbolName: string;
|
||||
if (accessibleSymbolChain) {
|
||||
currentSymbolName = ts.map(accessibleSymbolChain, accessibleSymbol => getSymbolName(accessibleSymbol)).join(".");
|
||||
}
|
||||
else {
|
||||
// If we didn't find accessible symbol chain for this symbol, break if this is external module
|
||||
if (!isFirstName && ts.forEach(symbol.declarations, declaration => hasExternalModuleSymbol(declaration))) {
|
||||
break;
|
||||
}
|
||||
currentSymbolName = getSymbolName(symbol);
|
||||
}
|
||||
symbolName = currentSymbolName + (isFirstName ? "" : ("." + symbolName));
|
||||
if (accessibleSymbolChain && !needsQualification(accessibleSymbolChain[0], enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) {
|
||||
break;
|
||||
}
|
||||
symbol = getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol);
|
||||
meaning = getQualifiedLeftMeaning(meaning);
|
||||
}
|
||||
|
||||
return symbolName;
|
||||
walkSymbol(symbol, meaning);
|
||||
return;
|
||||
}
|
||||
|
||||
return getSymbolName(symbol);
|
||||
return writeSymbolName(symbol);
|
||||
}
|
||||
|
||||
function writeSymbolToTextWriter(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, writer: TextWriter) {
|
||||
writer.write(symbolToString(symbol, enclosingDeclaration, meaning));
|
||||
}
|
||||
|
||||
function createSingleLineTextWriter(maxLength?: number) {
|
||||
var result = "";
|
||||
var overflow = false;
|
||||
function write(s: string) {
|
||||
if (!overflow) {
|
||||
result += s;
|
||||
if (result.length > maxLength) {
|
||||
result = result.substr(0, maxLength - 3) + "...";
|
||||
overflow = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
write: write,
|
||||
writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
|
||||
writeSymbolToTextWriter(symbol, enclosingDeclaration, meaning, this);
|
||||
},
|
||||
writeLine() {
|
||||
write(" ");
|
||||
},
|
||||
increaseIndent() { },
|
||||
decreaseIndent() { },
|
||||
getText() {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string {
|
||||
var writer = getStringWriter();
|
||||
writeType(type, writer, enclosingDeclaration, flags);
|
||||
|
||||
var result = writer.string();
|
||||
releaseStringWriter(writer);
|
||||
|
||||
var maxLength = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation ? undefined : 100;
|
||||
var stringWriter = createSingleLineTextWriter(maxLength);
|
||||
// TODO(shkamat): typeToString should take enclosingDeclaration as input, once we have implemented enclosingDeclaration
|
||||
writeTypeToTextWriter(type, enclosingDeclaration, flags, stringWriter);
|
||||
return stringWriter.getText();
|
||||
if (maxLength && result.length >= maxLength) {
|
||||
result = result.substr(0, maxLength - "...".length) + "...";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function writeTypeToTextWriter(type: Type, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter) {
|
||||
function typeToDisplayParts(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] {
|
||||
var writer = getDisplayPartWriter();
|
||||
writeType(type, writer, enclosingDeclaration, flags);
|
||||
|
||||
var result = writer.displayParts();
|
||||
releaseDisplayPartWriter(writer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function writeType(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags) {
|
||||
var typeStack: Type[];
|
||||
return writeType(type, /*allowFunctionOrConstructorTypeLiteral*/ true);
|
||||
|
||||
function writeType(type: Type, allowFunctionOrConstructorTypeLiteral: boolean) {
|
||||
if (type.flags & TypeFlags.Intrinsic) {
|
||||
writer.write((<IntrinsicType>type).intrinsicName);
|
||||
writer.writeKind((<IntrinsicType>type).intrinsicName, SymbolDisplayPartKind.keyword);
|
||||
}
|
||||
else if (type.flags & TypeFlags.Reference) {
|
||||
writeTypeReference(<TypeReference>type);
|
||||
}
|
||||
else if (type.flags & (TypeFlags.Class | TypeFlags.Interface | TypeFlags.Enum | TypeFlags.TypeParameter)) {
|
||||
writer.writeSymbol(type.symbol, enclosingDeclaration, SymbolFlags.Type);
|
||||
writeSymbol(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type);
|
||||
}
|
||||
else if (type.flags & TypeFlags.Tuple) {
|
||||
writeTupleType(<TupleType>type);
|
||||
@ -1003,18 +1160,24 @@ module ts {
|
||||
writeAnonymousType(<ObjectType>type, allowFunctionOrConstructorTypeLiteral);
|
||||
}
|
||||
else if (type.flags & TypeFlags.StringLiteral) {
|
||||
writer.write((<StringLiteralType>type).text);
|
||||
writer.writeKind((<StringLiteralType>type).text, SymbolDisplayPartKind.stringLiteral);
|
||||
}
|
||||
else {
|
||||
// Should never get here
|
||||
writer.write("{ ... }");
|
||||
// { ... }
|
||||
writePunctuation(writer, SyntaxKind.OpenBraceToken);
|
||||
writeSpace(writer);
|
||||
writePunctuation(writer, SyntaxKind.DotDotDotToken);
|
||||
writeSpace(writer);
|
||||
writePunctuation(writer, SyntaxKind.CloseBraceToken);
|
||||
}
|
||||
}
|
||||
|
||||
function writeTypeList(types: Type[]) {
|
||||
for (var i = 0; i < types.length; i++) {
|
||||
if (i > 0) {
|
||||
writer.write(", ");
|
||||
writePunctuation(writer, SyntaxKind.CommaToken);
|
||||
writeSpace(writer);
|
||||
}
|
||||
writeType(types[i], /*allowFunctionOrConstructorTypeLiteral*/ true);
|
||||
}
|
||||
@ -1025,20 +1188,21 @@ module ts {
|
||||
// If we are writing array element type the arrow style signatures are not allowed as
|
||||
// we need to surround it by curlies, e.g. { (): T; }[]; as () => T[] would mean something different
|
||||
writeType(type.typeArguments[0], /*allowFunctionOrConstructorTypeLiteral*/ false);
|
||||
writer.write("[]");
|
||||
writePunctuation(writer, SyntaxKind.OpenBracketToken);
|
||||
writePunctuation(writer, SyntaxKind.CloseBracketToken);
|
||||
}
|
||||
else {
|
||||
writer.writeSymbol(type.target.symbol, enclosingDeclaration, SymbolFlags.Type);
|
||||
writer.write("<");
|
||||
writeSymbol(type.target.symbol, writer, enclosingDeclaration, SymbolFlags.Type);
|
||||
writePunctuation(writer, SyntaxKind.LessThanToken);
|
||||
writeTypeList(type.typeArguments);
|
||||
writer.write(">");
|
||||
writePunctuation(writer, SyntaxKind.GreaterThanToken);
|
||||
}
|
||||
}
|
||||
|
||||
function writeTupleType(type: TupleType) {
|
||||
writer.write("[");
|
||||
writePunctuation(writer, SyntaxKind.OpenBracketToken);
|
||||
writeTypeList(type.elementTypes);
|
||||
writer.write("]");
|
||||
writePunctuation(writer, SyntaxKind.CloseBracketToken);
|
||||
}
|
||||
|
||||
function writeAnonymousType(type: ObjectType, allowFunctionOrConstructorTypeLiteral: boolean) {
|
||||
@ -1052,7 +1216,7 @@ module ts {
|
||||
}
|
||||
else if (typeStack && contains(typeStack, type)) {
|
||||
// Recursive usage, use any
|
||||
writer.write("any");
|
||||
writeKeyword(writer, SyntaxKind.AnyKeyword);
|
||||
}
|
||||
else {
|
||||
if (!typeStack) {
|
||||
@ -1082,15 +1246,17 @@ module ts {
|
||||
}
|
||||
|
||||
function writeTypeofSymbol(type: ObjectType) {
|
||||
writer.write("typeof ");
|
||||
writer.writeSymbol(type.symbol, enclosingDeclaration, SymbolFlags.Value);
|
||||
writeKeyword(writer, SyntaxKind.TypeOfKeyword);
|
||||
writeSpace(writer);
|
||||
writeSymbol(type.symbol, writer, enclosingDeclaration, SymbolFlags.Value);
|
||||
}
|
||||
|
||||
function writeLiteralType(type: ObjectType, allowFunctionOrConstructorTypeLiteral: boolean) {
|
||||
var resolved = resolveObjectTypeMembers(type);
|
||||
if (!resolved.properties.length && !resolved.stringIndexType && !resolved.numberIndexType) {
|
||||
if (!resolved.callSignatures.length && !resolved.constructSignatures.length) {
|
||||
writer.write("{}");
|
||||
writePunctuation(writer, SyntaxKind.OpenBraceToken);
|
||||
writePunctuation(writer, SyntaxKind.CloseBraceToken);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1100,37 +1266,56 @@ module ts {
|
||||
return;
|
||||
}
|
||||
if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) {
|
||||
writer.write("new ");
|
||||
writeKeyword(writer, SyntaxKind.NewKeyword);
|
||||
writeSpace(writer);
|
||||
writeSignature(resolved.constructSignatures[0], /*arrowStyle*/ true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer.write("{");
|
||||
writePunctuation(writer, SyntaxKind.OpenBraceToken);
|
||||
writer.writeLine();
|
||||
writer.increaseIndent();
|
||||
for (var i = 0; i < resolved.callSignatures.length; i++) {
|
||||
writeSignature(resolved.callSignatures[i]);
|
||||
writer.write(";");
|
||||
writePunctuation(writer, SyntaxKind.SemicolonToken);
|
||||
writer.writeLine();
|
||||
}
|
||||
for (var i = 0; i < resolved.constructSignatures.length; i++) {
|
||||
writer.write("new ");
|
||||
writeKeyword(writer, SyntaxKind.NewKeyword);
|
||||
writeSpace(writer);
|
||||
|
||||
writeSignature(resolved.constructSignatures[i]);
|
||||
writer.write(";");
|
||||
writePunctuation(writer, SyntaxKind.SemicolonToken);
|
||||
writer.writeLine();
|
||||
}
|
||||
if (resolved.stringIndexType) {
|
||||
writer.write("[x: string]: ");
|
||||
// [x: string]:
|
||||
writePunctuation(writer, SyntaxKind.OpenBracketToken);
|
||||
writer.writeKind("x", SymbolDisplayPartKind.parameterName);
|
||||
writePunctuation(writer, SyntaxKind.ColonToken);
|
||||
writeSpace(writer);
|
||||
writeKeyword(writer, SyntaxKind.StringKeyword);
|
||||
writePunctuation(writer, SyntaxKind.CloseBracketToken);
|
||||
writePunctuation(writer, SyntaxKind.ColonToken);
|
||||
writeSpace(writer);
|
||||
writeType(resolved.stringIndexType, /*allowFunctionOrConstructorTypeLiteral*/ true);
|
||||
writer.write(";");
|
||||
writePunctuation(writer, SyntaxKind.SemicolonToken);
|
||||
writer.writeLine();
|
||||
}
|
||||
if (resolved.numberIndexType) {
|
||||
writer.write("[x: number]: ");
|
||||
// [x: number]:
|
||||
writePunctuation(writer, SyntaxKind.OpenBracketToken);
|
||||
writer.writeKind("x", SymbolDisplayPartKind.parameterName);
|
||||
writePunctuation(writer, SyntaxKind.ColonToken);
|
||||
writeSpace(writer);
|
||||
writeKeyword(writer, SyntaxKind.NumberKeyword);
|
||||
writePunctuation(writer, SyntaxKind.CloseBracketToken);
|
||||
writePunctuation(writer, SyntaxKind.ColonToken);
|
||||
writeSpace(writer);
|
||||
writeType(resolved.numberIndexType, /*allowFunctionOrConstructorTypeLiteral*/ true);
|
||||
writer.write(";");
|
||||
writePunctuation(writer, SyntaxKind.SemicolonToken);
|
||||
writer.writeLine();
|
||||
}
|
||||
for (var i = 0; i < resolved.properties.length; i++) {
|
||||
@ -1139,64 +1324,81 @@ module ts {
|
||||
if (p.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfType(t).length) {
|
||||
var signatures = getSignaturesOfType(t, SignatureKind.Call);
|
||||
for (var j = 0; j < signatures.length; j++) {
|
||||
writer.writeSymbol(p);
|
||||
writeSymbol(p, writer);
|
||||
if (isOptionalProperty(p)) {
|
||||
writer.write("?");
|
||||
writePunctuation(writer, SyntaxKind.QuestionToken);
|
||||
}
|
||||
writeSignature(signatures[j]);
|
||||
writer.write(";");
|
||||
writePunctuation(writer, SyntaxKind.SemicolonToken);
|
||||
writer.writeLine();
|
||||
}
|
||||
}
|
||||
else {
|
||||
writer.writeSymbol(p);
|
||||
writeSymbol(p, writer);
|
||||
if (isOptionalProperty(p)) {
|
||||
writer.write("?");
|
||||
writePunctuation(writer, SyntaxKind.QuestionToken);
|
||||
}
|
||||
writer.write(": ");
|
||||
writePunctuation(writer, SyntaxKind.ColonToken);
|
||||
writeSpace(writer);
|
||||
writeType(t, /*allowFunctionOrConstructorTypeLiteral*/ true);
|
||||
writer.write(";");
|
||||
writePunctuation(writer, SyntaxKind.SemicolonToken);
|
||||
writer.writeLine();
|
||||
}
|
||||
}
|
||||
writer.decreaseIndent();
|
||||
writer.write("}");
|
||||
writePunctuation(writer, SyntaxKind.CloseBraceToken);
|
||||
}
|
||||
|
||||
function writeSignature(signature: Signature, arrowStyle?: boolean) {
|
||||
if (signature.typeParameters) {
|
||||
writer.write("<");
|
||||
writePunctuation(writer, SyntaxKind.LessThanToken);
|
||||
for (var i = 0; i < signature.typeParameters.length; i++) {
|
||||
if (i > 0) {
|
||||
writer.write(", ");
|
||||
writePunctuation(writer, SyntaxKind.CommaToken);
|
||||
writeSpace(writer);
|
||||
}
|
||||
var tp = signature.typeParameters[i];
|
||||
writer.writeSymbol(tp.symbol);
|
||||
writeSymbol(tp.symbol, writer);
|
||||
var constraint = getConstraintOfTypeParameter(tp);
|
||||
if (constraint) {
|
||||
writer.write(" extends ");
|
||||
writeSpace(writer);
|
||||
writeKeyword(writer, SyntaxKind.ExtendsKeyword);
|
||||
writeSpace(writer);
|
||||
writeType(constraint, /*allowFunctionOrConstructorTypeLiteral*/ true);
|
||||
}
|
||||
}
|
||||
writer.write(">");
|
||||
writePunctuation(writer, SyntaxKind.GreaterThanToken);
|
||||
}
|
||||
writer.write("(");
|
||||
writePunctuation(writer, SyntaxKind.OpenParenToken);
|
||||
for (var i = 0; i < signature.parameters.length; i++) {
|
||||
if (i > 0) {
|
||||
writer.write(", ");
|
||||
writePunctuation(writer, SyntaxKind.CommaToken);
|
||||
writeSpace(writer);
|
||||
}
|
||||
var p = signature.parameters[i];
|
||||
if (getDeclarationFlagsFromSymbol(p) & NodeFlags.Rest) {
|
||||
writer.write("...");
|
||||
writePunctuation(writer, SyntaxKind.DotDotDotToken);
|
||||
}
|
||||
writer.writeSymbol(p);
|
||||
writeSymbol(p, writer);
|
||||
if (p.valueDeclaration.flags & NodeFlags.QuestionMark || (<VariableDeclaration>p.valueDeclaration).initializer) {
|
||||
writer.write("?");
|
||||
writePunctuation(writer, SyntaxKind.QuestionToken);
|
||||
}
|
||||
writer.write(": ");
|
||||
writePunctuation(writer, SyntaxKind.ColonToken);
|
||||
writeSpace(writer);
|
||||
|
||||
writeType(getTypeOfSymbol(p), /*allowFunctionOrConstructorTypeLiteral*/ true);
|
||||
}
|
||||
writer.write(arrowStyle ? ") => " : "): ");
|
||||
|
||||
writePunctuation(writer, SyntaxKind.CloseParenToken);
|
||||
if (arrowStyle) {
|
||||
writeSpace(writer);
|
||||
writePunctuation(writer, SyntaxKind.EqualsGreaterThanToken);
|
||||
}
|
||||
else {
|
||||
writePunctuation(writer, SyntaxKind.ColonToken);
|
||||
}
|
||||
writeSpace(writer);
|
||||
|
||||
writeType(getReturnTypeOfSignature(signature), /*allowFunctionOrConstructorTypeLiteral*/ true);
|
||||
}
|
||||
}
|
||||
@ -6307,7 +6509,7 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getConstantValue(node: Expression): number {
|
||||
function getConstantValueForExpression(node: Expression): number {
|
||||
var isNegative = false;
|
||||
if (node.kind === SyntaxKind.PrefixOperator) {
|
||||
var unaryExpression = <UnaryExpression>node;
|
||||
@ -6324,38 +6526,51 @@ module ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function computeEnumMemberValues(node: EnumDeclaration) {
|
||||
var nodeLinks = getNodeLinks(node);
|
||||
|
||||
if (!(nodeLinks.flags & NodeCheckFlags.EnumValuesComputed)) {
|
||||
var enumSymbol = getSymbolOfNode(node);
|
||||
var enumType = getDeclaredTypeOfSymbol(enumSymbol);
|
||||
var autoValue = 0;
|
||||
var ambient = isInAmbientContext(node);
|
||||
|
||||
forEach(node.members, member => {
|
||||
var initializer = member.initializer;
|
||||
if (initializer) {
|
||||
autoValue = getConstantValueForExpression(initializer);
|
||||
if (autoValue === undefined && !ambient) {
|
||||
// Only here do we need to check that the initializer is assignable to the enum type.
|
||||
// If it is a constant value (not undefined), it is syntactically constrained to be a number.
|
||||
// Also, we do not need to check this for ambients because there is already
|
||||
// a syntax error if it is not a constant.
|
||||
checkTypeAssignableTo(checkExpression(initializer), enumType, initializer, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined);
|
||||
}
|
||||
}
|
||||
else if (ambient) {
|
||||
autoValue = undefined;
|
||||
}
|
||||
|
||||
if (autoValue !== undefined) {
|
||||
getNodeLinks(member).enumMemberValue = autoValue++;
|
||||
}
|
||||
});
|
||||
|
||||
nodeLinks.flags |= NodeCheckFlags.EnumValuesComputed;
|
||||
}
|
||||
}
|
||||
|
||||
function checkEnumDeclaration(node: EnumDeclaration) {
|
||||
if (!fullTypeCheck) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkTypeNameIsReserved(node.name, Diagnostics.Enum_name_cannot_be_0);
|
||||
checkCollisionWithCapturedThisVariable(node, node.name);
|
||||
checkCollistionWithRequireExportsInGeneratedCode(node, node.name);
|
||||
checkExportsOnMergedDeclarations(node);
|
||||
var enumSymbol = getSymbolOfNode(node);
|
||||
var enumType = getDeclaredTypeOfSymbol(enumSymbol);
|
||||
var autoValue = 0;
|
||||
var ambient = isInAmbientContext(node);
|
||||
forEach(node.members, member => {
|
||||
var initializer = member.initializer;
|
||||
if (initializer) {
|
||||
autoValue = getConstantValue(initializer);
|
||||
if (autoValue === undefined && !ambient) {
|
||||
// Only here do we need to check that the initializer is assignable to the enum type.
|
||||
// If it is a constant value (not undefined), it is syntactically constrained to be a number.
|
||||
// Also, we do not need to check this for ambients because there is already
|
||||
// a syntax error if it is not a constant.
|
||||
checkTypeAssignableTo(checkExpression(initializer), enumType, initializer, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined);
|
||||
}
|
||||
}
|
||||
else if (ambient) {
|
||||
autoValue = undefined;
|
||||
}
|
||||
|
||||
if (autoValue !== undefined) {
|
||||
getNodeLinks(member).enumMemberValue = autoValue++;
|
||||
}
|
||||
});
|
||||
computeEnumMemberValues(node);
|
||||
|
||||
// Spec 2014 - Section 9.3:
|
||||
// It isn't possible for one enum declaration to continue the automatic numbering sequence of another,
|
||||
@ -6363,6 +6578,7 @@ module ts {
|
||||
// for the first member.
|
||||
//
|
||||
// Only perform this check once per symbol
|
||||
var enumSymbol = getSymbolOfNode(node);
|
||||
var firstDeclaration = getDeclarationOfKind(enumSymbol, node.kind);
|
||||
if (node === firstDeclaration) {
|
||||
var seenEnumMissingInitialInitializer = false;
|
||||
@ -7262,17 +7478,6 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getPropertyAccessSubstitution(node: PropertyAccess): string {
|
||||
var symbol = getNodeLinks(node).resolvedSymbol;
|
||||
if (symbol && (symbol.flags & SymbolFlags.EnumMember)) {
|
||||
var declaration = symbol.valueDeclaration;
|
||||
var constantValue: number;
|
||||
if (declaration.kind === SyntaxKind.EnumMember && (constantValue = getNodeLinks(declaration).enumMemberValue) !== undefined) {
|
||||
return constantValue.toString() + " /* " + identifierToString(declaration.name) + " */";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getExportAssignmentName(node: SourceFile): string {
|
||||
var symbol = getExportAssignmentSymbol(getSymbolOfNode(node));
|
||||
return symbol && symbolIsValue(symbol) ? symbolToString(symbol): undefined;
|
||||
@ -7335,20 +7540,51 @@ module ts {
|
||||
}
|
||||
|
||||
function getEnumMemberValue(node: EnumMember): number {
|
||||
computeEnumMemberValues(<EnumDeclaration>node.parent);
|
||||
return getNodeLinks(node).enumMemberValue;
|
||||
}
|
||||
|
||||
function getConstantValue(node: PropertyAccess): number {
|
||||
var symbol = getNodeLinks(node).resolvedSymbol;
|
||||
if (symbol && (symbol.flags & SymbolFlags.EnumMember)) {
|
||||
var declaration = symbol.valueDeclaration;
|
||||
var constantValue: number;
|
||||
if (declaration.kind === SyntaxKind.EnumMember && (constantValue = getNodeLinks(declaration).enumMemberValue) !== undefined) {
|
||||
return constantValue;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Create a single instance that we can wrap the underlying emitter TextWriter with. That
|
||||
// way we don't have to allocate a new wrapper every time writeTypeAtLocation and
|
||||
// writeReturnTypeOfSignatureDeclaration are called.
|
||||
var emitSymbolWriter = {
|
||||
writer: <TextWriter>undefined,
|
||||
|
||||
writeKind: function (text: string) { this.writer.write(text) },
|
||||
writeSymbol: function (text: string) { this.writer.write(text) },
|
||||
writeLine: function () { this.writer.writeLine() },
|
||||
increaseIndent: function () { this.writer.increaseIndent() },
|
||||
decreaseIndent: function () { this.writer.decreaseIndent() },
|
||||
clear: function () { },
|
||||
trackSymbol: function (symbol: Symbol, declaration: Node, meaning: SymbolFlags) { this.writer.trackSymbol(symbol, declaration, meaning) }
|
||||
};
|
||||
|
||||
function writeTypeAtLocation(location: Node, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter) {
|
||||
// Get type of the symbol if this is the valid symbol otherwise get type at location
|
||||
var symbol = getSymbolOfNode(location);
|
||||
var type = symbol && !(symbol.flags & SymbolFlags.TypeLiteral) ? getTypeOfSymbol(symbol) : getTypeFromTypeNode(location);
|
||||
|
||||
writeTypeToTextWriter(type, enclosingDeclaration, flags, writer);
|
||||
emitSymbolWriter.writer = writer;
|
||||
writeType(type, emitSymbolWriter, enclosingDeclaration, flags);
|
||||
}
|
||||
|
||||
function writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter) {
|
||||
var signature = getSignatureFromDeclaration(signatureDeclaration);
|
||||
writeTypeToTextWriter(getReturnTypeOfSignature(signature), enclosingDeclaration, flags , writer);
|
||||
emitSymbolWriter.writer = writer;
|
||||
writeType(getReturnTypeOfSignature(signature), emitSymbolWriter, enclosingDeclaration, flags);
|
||||
}
|
||||
|
||||
function invokeEmitter(targetSourceFile?: SourceFile) {
|
||||
@ -7356,7 +7592,6 @@ module ts {
|
||||
getProgram: () => program,
|
||||
getLocalNameOfContainer: getLocalNameOfContainer,
|
||||
getExpressionNamePrefix: getExpressionNamePrefix,
|
||||
getPropertyAccessSubstitution: getPropertyAccessSubstitution,
|
||||
getExportAssignmentName: getExportAssignmentName,
|
||||
isReferencedImportDeclaration: isReferencedImportDeclaration,
|
||||
getNodeCheckFlags: getNodeCheckFlags,
|
||||
@ -7367,9 +7602,9 @@ module ts {
|
||||
isImplementationOfOverload: isImplementationOfOverload,
|
||||
writeTypeAtLocation: writeTypeAtLocation,
|
||||
writeReturnTypeOfSignatureDeclaration: writeReturnTypeOfSignatureDeclaration,
|
||||
writeSymbol: writeSymbolToTextWriter,
|
||||
isSymbolAccessible: isSymbolAccessible,
|
||||
isImportDeclarationEntityNameReferenceDeclarationVisibile: isImportDeclarationEntityNameReferenceDeclarationVisibile
|
||||
isImportDeclarationEntityNameReferenceDeclarationVisibile: isImportDeclarationEntityNameReferenceDeclarationVisibile,
|
||||
getConstantValue: getConstantValue,
|
||||
};
|
||||
checkProgram();
|
||||
return emitFiles(resolver, targetSourceFile);
|
||||
|
||||
@ -101,7 +101,7 @@ module ts {
|
||||
};
|
||||
}
|
||||
|
||||
function createTextWriter(writeSymbol: (symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags)=> void): EmitTextWriter {
|
||||
function createTextWriter(trackSymbol: (symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags)=> void): EmitTextWriter {
|
||||
var output = "";
|
||||
var indent = 0;
|
||||
var lineStart = true;
|
||||
@ -149,7 +149,7 @@ module ts {
|
||||
|
||||
return {
|
||||
write: write,
|
||||
writeSymbol: writeSymbol,
|
||||
trackSymbol: trackSymbol,
|
||||
rawWrite: rawWrite,
|
||||
writeLiteral: writeLiteral,
|
||||
writeLine: writeLine,
|
||||
@ -182,7 +182,7 @@ module ts {
|
||||
});
|
||||
}
|
||||
|
||||
function emitComments(comments: Comment[], trailingSeparator: boolean, writer: EmitTextWriter, writeComment: (comment: Comment, writer: EmitTextWriter) => void) {
|
||||
function emitComments(comments: CommentRange[], trailingSeparator: boolean, writer: EmitTextWriter, writeComment: (comment: CommentRange, writer: EmitTextWriter) => void) {
|
||||
var emitLeadingSpace = !trailingSeparator;
|
||||
forEach(comments, comment => {
|
||||
if (emitLeadingSpace) {
|
||||
@ -203,7 +203,7 @@ module ts {
|
||||
});
|
||||
}
|
||||
|
||||
function emitNewLineBeforeLeadingComments(node: TextRange, leadingComments: Comment[], writer: EmitTextWriter) {
|
||||
function emitNewLineBeforeLeadingComments(node: TextRange, leadingComments: CommentRange[], writer: EmitTextWriter) {
|
||||
// If the leading comments start on different line than the start of node, write new line
|
||||
if (leadingComments && leadingComments.length && node.pos !== leadingComments[0].pos &&
|
||||
getLineOfLocalPosition(node.pos) !== getLineOfLocalPosition(leadingComments[0].pos)) {
|
||||
@ -211,7 +211,7 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function writeCommentRange(comment: Comment, writer: EmitTextWriter) {
|
||||
function writeCommentRange(comment: CommentRange, writer: EmitTextWriter) {
|
||||
if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) {
|
||||
var firstCommentLineAndCharacter = currentSourceFile.getLineAndCharacterFromPosition(comment.pos);
|
||||
var firstCommentLineIndent: number;
|
||||
@ -307,7 +307,7 @@ module ts {
|
||||
}
|
||||
|
||||
function emitJavaScript(jsFilePath: string, root?: SourceFile) {
|
||||
var writer = createTextWriter(writeSymbol);
|
||||
var writer = createTextWriter(trackSymbol);
|
||||
var write = writer.write;
|
||||
var writeLine = writer.writeLine;
|
||||
var increaseIndent = writer.increaseIndent;
|
||||
@ -363,7 +363,7 @@ module ts {
|
||||
/** Sourcemap data that will get encoded */
|
||||
var sourceMapData: SourceMapData;
|
||||
|
||||
function writeSymbol(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags) { }
|
||||
function trackSymbol(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags) { }
|
||||
|
||||
function initializeEmitterWithSourceMaps() {
|
||||
var sourceMapDir: string; // The directory in which sourcemap will be
|
||||
@ -585,7 +585,7 @@ module ts {
|
||||
sourceMapNameIndices.pop();
|
||||
};
|
||||
|
||||
function writeCommentRangeWithMap(comment: Comment, writer: EmitTextWriter) {
|
||||
function writeCommentRangeWithMap(comment: CommentRange, writer: EmitTextWriter) {
|
||||
recordSourceMapSpan(comment.pos);
|
||||
writeCommentRange(comment, writer);
|
||||
recordSourceMapSpan(comment.end);
|
||||
@ -916,14 +916,15 @@ module ts {
|
||||
}
|
||||
|
||||
function emitPropertyAccess(node: PropertyAccess) {
|
||||
var text = resolver.getPropertyAccessSubstitution(node);
|
||||
if (text) {
|
||||
write(text);
|
||||
return;
|
||||
var constantValue = resolver.getConstantValue(node);
|
||||
if (constantValue !== undefined) {
|
||||
write(constantValue.toString() + " /* " + identifierToString(node.right) + " */");
|
||||
}
|
||||
else {
|
||||
emit(node.left);
|
||||
write(".");
|
||||
emit(node.right);
|
||||
}
|
||||
emit(node.left);
|
||||
write(".");
|
||||
emit(node.right);
|
||||
}
|
||||
|
||||
function emitIndexedAccess(node: IndexedAccess) {
|
||||
@ -2155,7 +2156,7 @@ module ts {
|
||||
|
||||
function getLeadingCommentsWithoutDetachedComments() {
|
||||
// get the leading comments from detachedPos
|
||||
var leadingComments = getLeadingComments(currentSourceFile.text, detachedCommentsInfo[detachedCommentsInfo.length - 1].detachedCommentEndPos);
|
||||
var leadingComments = getLeadingCommentRanges(currentSourceFile.text, detachedCommentsInfo[detachedCommentsInfo.length - 1].detachedCommentEndPos);
|
||||
if (detachedCommentsInfo.length - 1) {
|
||||
detachedCommentsInfo.pop();
|
||||
}
|
||||
@ -2169,14 +2170,14 @@ module ts {
|
||||
function getLeadingCommentsToEmit(node: Node) {
|
||||
// Emit the leading comments only if the parent's pos doesn't match because parent should take care of emitting these comments
|
||||
if (node.parent.kind === SyntaxKind.SourceFile || node.pos !== node.parent.pos) {
|
||||
var leadingComments: Comment[];
|
||||
var leadingComments: CommentRange[];
|
||||
if (hasDetachedComments(node.pos)) {
|
||||
// get comments without detached comments
|
||||
leadingComments = getLeadingCommentsWithoutDetachedComments();
|
||||
}
|
||||
else {
|
||||
// get the leading comments from the node
|
||||
leadingComments = getLeadingCommentsOfNode(node, currentSourceFile);
|
||||
leadingComments = getLeadingCommentRangesOfNode(node, currentSourceFile);
|
||||
}
|
||||
return leadingComments;
|
||||
}
|
||||
@ -2192,21 +2193,21 @@ module ts {
|
||||
function emitTrailingDeclarationComments(node: Node) {
|
||||
// Emit the trailing comments only if the parent's end doesn't match
|
||||
if (node.parent.kind === SyntaxKind.SourceFile || node.end !== node.parent.end) {
|
||||
var trailingComments = getTrailingComments(currentSourceFile.text, node.end);
|
||||
var trailingComments = getTrailingCommentRanges(currentSourceFile.text, node.end);
|
||||
// trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/
|
||||
emitComments(trailingComments, /*trailingSeparator*/ false, writer, writeComment);
|
||||
}
|
||||
}
|
||||
|
||||
function emitLeadingCommentsOfLocalPosition(pos: number) {
|
||||
var leadingComments: Comment[];
|
||||
var leadingComments: CommentRange[];
|
||||
if (hasDetachedComments(pos)) {
|
||||
// get comments without detached comments
|
||||
leadingComments = getLeadingCommentsWithoutDetachedComments();
|
||||
}
|
||||
else {
|
||||
// get the leading comments from the node
|
||||
leadingComments = getLeadingComments(currentSourceFile.text, pos);
|
||||
leadingComments = getLeadingCommentRanges(currentSourceFile.text, pos);
|
||||
}
|
||||
emitNewLineBeforeLeadingComments({ pos: pos, end: pos }, leadingComments, writer);
|
||||
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
|
||||
@ -2214,10 +2215,10 @@ module ts {
|
||||
}
|
||||
|
||||
function emitDetachedCommentsAtPosition(node: TextRange) {
|
||||
var leadingComments = getLeadingComments(currentSourceFile.text, node.pos);
|
||||
var leadingComments = getLeadingCommentRanges(currentSourceFile.text, node.pos);
|
||||
if (leadingComments) {
|
||||
var detachedComments: Comment[] = [];
|
||||
var lastComment: Comment;
|
||||
var detachedComments: CommentRange[] = [];
|
||||
var lastComment: CommentRange;
|
||||
|
||||
forEach(leadingComments, comment => {
|
||||
if (lastComment) {
|
||||
@ -2261,7 +2262,7 @@ module ts {
|
||||
function emitPinnedOrTripleSlashCommentsOfNode(node: Node) {
|
||||
var pinnedComments = ts.filter(getLeadingCommentsToEmit(node), isPinnedOrTripleSlashComment);
|
||||
|
||||
function isPinnedOrTripleSlashComment(comment: Comment) {
|
||||
function isPinnedOrTripleSlashComment(comment: CommentRange) {
|
||||
if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) {
|
||||
return currentSourceFile.text.charCodeAt(comment.pos + 2) === CharacterCodes.exclamation;
|
||||
}
|
||||
@ -2300,7 +2301,7 @@ module ts {
|
||||
}
|
||||
|
||||
function emitDeclarations(jsFilePath: string, root?: SourceFile) {
|
||||
var writer = createTextWriter(writeSymbol);
|
||||
var writer = createTextWriter(trackSymbol);
|
||||
var write = writer.write;
|
||||
var writeLine = writer.writeLine;
|
||||
var increaseIndent = writer.increaseIndent;
|
||||
@ -2328,7 +2329,7 @@ module ts {
|
||||
var oldWriter = writer;
|
||||
forEach(importDeclarations, aliasToWrite => {
|
||||
var aliasEmitInfo = forEach(aliasDeclarationEmitInfo, declEmitInfo => declEmitInfo.declaration === aliasToWrite ? declEmitInfo : undefined);
|
||||
writer = createTextWriter(writeSymbol);
|
||||
writer = createTextWriter(trackSymbol);
|
||||
for (var declarationIndent = aliasEmitInfo.indent; declarationIndent; declarationIndent--) {
|
||||
writer.increaseIndent();
|
||||
}
|
||||
@ -2339,10 +2340,9 @@ module ts {
|
||||
writer = oldWriter;
|
||||
}
|
||||
|
||||
function writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
|
||||
function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
|
||||
var symbolAccesibilityResult = resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning);
|
||||
if (symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) {
|
||||
resolver.writeSymbol(symbol, enclosingDeclaration, meaning, writer);
|
||||
|
||||
// write the aliases
|
||||
if (symbolAccesibilityResult && symbolAccesibilityResult.aliasesToMakeVisible) {
|
||||
|
||||
@ -138,25 +138,27 @@ module ts {
|
||||
return (<Identifier>(<ExpressionStatement>node).expression).text === "use strict";
|
||||
}
|
||||
|
||||
export function getLeadingCommentsOfNode(node: Node, sourceFileOfNode: SourceFile) {
|
||||
export function getLeadingCommentRangesOfNode(node: Node, sourceFileOfNode?: SourceFile) {
|
||||
sourceFileOfNode = sourceFileOfNode || getSourceFileOfNode(node);
|
||||
|
||||
// If parameter/type parameter, the prev token trailing comments are part of this node too
|
||||
if (node.kind === SyntaxKind.Parameter || node.kind === SyntaxKind.TypeParameter) {
|
||||
// e.g. (/** blah */ a, /** blah */ b);
|
||||
return concatenate(getTrailingComments(sourceFileOfNode.text, node.pos),
|
||||
return concatenate(getTrailingCommentRanges(sourceFileOfNode.text, node.pos),
|
||||
// e.g.: (
|
||||
// /** blah */ a,
|
||||
// /** blah */ b);
|
||||
getLeadingComments(sourceFileOfNode.text, node.pos));
|
||||
getLeadingCommentRanges(sourceFileOfNode.text, node.pos));
|
||||
}
|
||||
else {
|
||||
return getLeadingComments(sourceFileOfNode.text, node.pos);
|
||||
return getLeadingCommentRanges(sourceFileOfNode.text, node.pos);
|
||||
}
|
||||
}
|
||||
|
||||
export function getJsDocComments(node: Declaration, sourceFileOfNode: SourceFile) {
|
||||
return filter(getLeadingCommentsOfNode(node, sourceFileOfNode), comment => isJsDocComment(comment));
|
||||
return filter(getLeadingCommentRangesOfNode(node, sourceFileOfNode), comment => isJsDocComment(comment));
|
||||
|
||||
function isJsDocComment(comment: Comment) {
|
||||
function isJsDocComment(comment: CommentRange) {
|
||||
// True if the comment starts with '/**' but not if it is '/**/'
|
||||
return sourceFileOfNode.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk &&
|
||||
sourceFileOfNode.text.charCodeAt(comment.pos + 2) === CharacterCodes.asterisk &&
|
||||
|
||||
@ -371,8 +371,8 @@ module ts {
|
||||
// between the given position and the next line break are returned. The return value is an array containing a TextRange for each
|
||||
// comment. Single-line comment ranges include the beginning '//' characters but not the ending line break. Multi-line comment
|
||||
// ranges include the beginning '/* and ending '*/' characters. The return value is undefined if no comments were found.
|
||||
function getCommentRanges(text: string, pos: number, trailing: boolean): Comment[] {
|
||||
var result: Comment[];
|
||||
function getCommentRanges(text: string, pos: number, trailing: boolean): CommentRange[] {
|
||||
var result: CommentRange[];
|
||||
var collecting = trailing || pos === 0;
|
||||
while (true) {
|
||||
var ch = text.charCodeAt(pos);
|
||||
@ -440,11 +440,11 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function getLeadingComments(text: string, pos: number): Comment[] {
|
||||
export function getLeadingCommentRanges(text: string, pos: number): CommentRange[] {
|
||||
return getCommentRanges(text, pos, /*trailing*/ false);
|
||||
}
|
||||
|
||||
export function getTrailingComments(text: string, pos: number): Comment[] {
|
||||
export function getTrailingCommentRanges(text: string, pos: number): CommentRange[] {
|
||||
return getCommentRanges(text, pos, /*trailing*/ true);
|
||||
}
|
||||
|
||||
|
||||
@ -529,7 +529,7 @@ module ts {
|
||||
filename: string;
|
||||
}
|
||||
|
||||
export interface Comment extends TextRange {
|
||||
export interface CommentRange extends TextRange {
|
||||
hasTrailingNewLine?: boolean;
|
||||
}
|
||||
|
||||
@ -640,15 +640,21 @@ module ts {
|
||||
getApparentType(type: Type): ApparentType;
|
||||
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
|
||||
symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string;
|
||||
typeToDisplayParts(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[];
|
||||
symbolToDisplayParts(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): SymbolDisplayPart[];
|
||||
getFullyQualifiedName(symbol: Symbol): string;
|
||||
getAugmentedPropertiesOfApparentType(type: Type): Symbol[];
|
||||
getRootSymbol(symbol: Symbol): Symbol;
|
||||
getContextualType(node: Node): Type;
|
||||
|
||||
// Returns the constant value of this enum member, or 'undefined' if the enum member has a
|
||||
// computed value.
|
||||
getEnumMemberValue(node: EnumMember): number;
|
||||
}
|
||||
|
||||
export interface TextWriter {
|
||||
write(s: string): void;
|
||||
writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void;
|
||||
trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void;
|
||||
writeLine(): void;
|
||||
increaseIndent(): void;
|
||||
decreaseIndent(): void;
|
||||
@ -679,7 +685,6 @@ module ts {
|
||||
getProgram(): Program;
|
||||
getLocalNameOfContainer(container: Declaration): string;
|
||||
getExpressionNamePrefix(node: Identifier): string;
|
||||
getPropertyAccessSubstitution(node: PropertyAccess): string;
|
||||
getExportAssignmentName(node: SourceFile): string;
|
||||
isReferencedImportDeclaration(node: ImportDeclaration): boolean;
|
||||
isTopLevelValueImportedViaEntityName(node: ImportDeclaration): boolean;
|
||||
@ -690,9 +695,12 @@ module ts {
|
||||
isImplementationOfOverload(node: FunctionDeclaration): boolean;
|
||||
writeTypeAtLocation(location: Node, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void;
|
||||
writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void;
|
||||
writeSymbol(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, writer: TextWriter): void;
|
||||
isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult;
|
||||
isImportDeclarationEntityNameReferenceDeclarationVisibile(entityName: EntityName): SymbolAccessiblityResult;
|
||||
|
||||
// Returns the constant value this property access resolves to, or 'undefined' if it does
|
||||
// resolve to a constant.
|
||||
getConstantValue(node: PropertyAccess): number;
|
||||
}
|
||||
|
||||
export enum SymbolFlags {
|
||||
@ -794,13 +802,16 @@ module ts {
|
||||
}
|
||||
|
||||
export enum NodeCheckFlags {
|
||||
TypeChecked = 0x00000001, // Node has been type checked
|
||||
LexicalThis = 0x00000002, // Lexical 'this' reference
|
||||
CaptureThis = 0x00000004, // Lexical 'this' used in body
|
||||
EmitExtends = 0x00000008, // Emit __extends
|
||||
SuperInstance = 0x00000010, // Instance 'super' reference
|
||||
SuperStatic = 0x00000020, // Static 'super' reference
|
||||
ContextChecked = 0x00000040, // Contextual types have been assigned
|
||||
TypeChecked = 0x00000001, // Node has been type checked
|
||||
LexicalThis = 0x00000002, // Lexical 'this' reference
|
||||
CaptureThis = 0x00000004, // Lexical 'this' used in body
|
||||
EmitExtends = 0x00000008, // Emit __extends
|
||||
SuperInstance = 0x00000010, // Instance 'super' reference
|
||||
SuperStatic = 0x00000020, // Static 'super' reference
|
||||
ContextChecked = 0x00000040, // Contextual types have been assigned
|
||||
|
||||
// Values for enum members have been computed, and any errors have been reported for them.
|
||||
EnumValuesComputed = 0x00000080,
|
||||
}
|
||||
|
||||
export interface NodeLinks {
|
||||
@ -1171,6 +1182,48 @@ module ts {
|
||||
verticalTab = 0x0B, // \v
|
||||
}
|
||||
|
||||
export class SymbolDisplayPart {
|
||||
constructor(public text: string,
|
||||
public kind: SymbolDisplayPartKind,
|
||||
public symbol: Symbol) {
|
||||
}
|
||||
|
||||
public toJSON() {
|
||||
return {
|
||||
text: this.text,
|
||||
kind: SymbolDisplayPartKind[this.kind]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export enum SymbolDisplayPartKind {
|
||||
aliasName,
|
||||
className,
|
||||
enumName,
|
||||
fieldName,
|
||||
interfaceName,
|
||||
keyword,
|
||||
labelName,
|
||||
lineBreak,
|
||||
numericLiteral,
|
||||
stringLiteral,
|
||||
localName,
|
||||
methodName,
|
||||
moduleName,
|
||||
namespaceName,
|
||||
operator,
|
||||
parameterName,
|
||||
propertyName,
|
||||
punctuation,
|
||||
space,
|
||||
anonymousTypeIndicator,
|
||||
text,
|
||||
typeParameterName,
|
||||
enumMemberName,
|
||||
functionName,
|
||||
regularExpressionLiteral,
|
||||
}
|
||||
|
||||
export interface CancellationToken {
|
||||
isCancellationRequested(): boolean;
|
||||
}
|
||||
|
||||
@ -45,6 +45,7 @@ module ts {
|
||||
getFlags(): SymbolFlags;
|
||||
getName(): string;
|
||||
getDeclarations(): Declaration[];
|
||||
getDocumentationComment(): string;
|
||||
}
|
||||
|
||||
export interface Type {
|
||||
@ -96,9 +97,7 @@ module ts {
|
||||
private _children: Node[];
|
||||
|
||||
public getSourceFile(): SourceFile {
|
||||
var node: Node = this;
|
||||
while (node.kind !== SyntaxKind.SourceFile) node = node.parent;
|
||||
return <SourceFile>node;
|
||||
return getSourceFileOfNode(this);
|
||||
}
|
||||
|
||||
public getStart(sourceFile?: SourceFile): number {
|
||||
@ -224,19 +223,176 @@ module ts {
|
||||
flags: SymbolFlags;
|
||||
name: string;
|
||||
declarations: Declaration[];
|
||||
|
||||
// Undefined is used to indicate the value has not been computed. If, after computing, the
|
||||
// symbol has no doc comment, then the empty string will be returned.
|
||||
documentationComment: string;
|
||||
|
||||
constructor(flags: SymbolFlags, name: string) {
|
||||
this.flags = flags;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
getFlags(): SymbolFlags {
|
||||
return this.flags;
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
getDeclarations(): Declaration[] {
|
||||
return this.declarations;
|
||||
}
|
||||
|
||||
getDocumentationComment(): string {
|
||||
if (this.documentationComment === undefined) {
|
||||
var lines: string[] = [];
|
||||
|
||||
// Get the doc comments from all the declarations of this symbol, and merge them
|
||||
// into one single doc comment.
|
||||
var declarations = this.getDeclarations();
|
||||
if (declarations) {
|
||||
for (var i = 0, n = declarations.length; i < n; i++) {
|
||||
this.processDocumentationCommentDeclaration(lines, declarations[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: get the newline info from the host.
|
||||
this.documentationComment = lines.join("\r\n");
|
||||
}
|
||||
|
||||
return this.documentationComment;
|
||||
}
|
||||
|
||||
private processDocumentationCommentDeclaration(lines: string[], declaration: Node) {
|
||||
var commentRanges = getLeadingCommentRangesOfNode(declaration);
|
||||
if (commentRanges) {
|
||||
var sourceFile = declaration.getSourceFile();
|
||||
|
||||
for (var i = 0, n = commentRanges.length; i < n; i++) {
|
||||
this.processDocumentationCommentRange(
|
||||
lines, sourceFile, commentRanges[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private processDocumentationCommentRange(lines: string[], sourceFile: SourceFile, commentRange: CommentRange) {
|
||||
// We only care about well-formed /** */ comments
|
||||
if (commentRange.end - commentRange.pos > "/**/".length &&
|
||||
sourceFile.text.substr(commentRange.pos, "/**".length) === "/**" &&
|
||||
sourceFile.text.substr(commentRange.end - "*/".length, "*/".length) === "*/") {
|
||||
|
||||
// Put a newline between each converted comment we join together.
|
||||
if (lines.length) {
|
||||
lines.push("");
|
||||
}
|
||||
|
||||
var startLineAndChar = sourceFile.getLineAndCharacterFromPosition(commentRange.pos);
|
||||
var endLineAndChar = sourceFile.getLineAndCharacterFromPosition(commentRange.end);
|
||||
|
||||
if (startLineAndChar.line === endLineAndChar.line) {
|
||||
// A single line doc comment. Just extract the text between the
|
||||
// comment markers and add that to the doc comment we're building
|
||||
// up.
|
||||
lines.push(sourceFile.text.substring(commentRange.pos + "/**".length, commentRange.end - "*/".length).trim());
|
||||
}
|
||||
else {
|
||||
this.processMultiLineDocumentationCommentRange(sourceFile, commentRange, startLineAndChar, endLineAndChar, lines);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private processMultiLineDocumentationCommentRange(
|
||||
sourceFile: SourceFile, commentRange: CommentRange,
|
||||
startLineAndChar: { line: number; character: number },
|
||||
endLineAndChar: { line: number; character: number },
|
||||
lines: string[]) {
|
||||
|
||||
// Comment spanned multiple lines. Find the leftmost character
|
||||
// position in each line, and use that to determine what we should
|
||||
// trim off, and what part of the line to keep.
|
||||
// i.e. if the comment looks like:
|
||||
//
|
||||
// /** Foo
|
||||
// * Bar
|
||||
// * Baz
|
||||
// */
|
||||
//
|
||||
// Then we'll want to add:
|
||||
// Foo
|
||||
// Bar
|
||||
// Baz
|
||||
var trimLength: number = undefined;
|
||||
for (var iLine = startLineAndChar.line + 1; iLine <= endLineAndChar.line; iLine++) {
|
||||
var lineStart = sourceFile.getPositionFromLineAndCharacter(iLine, /*character:*/ 1);
|
||||
var lineEnd = iLine === endLineAndChar.line
|
||||
? commentRange.end - "*/".length
|
||||
: sourceFile.getPositionFromLineAndCharacter(iLine + 1, 1);
|
||||
var docCommentTriviaLength = this.skipDocumentationCommentTrivia(sourceFile.text, lineStart, lineEnd);
|
||||
|
||||
if (trimLength === undefined || (docCommentTriviaLength && docCommentTriviaLength < trimLength)) {
|
||||
trimLength = docCommentTriviaLength;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the first line in.
|
||||
var firstLine = sourceFile.text.substring(
|
||||
commentRange.pos + "/**".length,
|
||||
sourceFile.getPositionFromLineAndCharacter(startLineAndChar.line + 1, /*character:*/ 1)).trim();
|
||||
if (firstLine !== "") {
|
||||
lines.push(firstLine);
|
||||
}
|
||||
|
||||
// For all the lines up to the last (but not including the last), add the contents
|
||||
// of the line (with the length up to the
|
||||
for (var iLine = startLineAndChar.line + 1; iLine < endLineAndChar.line; iLine++) {
|
||||
var line = this.trimRight(sourceFile.text.substring(
|
||||
sourceFile.getPositionFromLineAndCharacter(iLine, /*character*/ 1),
|
||||
sourceFile.getPositionFromLineAndCharacter(iLine + 1, /*character*/ 1))).substr(trimLength);
|
||||
|
||||
lines.push(line);
|
||||
}
|
||||
|
||||
// Add the last line if there is any actual text before the */
|
||||
var lastLine = this.trimRight(sourceFile.text.substring(
|
||||
sourceFile.getPositionFromLineAndCharacter(endLineAndChar.line, /*character:*/ 1),
|
||||
commentRange.end - "*/".length)).substr(trimLength);
|
||||
|
||||
if (lastLine !== "") {
|
||||
lines.push(lastLine);
|
||||
}
|
||||
}
|
||||
|
||||
private trimRight(val: string) {
|
||||
return val.replace(/(\n|\r|\s)+$/, '');
|
||||
}
|
||||
|
||||
private skipDocumentationCommentTrivia(text: string, lineStart: number, lineEnd: number): number {
|
||||
var seenAsterisk = false;
|
||||
var lineLength = lineEnd - lineStart;
|
||||
for (var i = 0; i < lineLength; i++) {
|
||||
var char = text.charCodeAt(i + lineStart);
|
||||
if (char === CharacterCodes.asterisk && !seenAsterisk) {
|
||||
// Ignore the first asterisk we see. We want to trim out the line of *'s
|
||||
// commonly seen at the start of a doc comment.
|
||||
seenAsterisk = true;
|
||||
continue;
|
||||
}
|
||||
else if (isLineBreak(char)) {
|
||||
// This was a blank line. Just ignore it wrt computing the leading whitespace to
|
||||
// trim.
|
||||
break;
|
||||
}
|
||||
else if (!isWhiteSpace(char)) {
|
||||
// Found a real doc comment character. Keep track of it so we can determine how
|
||||
// much of the doc comment leading trivia to trim off.
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
class TypeObject implements Type {
|
||||
@ -494,6 +650,7 @@ module ts {
|
||||
getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails;
|
||||
|
||||
getTypeAtPosition(fileName: string, position: number): TypeInfo;
|
||||
getQuickInfoAtPosition(fileName: string, position: number): QuickInfo;
|
||||
|
||||
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TypeScript.TextSpan;
|
||||
|
||||
@ -651,6 +808,15 @@ module ts {
|
||||
text: string;
|
||||
}
|
||||
|
||||
export class QuickInfo {
|
||||
constructor(public kind: string,
|
||||
public kindModifiers: string,
|
||||
public textSpan: TypeScript.TextSpan,
|
||||
public displayParts: SymbolDisplayPart[],
|
||||
public documentation: SymbolDisplayPart[]) {
|
||||
}
|
||||
}
|
||||
|
||||
export class TypeInfo {
|
||||
constructor(
|
||||
public memberName: TypeScript.MemberName,
|
||||
@ -1467,11 +1633,14 @@ module ts {
|
||||
var formattingRulesProvider: TypeScript.Services.Formatting.RulesProvider;
|
||||
var hostCache: HostCache; // A cache of all the information about the files on the host side.
|
||||
var program: Program;
|
||||
|
||||
// this checker is used to answer all LS questions except errors
|
||||
var typeInfoResolver: TypeChecker;
|
||||
|
||||
// the sole purpose of this checker is to return semantic diagnostics
|
||||
// creation is deferred - use getFullTypeCheckChecker to get instance
|
||||
var fullTypeCheckChecker_doNotAccessDirectly: TypeChecker;
|
||||
|
||||
var useCaseSensitivefilenames = false;
|
||||
var sourceFilesByName: Map<SourceFile> = {};
|
||||
var documentRegistry = documentRegistry;
|
||||
@ -1712,11 +1881,10 @@ module ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var declarations = symbol.getDeclarations();
|
||||
return {
|
||||
name: displayName,
|
||||
kind: getSymbolKind(symbol),
|
||||
kindModifiers: declarations ? getNodeModifiers(declarations[0]) : ScriptElementKindModifier.none
|
||||
kindModifiers: getSymbolModifiers(symbol)
|
||||
};
|
||||
}
|
||||
|
||||
@ -2197,6 +2365,12 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getSymbolModifiers(symbol: Symbol): string {
|
||||
return symbol && symbol.declarations && symbol.declarations.length > 0
|
||||
? getNodeModifiers(symbol.declarations[0])
|
||||
: ScriptElementKindModifier.none;
|
||||
}
|
||||
|
||||
function getNodeModifiers(node: Node): string {
|
||||
var flags = node.flags;
|
||||
var result: string[] = [];
|
||||
@ -2210,7 +2384,114 @@ module ts {
|
||||
return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none;
|
||||
}
|
||||
|
||||
/// QuickInfo
|
||||
function getQuickInfoAtPosition(fileName: string, position: number): QuickInfo {
|
||||
synchronizeHostData();
|
||||
|
||||
fileName = TypeScript.switchToForwardSlashes(fileName);
|
||||
var sourceFile = getSourceFile(fileName);
|
||||
var node = getNodeAtPosition(sourceFile, position);
|
||||
if (!node) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var symbol = typeInfoResolver.getSymbolInfo(node);
|
||||
if (!symbol) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var documentation = symbol.getDocumentationComment();
|
||||
var documentationParts = documentation === "" ? [] : [new SymbolDisplayPart(documentation, SymbolDisplayPartKind.text, /*symbol:*/ null)];
|
||||
|
||||
// Having all this logic here is pretty unclean. Consider moving to the roslyn model
|
||||
// where all symbol display logic is encapsulated into visitors and options.
|
||||
var totalParts: SymbolDisplayPart[] = [];
|
||||
|
||||
if (symbol.flags & SymbolFlags.Class) {
|
||||
totalParts.push(new SymbolDisplayPart("class", SymbolDisplayPartKind.keyword, undefined));
|
||||
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
|
||||
totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, sourceFile));
|
||||
}
|
||||
else if (symbol.flags & SymbolFlags.Interface) {
|
||||
totalParts.push(new SymbolDisplayPart("interface", SymbolDisplayPartKind.keyword, undefined));
|
||||
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
|
||||
totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, sourceFile));
|
||||
}
|
||||
else if (symbol.flags & SymbolFlags.Enum) {
|
||||
totalParts.push(new SymbolDisplayPart("enum", SymbolDisplayPartKind.keyword, undefined));
|
||||
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
|
||||
totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, sourceFile));
|
||||
}
|
||||
else if (symbol.flags & SymbolFlags.Module) {
|
||||
totalParts.push(new SymbolDisplayPart("module", SymbolDisplayPartKind.keyword, undefined));
|
||||
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
|
||||
totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, sourceFile));
|
||||
}
|
||||
else if (symbol.flags & SymbolFlags.TypeParameter) {
|
||||
totalParts.push(new SymbolDisplayPart("(", SymbolDisplayPartKind.punctuation, undefined));
|
||||
totalParts.push(new SymbolDisplayPart("type parameter", SymbolDisplayPartKind.text, undefined));
|
||||
totalParts.push(new SymbolDisplayPart(")", SymbolDisplayPartKind.punctuation, undefined));
|
||||
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
|
||||
totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol));
|
||||
}
|
||||
else {
|
||||
totalParts.push(new SymbolDisplayPart("(", SymbolDisplayPartKind.punctuation, undefined));
|
||||
var text: string;
|
||||
|
||||
if (symbol.flags & SymbolFlags.Property) { text = "property" }
|
||||
else if (symbol.flags & SymbolFlags.EnumMember) { text = "enum member" }
|
||||
else if (symbol.flags & SymbolFlags.Function) { text = "function" }
|
||||
else if (symbol.flags & SymbolFlags.Variable) { text = "variable" }
|
||||
else if (symbol.flags & SymbolFlags.Method) { text = "method" }
|
||||
|
||||
if (!text) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
totalParts.push(new SymbolDisplayPart(text, SymbolDisplayPartKind.text, undefined));
|
||||
totalParts.push(new SymbolDisplayPart(")", SymbolDisplayPartKind.punctuation, undefined));
|
||||
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
|
||||
|
||||
totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, getContainerNode(node)));
|
||||
|
||||
var type = typeInfoResolver.getTypeOfSymbol(symbol);
|
||||
|
||||
if (symbol.flags & SymbolFlags.Property ||
|
||||
symbol.flags & SymbolFlags.Variable) {
|
||||
|
||||
if (type) {
|
||||
totalParts.push(new SymbolDisplayPart(":", SymbolDisplayPartKind.punctuation, undefined));
|
||||
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
|
||||
totalParts.push.apply(totalParts, typeInfoResolver.typeToDisplayParts(type, getContainerNode(node)));
|
||||
}
|
||||
}
|
||||
else if (symbol.flags & SymbolFlags.Function ||
|
||||
symbol.flags & SymbolFlags.Method) {
|
||||
if (type) {
|
||||
totalParts.push.apply(totalParts, typeInfoResolver.typeToDisplayParts(type, getContainerNode(node)));
|
||||
}
|
||||
}
|
||||
else if (symbol.flags & SymbolFlags.EnumMember) {
|
||||
var declaration = symbol.declarations[0];
|
||||
if (declaration.kind === SyntaxKind.EnumMember) {
|
||||
var constantValue = typeInfoResolver.getEnumMemberValue(<EnumMember>declaration);
|
||||
if (constantValue !== undefined) {
|
||||
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
|
||||
totalParts.push(new SymbolDisplayPart("=", SymbolDisplayPartKind.operator, undefined));
|
||||
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
|
||||
totalParts.push(new SymbolDisplayPart(constantValue.toString(), SymbolDisplayPartKind.numericLiteral, undefined));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new QuickInfo(
|
||||
getSymbolKind(symbol),
|
||||
getSymbolModifiers(symbol),
|
||||
new TypeScript.TextSpan(node.getStart(), node.getWidth()),
|
||||
totalParts,
|
||||
documentationParts);
|
||||
}
|
||||
|
||||
function getTypeAtPosition(fileName: string, position: number): TypeInfo {
|
||||
synchronizeHostData();
|
||||
|
||||
@ -3926,8 +4207,8 @@ module ts {
|
||||
}
|
||||
|
||||
// Looks to be within the trivia. See if we can find the comment containing it.
|
||||
if (!getContainingComment(getTrailingComments(fileContents, token.getFullStart()), matchPosition) &&
|
||||
!getContainingComment(getLeadingComments(fileContents, token.getFullStart()), matchPosition)) {
|
||||
if (!getContainingComment(getTrailingCommentRanges(fileContents, token.getFullStart()), matchPosition) &&
|
||||
!getContainingComment(getLeadingCommentRanges(fileContents, token.getFullStart()), matchPosition)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -4014,7 +4295,7 @@ module ts {
|
||||
return new RegExp(regExpString, "gim");
|
||||
}
|
||||
|
||||
function getContainingComment(comments: Comment[], position: number): Comment {
|
||||
function getContainingComment(comments: CommentRange[], position: number): CommentRange {
|
||||
if (comments) {
|
||||
for (var i = 0, n = comments.length; i < n; i++) {
|
||||
var comment = comments[i];
|
||||
@ -4052,7 +4333,7 @@ module ts {
|
||||
var kind = getSymbolKind(symbol);
|
||||
if (kind) {
|
||||
return RenameInfo.Create(symbol.name, typeInfoResolver.getFullyQualifiedName(symbol), kind,
|
||||
getNodeModifiers(symbol.getDeclarations()[0]),
|
||||
getSymbolModifiers(symbol),
|
||||
new TypeScript.TextSpan(node.getStart(), node.getWidth()));
|
||||
}
|
||||
}
|
||||
@ -4072,6 +4353,7 @@ module ts {
|
||||
getCompletionsAtPosition: getCompletionsAtPosition,
|
||||
getCompletionEntryDetails: getCompletionEntryDetails,
|
||||
getTypeAtPosition: getTypeAtPosition,
|
||||
getQuickInfoAtPosition: getQuickInfoAtPosition,
|
||||
getSignatureHelpItems: (filename, position): SignatureHelpItems => null,
|
||||
getSignatureHelpCurrentArgumentState: (fileName, position, applicableSpanStart): SignatureHelpState => null,
|
||||
getDefinitionAtPosition: getDefinitionAtPosition,
|
||||
|
||||
@ -87,7 +87,9 @@ module ts {
|
||||
getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean): string;
|
||||
getCompletionEntryDetails(fileName: string, position: number, entryName: string): string;
|
||||
|
||||
getQuickInfoAtPosition(fileName: string, position: number): string;
|
||||
getTypeAtPosition(fileName: string, position: number): string;
|
||||
|
||||
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string;
|
||||
getBreakpointStatementAtPosition(fileName: string, position: number): string;
|
||||
|
||||
@ -540,6 +542,16 @@ module ts {
|
||||
/// QUICKINFO
|
||||
/// Computes a string representation of the type at the requested position
|
||||
/// in the active file.
|
||||
public getQuickInfoAtPosition(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getQuickInfoAtPosition('" + fileName + "', " + position + ")",
|
||||
() => {
|
||||
var quickInfo = this.languageService.getQuickInfoAtPosition(fileName, position);
|
||||
return quickInfo;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public getTypeAtPosition(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getTypeAtPosition('" + fileName + "', " + position + ")",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user