Merge remote-tracking branch 'origin/master' into useReturnedThisFromSuperCalls

This commit is contained in:
Daniel Rosenwasser
2016-09-20 12:31:02 -04:00
306 changed files with 4775 additions and 1754 deletions
+2 -1
View File
@@ -129,6 +129,7 @@ var servicesSources = [
"documentRegistry.ts",
"findAllReferences.ts",
"goToDefinition.ts",
"goToImplementation.ts",
"jsDoc.ts",
"jsTyping.ts",
"navigateTo.ts",
@@ -789,7 +790,7 @@ function cleanTestDirs() {
// used to pass data from jake command line directly to run.js
function writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stackTraceLimit) {
var testConfigContents = JSON.stringify({
var testConfigContents = JSON.stringify({
test: tests ? [tests] : undefined,
light: light,
workerCount: workerCount,
+2 -4
View File
@@ -268,7 +268,7 @@ namespace ts {
Debug.assert(node.parent.kind === SyntaxKind.JSDocFunctionType);
let functionType = <JSDocFunctionType>node.parent;
let index = indexOf(functionType.parameters, node);
return "p" + index;
return "arg" + index;
case SyntaxKind.JSDocTypedefTag:
const parentNode = node.parent && node.parent.parent;
let nameFromParentNode: string;
@@ -540,9 +540,7 @@ namespace ts {
// because the scope of JsDocComment should not be affected by whether the current node is a
// container or not.
if (isInJavaScriptFile(node) && node.jsDocComments) {
for (const jsDocComment of node.jsDocComments) {
bind(jsDocComment);
}
forEach(node.jsDocComments, bind);
}
if (checkUnreachable(node)) {
forEachChild(node, bind);
+31 -15
View File
@@ -914,8 +914,8 @@ namespace ts {
}
}
// If we're in an external module, we can't reference symbols created from UMD export declarations
if (result && isInExternalModule) {
// If we're in an external module, we can't reference value symbols created from UMD export declarations
if (result && isInExternalModule && (meaning & SymbolFlags.Value) === SymbolFlags.Value) {
const decls = result.declarations;
if (decls && decls.length === 1 && decls[0].kind === SyntaxKind.NamespaceExportDeclaration) {
error(errorLocation, Diagnostics.Identifier_0_must_be_imported_from_a_module, name);
@@ -1758,7 +1758,15 @@ namespace ts {
return false;
}
function isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessibilityResult {
/**
* Check if the given symbol in given enclosing declaration is accessible and mark all associated alias to be visible if requested
*
* @param symbol a Symbol to check if accessible
* @param enclosingDeclaration a Node containing reference to the symbol
* @param meaning a SymbolFlags to check if such meaning of the symbol is accessible
* @param shouldComputeAliasToMakeVisible a boolean value to indicate whether to return aliases to be mark visible in case the symbol is accessible
*/
function isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean): SymbolAccessibilityResult {
if (symbol && enclosingDeclaration && !(symbol.flags & SymbolFlags.TypeParameter)) {
const initialSymbol = symbol;
let meaningToLook = meaning;
@@ -1766,7 +1774,7 @@ namespace ts {
// Symbol is accessible if it by itself is accessible
const accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaningToLook, /*useOnlyExternalAliasing*/ false);
if (accessibleSymbolChain) {
const hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0]);
const hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0], shouldComputeAliasesToMakeVisible);
if (!hasAccessibleDeclarations) {
return <SymbolAccessibilityResult>{
accessibility: SymbolAccessibility.NotAccessible,
@@ -1830,7 +1838,7 @@ namespace ts {
return isAmbientModule(declaration) || (declaration.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(<SourceFile>declaration));
}
function hasVisibleDeclarations(symbol: Symbol): SymbolVisibilityResult {
function hasVisibleDeclarations(symbol: Symbol, shouldComputeAliasToMakeVisible: boolean): SymbolVisibilityResult {
let aliasesToMakeVisible: AnyImportSyntax[];
if (forEach(symbol.declarations, declaration => !getIsDeclarationVisible(declaration))) {
return undefined;
@@ -1846,14 +1854,19 @@ namespace ts {
if (anyImportSyntax &&
!(getModifierFlags(anyImportSyntax) & ModifierFlags.Export) && // import clause without export
isDeclarationVisible(<Declaration>anyImportSyntax.parent)) {
getNodeLinks(declaration).isVisible = true;
if (aliasesToMakeVisible) {
if (!contains(aliasesToMakeVisible, anyImportSyntax)) {
aliasesToMakeVisible.push(anyImportSyntax);
// In function "buildTypeDisplay" where we decide whether to write type-alias or serialize types,
// we want to just check if type- alias is accessible or not but we don't care about emitting those alias at that time
// since we will do the emitting later in trackSymbol.
if (shouldComputeAliasToMakeVisible) {
getNodeLinks(declaration).isVisible = true;
if (aliasesToMakeVisible) {
if (!contains(aliasesToMakeVisible, anyImportSyntax)) {
aliasesToMakeVisible.push(anyImportSyntax);
}
}
else {
aliasesToMakeVisible = [anyImportSyntax];
}
}
else {
aliasesToMakeVisible = [anyImportSyntax];
}
return true;
}
@@ -1888,7 +1901,7 @@ namespace ts {
const symbol = resolveName(enclosingDeclaration, (<Identifier>firstIdentifier).text, meaning, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined);
// Verify if the symbol is accessible
return (symbol && hasVisibleDeclarations(symbol)) || <SymbolVisibilityResult>{
return (symbol && hasVisibleDeclarations(symbol, /*shouldComputeAliasToMakeVisible*/ true)) || <SymbolVisibilityResult>{
accessibility: SymbolAccessibility.NotAccessible,
errorSymbolName: getTextOfNode(firstIdentifier),
errorNode: firstIdentifier
@@ -2163,7 +2176,9 @@ namespace ts {
// The specified symbol flags need to be reinterpreted as type flags
buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags);
}
else if (!(flags & TypeFormatFlags.InTypeAlias) && type.flags & (TypeFlags.Anonymous | TypeFlags.UnionOrIntersection) && type.aliasSymbol) {
else if (!(flags & TypeFormatFlags.InTypeAlias) && type.flags & (TypeFlags.Anonymous | TypeFlags.UnionOrIntersection) && type.aliasSymbol &&
isSymbolAccessible(type.aliasSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) {
// Only write out inferred type with its corresponding type-alias if type-alias is visible
const typeArguments = type.aliasTypeArguments;
writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, typeArguments ? typeArguments.length : 0, nextFlags);
}
@@ -5653,12 +5668,13 @@ namespace ts {
case SyntaxKind.JSDocThisType:
case SyntaxKind.JSDocOptionalType:
return getTypeFromTypeNode((<ParenthesizedTypeNode | JSDocTypeReferencingNode>node).type);
case SyntaxKind.JSDocRecordType:
return getTypeFromTypeNode((node as JSDocRecordType).literal);
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructorType:
case SyntaxKind.TypeLiteral:
case SyntaxKind.JSDocTypeLiteral:
case SyntaxKind.JSDocFunctionType:
case SyntaxKind.JSDocRecordType:
return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node, aliasSymbol, aliasTypeArguments);
// This function assumes that an identifier or qualified name is a type expression
// Callers should first ensure this by calling isTypeNode
+1 -1
View File
@@ -306,7 +306,7 @@ namespace ts {
}
function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning));
handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning, /*shouldComputeAliasesToMakeVisible*/ true));
recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForSymbol(symbol, meaning));
}
+272 -142
View File
@@ -379,7 +379,7 @@ namespace ts {
case SyntaxKind.JSDocNullableType:
return visitNode(cbNode, (<JSDocNullableType>node).type);
case SyntaxKind.JSDocRecordType:
return visitNodes(cbNodes, (<JSDocRecordType>node).members);
return visitNode(cbNode, (<JSDocRecordType>node).literal);
case SyntaxKind.JSDocTypeReference:
return visitNode(cbNode, (<JSDocTypeReference>node).name) ||
visitNodes(cbNodes, (<JSDocTypeReference>node).typeArguments);
@@ -398,7 +398,7 @@ namespace ts {
return visitNode(cbNode, (<JSDocRecordMember>node).name) ||
visitNode(cbNode, (<JSDocRecordMember>node).type);
case SyntaxKind.JSDocComment:
return visitNodes(cbNodes, (<JSDocComment>node).tags);
return visitNodes(cbNodes, (<JSDoc>node).tags);
case SyntaxKind.JSDocParameterTag:
return visitNode(cbNode, (<JSDocParameterTag>node).preParameterName) ||
visitNode(cbNode, (<JSDocParameterTag>node).typeExpression) ||
@@ -453,10 +453,10 @@ namespace ts {
/* @internal */
export function parseIsolatedJSDocComment(content: string, start?: number, length?: number) {
const result = Parser.JSDocParser.parseIsolatedJSDocComment(content, start, length);
if (result && result.jsDocComment) {
if (result && result.jsDoc) {
// because the jsDocComment was parsed out of the source file, it might
// not be covered by the fixupParentReferences.
Parser.fixupParentReferences(result.jsDocComment);
Parser.fixupParentReferences(result.jsDoc);
}
return result;
@@ -655,20 +655,18 @@ namespace ts {
function addJSDocComment<T extends Node>(node: T): T {
if (contextFlags & NodeFlags.JavaScriptFile) {
const comments = getLeadingCommentRangesOfNode(node, sourceFile);
if (comments) {
for (const comment of comments) {
const jsDocComment = JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos);
if (!jsDocComment) {
continue;
}
if (!node.jsDocComments) {
node.jsDocComments = [];
}
node.jsDocComments.push(jsDocComment);
const comments = getJsDocCommentsFromText(node, sourceFile.text);
if (comments) {
for (const comment of comments) {
const jsDoc = JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos);
if (!jsDoc) {
continue;
}
if (!node.jsDocComments) {
node.jsDocComments = [];
}
node.jsDocComments.push(jsDoc);
}
}
@@ -2204,7 +2202,7 @@ namespace ts {
}
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, node);
parseTypeMemberSemicolon();
return finishNode(node);
return addJSDocComment(finishNode(node));
}
function isIndexSignature(): boolean {
@@ -2294,7 +2292,7 @@ namespace ts {
// [Yield] nor [Await]
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, method);
parseTypeMemberSemicolon();
return finishNode(method);
return addJSDocComment(finishNode(method));
}
else {
const property = <PropertySignature>createNode(SyntaxKind.PropertySignature, fullStart);
@@ -2311,7 +2309,7 @@ namespace ts {
}
parseTypeMemberSemicolon();
return finishNode(property);
return addJSDocComment(finishNode(property));
}
}
@@ -2898,7 +2896,7 @@ namespace ts {
node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, "=>");
node.body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier);
return finishNode(node);
return addJSDocComment(finishNode(node));
}
function tryParseParenthesizedArrowFunctionExpression(): Expression {
@@ -2931,7 +2929,7 @@ namespace ts {
? parseArrowFunctionExpressionBody(isAsync)
: parseIdentifier();
return finishNode(arrowFunction);
return addJSDocComment(finishNode(arrowFunction));
}
// True -> We definitely expect a parenthesized arrow function here.
@@ -4114,7 +4112,7 @@ namespace ts {
function tryParseAccessorDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: NodeArray<Modifier>): AccessorDeclaration {
if (parseContextualModifier(SyntaxKind.GetKeyword)) {
return addJSDocComment(parseAccessorDeclaration(SyntaxKind.GetAccessor, fullStart, decorators, modifiers));
return parseAccessorDeclaration(SyntaxKind.GetAccessor, fullStart, decorators, modifiers);
}
else if (parseContextualModifier(SyntaxKind.SetKeyword)) {
return parseAccessorDeclaration(SyntaxKind.SetAccessor, fullStart, decorators, modifiers);
@@ -4997,7 +4995,7 @@ namespace ts {
: doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.DisallowInContext, parseNonParameterInitializer);
parseSemicolon();
return finishNode(property);
return addJSDocComment(finishNode(property));
}
function parsePropertyOrMethodDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: NodeArray<Modifier>): ClassElement {
@@ -5026,7 +5024,7 @@ namespace ts {
node.name = parsePropertyName();
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, node);
node.body = parseFunctionBlockOrSemicolon(/*isGenerator*/ false, /*isAsync*/ false);
return finishNode(node);
return addJSDocComment(finishNode(node));
}
function isClassMemberModifier(idToken: SyntaxKind) {
@@ -5264,7 +5262,7 @@ namespace ts {
node.members = createMissingList<ClassElement>();
}
return finishNode(node);
return addJSDocComment(finishNode(node));
}
function parseNameOfClassDeclarationOrExpression(): Identifier {
@@ -5332,7 +5330,7 @@ namespace ts {
node.typeParameters = parseTypeParameters();
node.heritageClauses = parseHeritageClauses(/*isClassHeritageClause*/ false);
node.members = parseObjectTypeMembers();
return finishNode(node);
return addJSDocComment(finishNode(node));
}
function parseTypeAliasDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: NodeArray<Modifier>): TypeAliasDeclaration {
@@ -5356,7 +5354,7 @@ namespace ts {
const node = <EnumMember>createNode(SyntaxKind.EnumMember, scanner.getStartPos());
node.name = parsePropertyName();
node.initializer = allowInAnd(parseNonParameterInitializer);
return finishNode(node);
return addJSDocComment(finishNode(node));
}
function parseEnumDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: NodeArray<Modifier>): EnumDeclaration {
@@ -5372,7 +5370,7 @@ namespace ts {
else {
node.members = createMissingList<EnumMember>();
}
return finishNode(node);
return addJSDocComment(finishNode(node));
}
function parseModuleBlock(): ModuleBlock {
@@ -5399,7 +5397,7 @@ namespace ts {
node.body = parseOptional(SyntaxKind.DotToken)
? parseModuleOrNamespaceDeclaration(getNodePos(), /*decorators*/ undefined, /*modifiers*/ undefined, NodeFlags.NestedNamespace | namespaceFlag)
: parseModuleBlock();
return finishNode(node);
return addJSDocComment(finishNode(node));
}
function parseAmbientExternalModuleDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: NodeArray<Modifier>): ModuleDeclaration {
@@ -5488,7 +5486,7 @@ namespace ts {
parseExpected(SyntaxKind.EqualsToken);
importEqualsDeclaration.moduleReference = parseModuleReference();
parseSemicolon();
return finishNode(importEqualsDeclaration);
return addJSDocComment(finishNode(importEqualsDeclaration));
}
}
@@ -5809,6 +5807,7 @@ namespace ts {
export function parseJSDocTypeExpressionForTests(content: string, start: number, length: number) {
initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS);
sourceFile = createSourceFile("file.js", ScriptTarget.Latest, ScriptKind.JS);
scanner.setText(content, start, length);
currentToken = scanner.scan();
const jsDocTypeExpression = parseJSDocTypeExpression();
@@ -6027,22 +6026,7 @@ namespace ts {
function parseJSDocRecordType(): JSDocRecordType {
const result = <JSDocRecordType>createNode(SyntaxKind.JSDocRecordType);
nextToken();
result.members = parseDelimitedList(ParsingContext.JSDocRecordMembers, parseJSDocRecordMember);
checkForTrailingComma(result.members);
parseExpected(SyntaxKind.CloseBraceToken);
return finishNode(result);
}
function parseJSDocRecordMember(): JSDocRecordMember {
const result = <JSDocRecordMember>createNode(SyntaxKind.JSDocRecordMember);
result.name = parseSimplePropertyName();
if (token() === SyntaxKind.ColonToken) {
nextToken();
result.type = parseJSDocType();
}
result.literal = parseTypeLiteral();
return finishNode(result);
}
@@ -6140,14 +6124,14 @@ namespace ts {
export function parseIsolatedJSDocComment(content: string, start: number, length: number) {
initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS);
sourceFile = <SourceFile>{ languageVariant: LanguageVariant.Standard, text: content };
const jsDocComment = parseJSDocCommentWorker(start, length);
const jsDoc = parseJSDocCommentWorker(start, length);
const diagnostics = parseDiagnostics;
clearState();
return jsDocComment ? { jsDocComment, diagnostics } : undefined;
return jsDoc ? { jsDoc, diagnostics } : undefined;
}
export function parseJSDocComment(parent: Node, start: number, length: number): JSDocComment {
export function parseJSDocComment(parent: Node, start: number, length: number): JSDoc {
const saveToken = currentToken;
const saveParseDiagnosticsLength = parseDiagnostics.length;
const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode;
@@ -6164,7 +6148,13 @@ namespace ts {
return comment;
}
export function parseJSDocCommentWorker(start: number, length: number): JSDocComment {
const enum JSDocState {
BeginningOfLine,
SawAsterisk,
SavingComments,
}
export function parseJSDocCommentWorker(start: number, length: number): JSDoc {
const content = sourceText;
start = start || 0;
const end = length === undefined ? content.length : start + length;
@@ -6175,76 +6165,134 @@ namespace ts {
Debug.assert(end <= content.length);
let tags: NodeArray<JSDocTag>;
let result: JSDocComment;
const comments: string[] = [];
let result: JSDoc;
// Check for /** (JSDoc opening part)
if (content.charCodeAt(start) === CharacterCodes.slash &&
content.charCodeAt(start + 1) === CharacterCodes.asterisk &&
content.charCodeAt(start + 2) === CharacterCodes.asterisk &&
content.charCodeAt(start + 3) !== CharacterCodes.asterisk) {
if (!isJsDocStart(content, start)) {
return result;
}
// + 3 for leading /**, - 5 in total for /** */
scanner.scanRange(start + 3, length - 5, () => {
// Initially we can parse out a tag. We also have seen a starting asterisk.
// This is so that /** * @type */ doesn't parse.
let advanceToken = true;
let state = JSDocState.SawAsterisk;
let margin: number | undefined = undefined;
// + 4 for leading '/** '
let indent = start - Math.max(content.lastIndexOf("\n", start), 0) + 4;
function pushComment(text: string) {
if (!margin) {
margin = indent;
}
comments.push(text);
indent += text.length;
}
// + 3 for leading /**, - 5 in total for /** */
scanner.scanRange(start + 3, length - 5, () => {
// Initially we can parse out a tag. We also have seen a starting asterisk.
// This is so that /** * @type */ doesn't parse.
let canParseTag = true;
let seenAsterisk = true;
nextJSDocToken();
while (token() === SyntaxKind.WhitespaceTrivia) {
nextJSDocToken();
while (token() !== SyntaxKind.EndOfFileToken) {
switch (token()) {
case SyntaxKind.AtToken:
if (canParseTag) {
parseTag();
}
// This will take us to the end of the line, so it's OK to parse a tag on the next pass through the loop
seenAsterisk = false;
break;
case SyntaxKind.NewLineTrivia:
// After a line break, we can parse a tag, and we haven't seen an asterisk on the next line yet
canParseTag = true;
seenAsterisk = false;
break;
case SyntaxKind.AsteriskToken:
if (seenAsterisk) {
// If we've already seen an asterisk, then we can no longer parse a tag on this line
canParseTag = false;
}
}
if (token() === SyntaxKind.NewLineTrivia) {
state = JSDocState.BeginningOfLine;
nextJSDocToken();
}
while (token() !== SyntaxKind.EndOfFileToken) {
switch (token()) {
case SyntaxKind.AtToken:
if (state === JSDocState.BeginningOfLine || state === JSDocState.SawAsterisk) {
removeTrailingNewlines(comments);
parseTag(indent);
// NOTE: According to usejsdoc.org, a tag goes to end of line, except the last tag.
// Real-world comments may break this rule, so "BeginningOfLine" will not be a real line beginning
// for malformed examples like `/** @param {string} x @returns {number} the length */`
state = JSDocState.BeginningOfLine;
advanceToken = false;
margin = undefined;
indent++;
}
else {
pushComment(scanner.getTokenText());
}
break;
case SyntaxKind.NewLineTrivia:
comments.push(scanner.getTokenText());
state = JSDocState.BeginningOfLine;
indent = 0;
break;
case SyntaxKind.AsteriskToken:
const asterisk = scanner.getTokenText();
if (state === JSDocState.SawAsterisk) {
// If we've already seen an asterisk, then we can no longer parse a tag on this line
state = JSDocState.SavingComments;
pushComment(asterisk);
}
else {
// Ignore the first asterisk on a line
seenAsterisk = true;
break;
case SyntaxKind.Identifier:
// Anything else is doc comment text. We can't do anything with it. Because it
// wasn't a tag, we can no longer parse a tag on this line until we hit the next
// line break.
canParseTag = false;
break;
case SyntaxKind.EndOfFileToken:
break;
}
state = JSDocState.SawAsterisk;
indent += asterisk.length;
}
break;
case SyntaxKind.Identifier:
// Anything else is doc comment text. We just save it. Because it
// wasn't a tag, we can no longer parse a tag on this line until we hit the next
// line break.
pushComment(scanner.getTokenText());
state = JSDocState.SavingComments;
break;
case SyntaxKind.WhitespaceTrivia:
// only collect whitespace if we're already saving comments or have just crossed the comment indent margin
const whitespace = scanner.getTokenText();
if (state === JSDocState.SavingComments || margin !== undefined && indent + whitespace.length > margin) {
comments.push(whitespace.slice(margin - indent - 1));
}
indent += whitespace.length;
break;
case SyntaxKind.EndOfFileToken:
break;
default:
pushComment(scanner.getTokenText());
break;
}
if (advanceToken) {
nextJSDocToken();
}
else {
advanceToken = true;
}
}
removeLeadingNewlines(comments);
removeTrailingNewlines(comments);
result = createJSDocComment();
result = createJSDocComment();
});
}
});
return result;
function createJSDocComment(): JSDocComment {
if (!tags) {
return undefined;
function removeLeadingNewlines(comments: string[]) {
while (comments.length && (comments[0] === "\n" || comments[0] === "\r")) {
comments.shift();
}
}
const result = <JSDocComment>createNode(SyntaxKind.JSDocComment, start);
function removeTrailingNewlines(comments: string[]) {
while (comments.length && (comments[comments.length - 1] === "\n" || comments[comments.length - 1] === "\r")) {
comments.pop();
}
}
function isJsDocStart(content: string, start: number) {
return content.charCodeAt(start) === CharacterCodes.slash &&
content.charCodeAt(start + 1) === CharacterCodes.asterisk &&
content.charCodeAt(start + 2) === CharacterCodes.asterisk &&
content.charCodeAt(start + 3) !== CharacterCodes.asterisk;
}
function createJSDocComment(): JSDoc {
const result = <JSDoc>createNode(SyntaxKind.JSDocComment, start);
result.tags = tags;
result.comment = comments.length ? comments.join("") : undefined;
return finishNode(result, end);
}
@@ -6254,78 +6302,154 @@ namespace ts {
}
}
function parseTag(): void {
function parseTag(indent: number) {
Debug.assert(token() === SyntaxKind.AtToken);
const atToken = createNode(SyntaxKind.AtToken, scanner.getTokenPos());
atToken.end = scanner.getTextPos();
nextJSDocToken();
const tagName = parseJSDocIdentifierName();
skipWhitespace();
if (!tagName) {
return;
}
const tag = handleTag(atToken, tagName) || handleUnknownTag(atToken, tagName);
addTag(tag);
}
function handleTag(atToken: Node, tagName: Identifier): JSDocTag {
let tag: JSDocTag;
if (tagName) {
switch (tagName.text) {
case "param":
return handleParamTag(atToken, tagName);
tag = parseParamTag(atToken, tagName);
break;
case "return":
case "returns":
return handleReturnTag(atToken, tagName);
tag = parseReturnTag(atToken, tagName);
break;
case "template":
return handleTemplateTag(atToken, tagName);
tag = parseTemplateTag(atToken, tagName);
break;
case "type":
return handleTypeTag(atToken, tagName);
tag = parseTypeTag(atToken, tagName);
break;
case "typedef":
return handleTypedefTag(atToken, tagName);
tag = parseTypedefTag(atToken, tagName);
break;
default:
tag = parseUnknownTag(atToken, tagName);
break;
}
}
else {
tag = parseUnknownTag(atToken, tagName);
}
return undefined;
if (!tag) {
// a badly malformed tag should not be added to the list of tags
return;
}
addTag(tag, parseTagComments(indent + tag.end - tag.pos));
}
function handleUnknownTag(atToken: Node, tagName: Identifier) {
function parseTagComments(indent: number) {
const comments: string[] = [];
let state = JSDocState.SawAsterisk;
let margin: number | undefined;
function pushComment(text: string) {
if (!margin) {
margin = indent;
}
comments.push(text);
indent += text.length;
}
while (token() !== SyntaxKind.AtToken && token() !== SyntaxKind.EndOfFileToken) {
switch (token()) {
case SyntaxKind.NewLineTrivia:
if (state >= JSDocState.SawAsterisk) {
state = JSDocState.BeginningOfLine;
comments.push(scanner.getTokenText());
}
indent = 0;
break;
case SyntaxKind.AtToken:
// Done
break;
case SyntaxKind.WhitespaceTrivia:
if (state === JSDocState.SavingComments) {
pushComment(scanner.getTokenText());
}
else {
const whitespace = scanner.getTokenText();
// if the whitespace crosses the margin, take only the whitespace that passes the margin
if (margin !== undefined && indent + whitespace.length > margin) {
comments.push(whitespace.slice(margin - indent - 1));
}
indent += whitespace.length;
}
break;
case SyntaxKind.AsteriskToken:
if (state === JSDocState.BeginningOfLine) {
// leading asterisks start recording on the *next* (non-whitespace) token
state = JSDocState.SawAsterisk;
indent += scanner.getTokenText().length;
break;
}
// FALLTHROUGH otherwise to record the * as a comment
default:
state = JSDocState.SavingComments; // leading identifiers start recording as well
pushComment(scanner.getTokenText());
break;
}
if (token() === SyntaxKind.AtToken) {
// Done
break;
}
nextJSDocToken();
}
removeLeadingNewlines(comments);
removeTrailingNewlines(comments);
return comments;
}
function parseUnknownTag(atToken: Node, tagName: Identifier) {
const result = <JSDocTag>createNode(SyntaxKind.JSDocTag, atToken.pos);
result.atToken = atToken;
result.tagName = tagName;
return finishNode(result);
}
function addTag(tag: JSDocTag): void {
if (tag) {
if (!tags) {
tags = createNodeArray([tag], tag.pos);
}
else {
tags.push(tag);
}
tags.end = tag.end;
function addTag(tag: JSDocTag, comments: string[]): void {
tag.comment = comments.join("");
if (!tags) {
tags = createNodeArray([tag], tag.pos);
}
else {
tags.push(tag);
}
tags.end = tag.end;
}
function tryParseTypeExpression(): JSDocTypeExpression {
if (token() !== SyntaxKind.OpenBraceToken) {
return undefined;
}
return tryParse(() => {
skipWhitespace();
if (token() !== SyntaxKind.OpenBraceToken) {
return undefined;
}
const typeExpression = parseJSDocTypeExpression();
return typeExpression;
return parseJSDocTypeExpression();
});
}
function handleParamTag(atToken: Node, tagName: Identifier) {
function parseParamTag(atToken: Node, tagName: Identifier) {
let typeExpression = tryParseTypeExpression();
skipWhitespace();
let name: Identifier;
let isBracketed: boolean;
// Looking for something like '[foo]' or 'foo'
if (parseOptionalToken(SyntaxKind.OpenBracketToken)) {
name = parseJSDocIdentifierName();
skipWhitespace();
isBracketed = true;
// May have an optional default, e.g. '[foo = 42]'
@@ -6362,11 +6486,12 @@ namespace ts {
result.preParameterName = preName;
result.typeExpression = typeExpression;
result.postParameterName = postName;
result.parameterName = postName || preName;
result.isBracketed = isBracketed;
return finishNode(result);
}
function handleReturnTag(atToken: Node, tagName: Identifier): JSDocReturnTag {
function parseReturnTag(atToken: Node, tagName: Identifier): JSDocReturnTag {
if (forEach(tags, t => t.kind === SyntaxKind.JSDocReturnTag)) {
parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_already_specified, tagName.text);
}
@@ -6378,7 +6503,7 @@ namespace ts {
return finishNode(result);
}
function handleTypeTag(atToken: Node, tagName: Identifier): JSDocTypeTag {
function parseTypeTag(atToken: Node, tagName: Identifier): JSDocTypeTag {
if (forEach(tags, t => t.kind === SyntaxKind.JSDocTypeTag)) {
parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_already_specified, tagName.text);
}
@@ -6390,10 +6515,11 @@ namespace ts {
return finishNode(result);
}
function handlePropertyTag(atToken: Node, tagName: Identifier): JSDocPropertyTag {
function parsePropertyTag(atToken: Node, tagName: Identifier): JSDocPropertyTag {
const typeExpression = tryParseTypeExpression();
skipWhitespace();
const name = parseJSDocIdentifierName();
skipWhitespace();
if (!name) {
parseErrorAtPosition(scanner.getStartPos(), /*length*/ 0, Diagnostics.Identifier_expected);
return undefined;
@@ -6407,7 +6533,7 @@ namespace ts {
return finishNode(result);
}
function handleTypedefTag(atToken: Node, tagName: Identifier): JSDocTypedefTag {
function parseTypedefTag(atToken: Node, tagName: Identifier): JSDocTypedefTag {
const typeExpression = tryParseTypeExpression();
skipWhitespace();
@@ -6416,6 +6542,7 @@ namespace ts {
typedefTag.tagName = tagName;
typedefTag.name = parseJSDocIdentifierName();
typedefTag.typeExpression = typeExpression;
skipWhitespace();
if (typeExpression) {
if (typeExpression.type.kind === SyntaxKind.JSDocTypeReference) {
@@ -6485,6 +6612,7 @@ namespace ts {
nextJSDocToken();
const tagName = parseJSDocIdentifierName();
skipWhitespace();
if (!tagName) {
return false;
}
@@ -6495,21 +6623,21 @@ namespace ts {
// already has a @type tag, terminate the parent tag now.
return false;
}
parentTag.jsDocTypeTag = handleTypeTag(atToken, tagName);
parentTag.jsDocTypeTag = parseTypeTag(atToken, tagName);
return true;
case "prop":
case "property":
if (!parentTag.jsDocPropertyTags) {
parentTag.jsDocPropertyTags = <NodeArray<JSDocPropertyTag>>[];
}
const propertyTag = handlePropertyTag(atToken, tagName);
const propertyTag = parsePropertyTag(atToken, tagName);
parentTag.jsDocPropertyTags.push(propertyTag);
return true;
}
return false;
}
function handleTemplateTag(atToken: Node, tagName: Identifier): JSDocTemplateTag {
function parseTemplateTag(atToken: Node, tagName: Identifier): JSDocTemplateTag {
if (forEach(tags, t => t.kind === SyntaxKind.JSDocTemplateTag)) {
parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_already_specified, tagName.text);
}
@@ -6519,6 +6647,7 @@ namespace ts {
while (true) {
const name = parseJSDocIdentifierName();
skipWhitespace();
if (!name) {
parseErrorAtPosition(scanner.getStartPos(), 0, Diagnostics.Identifier_expected);
return undefined;
@@ -6532,6 +6661,7 @@ namespace ts {
if (token() === SyntaxKind.CommaToken) {
nextJSDocToken();
skipWhitespace();
}
else {
break;
+27 -21
View File
@@ -1759,40 +1759,46 @@ namespace ts {
}
startPos = pos;
// Eat leading whitespace
let ch = text.charCodeAt(pos);
while (pos < end) {
ch = text.charCodeAt(pos);
if (isWhiteSpaceSingleLine(ch)) {
pos++;
}
else {
break;
}
}
tokenPos = pos;
const ch = text.charCodeAt(pos);
switch (ch) {
case CharacterCodes.tab:
case CharacterCodes.verticalTab:
case CharacterCodes.formFeed:
case CharacterCodes.space:
while (pos < end && isWhiteSpaceSingleLine(text.charCodeAt(pos))) {
pos++;
}
return token = SyntaxKind.WhitespaceTrivia;
case CharacterCodes.at:
return pos += 1, token = SyntaxKind.AtToken;
pos++;
return token = SyntaxKind.AtToken;
case CharacterCodes.lineFeed:
case CharacterCodes.carriageReturn:
return pos += 1, token = SyntaxKind.NewLineTrivia;
pos++;
return token = SyntaxKind.NewLineTrivia;
case CharacterCodes.asterisk:
return pos += 1, token = SyntaxKind.AsteriskToken;
pos++;
return token = SyntaxKind.AsteriskToken;
case CharacterCodes.openBrace:
return pos += 1, token = SyntaxKind.OpenBraceToken;
pos++;
return token = SyntaxKind.OpenBraceToken;
case CharacterCodes.closeBrace:
return pos += 1, token = SyntaxKind.CloseBraceToken;
pos++;
return token = SyntaxKind.CloseBraceToken;
case CharacterCodes.openBracket:
return pos += 1, token = SyntaxKind.OpenBracketToken;
pos++;
return token = SyntaxKind.OpenBracketToken;
case CharacterCodes.closeBracket:
return pos += 1, token = SyntaxKind.CloseBracketToken;
pos++;
return token = SyntaxKind.CloseBracketToken;
case CharacterCodes.equals:
return pos += 1, token = SyntaxKind.EqualsToken;
pos++;
return token = SyntaxKind.EqualsToken;
case CharacterCodes.comma:
return pos += 1, token = SyntaxKind.CommaToken;
pos++;
return token = SyntaxKind.CommaToken;
}
if (isIdentifierStart(ch, ScriptTarget.Latest)) {
+8 -8
View File
@@ -804,17 +804,17 @@ namespace ts {
* Adds a trailing VariableStatement for an enum or module declaration.
*/
function addVarForExportedEnumOrNamespaceDeclaration(statements: Statement[], node: EnumDeclaration | ModuleDeclaration) {
statements.push(
createVariableStatement(
/*modifiers*/ undefined,
[createVariableDeclaration(
getDeclarationName(node),
const transformedStatement = createVariableStatement(
/*modifiers*/ undefined,
[createVariableDeclaration(
getDeclarationName(node),
/*type*/ undefined,
createPropertyAccess(createIdentifier("exports"), getDeclarationName(node))
)],
createPropertyAccess(createIdentifier("exports"), getDeclarationName(node))
)],
/*location*/ node
)
);
setNodeEmitFlags(transformedStatement, NodeEmitFlags.NoComments);
statements.push(transformedStatement);
}
function getDeclarationName(node: DeclarationStatement) {
+37 -12
View File
@@ -694,19 +694,21 @@ namespace ts {
// let ${name} = ${classExpression} where name is either declaredName if the class doesn't contain self-reference
// or decoratedClassAlias if the class contain self-reference.
const transformedClassExpression = createVariableStatement(
/*modifiers*/ undefined,
createLetDeclarationList([
createVariableDeclaration(
classAlias || declaredName,
/*type*/ undefined,
classExpression
)
]),
/*location*/ location
);
setCommentRange(transformedClassExpression, node);
statements.push(
setOriginalNode(
createVariableStatement(
/*modifiers*/ undefined,
createLetDeclarationList([
createVariableDeclaration(
classAlias || declaredName,
/*type*/ undefined,
classExpression
)
]),
/*location*/ location
),
/*node*/ transformedClassExpression,
/*original*/ node
)
);
@@ -2859,7 +2861,6 @@ namespace ts {
const moduleBlock = <ModuleBlock>getInnerMostModuleDeclarationFromDottedModule(node).body;
statementsLocation = moveRangePos(moduleBlock.statements, -1);
}
addRange(statements, endLexicalEnvironment());
currentNamespaceContainerName = savedCurrentNamespaceContainerName;
@@ -2872,6 +2873,30 @@ namespace ts {
/*location*/ blockLocation,
/*multiLine*/ true
);
// namespace hello.hi.world {
// function foo() {}
//
// // TODO, blah
// }
//
// should be emitted as
//
// var hello;
// (function (hello) {
// var hi;
// (function (hi) {
// var world;
// (function (world) {
// function foo() { }
// // TODO, blah
// })(world = hi.world || (hi.world = {}));
// })(hi = hello.hi || (hello.hi = {}));
// })(hello || (hello = {}));
// We only want to emit comment on the namespace which contains block body itself, not the containing namespaces.
if (body.kind !== SyntaxKind.ModuleBlock) {
setNodeEmitFlags(block, block.emitFlags | NodeEmitFlags.NoComments);
}
return block;
}
+11 -5
View File
@@ -487,7 +487,7 @@ namespace ts {
parent?: Node; // Parent node (initialized by binding)
/* @internal */ original?: Node; // The original node if this is an updated node.
/* @internal */ startsOnNewLine?: boolean; // Whether a synthesized node should start on a new line (used by transforms).
/* @internal */ jsDocComments?: JSDocComment[]; // JSDoc for the node, if it has any. Only for .js files.
/* @internal */ jsDocComments?: JSDoc[]; // JSDoc for the node, if it has any.
/* @internal */ symbol?: Symbol; // Symbol declared by node (initialized by binding)
/* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding)
/* @internal */ nextContainer?: Node; // Next container in declaration order (initialized by binding)
@@ -1555,7 +1555,7 @@ namespace ts {
// @kind(SyntaxKind.JSDocRecordType)
export interface JSDocRecordType extends JSDocType, TypeLiteralNode {
members: NodeArray<JSDocRecordMember>;
literal: TypeLiteralNode;
}
// @kind(SyntaxKind.JSDocTypeReference)
@@ -1603,14 +1603,16 @@ namespace ts {
}
// @kind(SyntaxKind.JSDocComment)
export interface JSDocComment extends Node {
tags: NodeArray<JSDocTag>;
export interface JSDoc extends Node {
tags: NodeArray<JSDocTag> | undefined;
comment: string | undefined;
}
// @kind(SyntaxKind.JSDocTag)
export interface JSDocTag extends Node {
atToken: Node;
tagName: Identifier;
comment: string | undefined;
}
// @kind(SyntaxKind.JSDocTemplateTag)
@@ -1649,9 +1651,13 @@ namespace ts {
// @kind(SyntaxKind.JSDocParameterTag)
export interface JSDocParameterTag extends JSDocTag {
/** the parameter name, if provided *before* the type (TypeScript-style) */
preParameterName?: Identifier;
typeExpression?: JSDocTypeExpression;
/** the parameter name, if provided *after* the type (JSDoc-standard) */
postParameterName?: Identifier;
/** the parameter name, regardless of the location it was provided */
parameterName: Identifier;
isBracketed: boolean;
}
@@ -2138,7 +2144,7 @@ namespace ts {
writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
writeTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
writeBaseConstructorTypeOfClass(node: ClassLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessibilityResult;
isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, shouldComputeAliasToMarkVisible: boolean): SymbolAccessibilityResult;
isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult;
// Returns the constant value this property access resolves to, or 'undefined' for a non-constant
getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number;
+117 -37
View File
@@ -1426,39 +1426,75 @@ namespace ts {
return undefined;
}
const jsDocComments = getJSDocComments(node, checkParentVariableStatement);
if (!jsDocComments) {
const jsDocTags = getJSDocTags(node, checkParentVariableStatement);
if (!jsDocTags) {
return undefined;
}
for (const jsDocComment of jsDocComments) {
for (const tag of jsDocComment.tags) {
if (tag.kind === kind) {
return tag;
}
for (const tag of jsDocTags) {
if (tag.kind === kind) {
return tag;
}
}
}
function getJSDocComments(node: Node, checkParentVariableStatement: boolean): JSDocComment[] {
if (node.jsDocComments) {
return node.jsDocComments;
function append<T>(previous: T[] | undefined, additional: T[] | undefined): T[] | undefined {
if (additional) {
if (!previous) {
previous = [];
}
for (const x of additional) {
previous.push(x);
}
}
// Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement.
// /**
// * @param {number} name
// * @returns {number}
// */
// var x = function(name) { return name.length; }
if (checkParentVariableStatement) {
const isInitializerOfVariableDeclarationInStatement =
node.parent.kind === SyntaxKind.VariableDeclaration &&
(<VariableDeclaration>node.parent).initializer === node &&
node.parent.parent.parent.kind === SyntaxKind.VariableStatement;
return previous;
}
const variableStatementNode = isInitializerOfVariableDeclarationInStatement ? node.parent.parent.parent : undefined;
export function getJSDocComments(node: Node, checkParentVariableStatement: boolean): string[] {
return getJSDocs(node, checkParentVariableStatement, docs => map(docs, doc => doc.comment), tags => map(tags, tag => tag.comment));
}
function getJSDocTags(node: Node, checkParentVariableStatement: boolean): JSDocTag[] {
return getJSDocs(node, checkParentVariableStatement, docs => {
const result: JSDocTag[] = [];
for (const doc of docs) {
if (doc.tags) {
result.push(...doc.tags);
}
}
return result;
}, tags => tags);
}
function getJSDocs<T>(node: Node, checkParentVariableStatement: boolean, getDocs: (docs: JSDoc[]) => T[], getTags: (tags: JSDocTag[]) => T[]): T[] {
// TODO: Get rid of getJsDocComments and friends (note the lowercase 's' in Js)
// TODO: A lot of this work should be cached, maybe. I guess it's only used in services right now...
let result: T[] = undefined;
// prepend documentation from parent sources
if (checkParentVariableStatement) {
// Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement.
// /**
// * @param {number} name
// * @returns {number}
// */
// var x = function(name) { return name.length; }
const isInitializerOfVariableDeclarationInStatement =
isVariableLike(node.parent) &&
(node.parent).initializer === node &&
node.parent.parent.parent.kind === SyntaxKind.VariableStatement;
const isVariableOfVariableDeclarationStatement = isVariableLike(node) &&
node.parent.parent.kind === SyntaxKind.VariableStatement;
const variableStatementNode =
isInitializerOfVariableDeclarationInStatement ? node.parent.parent.parent :
isVariableOfVariableDeclarationStatement ? node.parent.parent :
undefined;
if (variableStatementNode) {
return variableStatementNode.jsDocComments;
result = append(result, getJSDocs(variableStatementNode, checkParentVariableStatement, getDocs, getTags));
}
if (node.kind === SyntaxKind.ModuleDeclaration &&
node.parent && node.parent.kind === SyntaxKind.ModuleDeclaration) {
result = append(result, getJSDocs(node.parent, checkParentVariableStatement, getDocs, getTags));
}
// Also recognize when the node is the RHS of an assignment expression
@@ -1469,16 +1505,62 @@ namespace ts {
(parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken &&
parent.parent.kind === SyntaxKind.ExpressionStatement;
if (isSourceOfAssignmentExpressionStatement) {
return parent.parent.jsDocComments;
result = append(result, getJSDocs(parent.parent, checkParentVariableStatement, getDocs, getTags));
}
const isPropertyAssignmentExpression = parent && parent.kind === SyntaxKind.PropertyAssignment;
if (isPropertyAssignmentExpression) {
return parent.jsDocComments;
result = append(result, getJSDocs(parent, checkParentVariableStatement, getDocs, getTags));
}
// Pull parameter comments from declaring function as well
if (node.kind === SyntaxKind.Parameter) {
const paramTags = getJSDocParameterTag(node as ParameterDeclaration, checkParentVariableStatement);
if (paramTags) {
result = append(result, getTags(paramTags));
}
}
}
return undefined;
if (isVariableLike(node) && node.initializer) {
result = append(result, getJSDocs(node.initializer, /*checkParentVariableStatement*/ false, getDocs, getTags));
}
if (node.jsDocComments) {
if (result) {
result = append(result, getDocs(node.jsDocComments));
}
else {
return getDocs(node.jsDocComments);
}
}
return result;
}
function getJSDocParameterTag(param: ParameterDeclaration, checkParentVariableStatement: boolean): JSDocTag[] {
const func = param.parent as FunctionLikeDeclaration;
const tags = getJSDocTags(func, checkParentVariableStatement);
if (!param.name) {
// this is an anonymous jsdoc param from a `function(type1, type2): type3` specification
const i = func.parameters.indexOf(param);
const paramTags = filter(tags, tag => tag.kind === SyntaxKind.JSDocParameterTag);
if (paramTags && 0 <= i && i < paramTags.length) {
return [paramTags[i]];
}
}
else if (param.name.kind === SyntaxKind.Identifier) {
const name = (param.name as Identifier).text;
const paramTags = filter(tags, tag => tag.kind === SyntaxKind.JSDocParameterTag && (tag as JSDocParameterTag).parameterName.text === name);
if (paramTags) {
return paramTags;
}
}
else {
// TODO: it's a destructured parameter, so it should look up an "object type" series of multiple lines
// But multi-line object types aren't supported yet either
return undefined;
}
}
export function getJSDocTypeTag(node: Node): JSDocTypeTag {
@@ -1499,17 +1581,15 @@ namespace ts {
// annotation.
const parameterName = (<Identifier>parameter.name).text;
const jsDocComments = getJSDocComments(parameter.parent, /*checkParentVariableStatement*/ true);
if (jsDocComments) {
for (const jsDocComment of jsDocComments) {
for (const tag of jsDocComment.tags) {
if (tag.kind === SyntaxKind.JSDocParameterTag) {
const parameterTag = <JSDocParameterTag>tag;
const name = parameterTag.preParameterName || parameterTag.postParameterName;
if (name.text === parameterName) {
return parameterTag;
}
}
const jsDocTags = getJSDocTags(parameter.parent, /*checkParentVariableStatement*/ true);
if (!jsDocTags) {
return undefined;
}
for (const tag of jsDocTags) {
if (tag.kind === SyntaxKind.JSDocParameterTag) {
const parameterTag = <JSDocParameterTag>tag;
if (parameterTag.parameterName.text === parameterName) {
return parameterTag;
}
}
}
+103
View File
@@ -88,6 +88,10 @@ namespace FourSlash {
marker?: Marker;
}
interface ImplementationLocationInformation extends ts.ImplementationLocation {
matched?: boolean;
}
export interface TextSpan {
start: number;
end: number;
@@ -1699,6 +1703,17 @@ namespace FourSlash {
assertFn(actualCount, expectedCount, this.messageAtLastKnownMarker("Type definitions Count"));
}
public verifyImplementationListIsEmpty(negative: boolean) {
const implementations = this.languageService.getImplementationAtPosition(this.activeFile.fileName, this.currentCaretPosition);
if (negative) {
assert.isTrue(implementations && implementations.length > 0, "Expected at least one implementation but got 0");
}
else {
assert.isUndefined(implementations, "Expected implementation list to be empty but implementations returned");
}
}
public verifyGoToDefinitionName(expectedName: string, expectedContainerName: string) {
const definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
const actualDefinitionName = definitions && definitions.length ? definitions[0].name : "";
@@ -1707,6 +1722,82 @@ namespace FourSlash {
assert.equal(actualDefinitionContainerName, expectedContainerName, this.messageAtLastKnownMarker("Definition Info Container Name"));
}
public goToImplementation() {
const implementations = this.languageService.getImplementationAtPosition(this.activeFile.fileName, this.currentCaretPosition);
if (!implementations || !implementations.length) {
this.raiseError("goToImplementation failed - expected to find at least one implementation location but got 0");
}
if (implementations.length > 1) {
this.raiseError(`goToImplementation failed - more than 1 implementation returned (${implementations.length})`);
}
const implementation = implementations[0];
this.openFile(implementation.fileName);
this.currentCaretPosition = implementation.textSpan.start;
}
public verifyRangesInImplementationList(markerName: string) {
this.goToMarker(markerName);
const implementations: ImplementationLocationInformation[] = this.languageService.getImplementationAtPosition(this.activeFile.fileName, this.currentCaretPosition);
if (!implementations || !implementations.length) {
this.raiseError("verifyRangesInImplementationList failed - expected to find at least one implementation location but got 0");
}
for (let i = 0; i < implementations.length; i++) {
for (let j = 0; j < implementations.length; j++) {
if (i !== j && implementationsAreEqual(implementations[i], implementations[j])) {
const { textSpan, fileName } = implementations[i];
const end = textSpan.start + textSpan.length;
this.raiseError(`Duplicate implementations returned for range (${textSpan.start}, ${end}) in ${fileName}`);
}
}
}
const ranges = this.getRanges();
if (!ranges || !ranges.length) {
this.raiseError("verifyRangesInImplementationList failed - expected to find at least one range in test source");
}
const unsatisfiedRanges: Range[] = [];
for (const range of ranges) {
const length = range.end - range.start;
const matchingImpl = ts.find(implementations, impl =>
range.fileName === impl.fileName && range.start === impl.textSpan.start && length === impl.textSpan.length);
if (matchingImpl) {
matchingImpl.matched = true;
}
else {
unsatisfiedRanges.push(range);
}
}
const unmatchedImplementations = implementations.filter(impl => !impl.matched);
if (unmatchedImplementations.length || unsatisfiedRanges.length) {
let error = "Not all ranges or implementations are satisfied";
if (unsatisfiedRanges.length) {
error += "\nUnsatisfied ranges:";
for (const range of unsatisfiedRanges) {
error += `\n (${range.start}, ${range.end}) in ${range.fileName}: ${this.rangeText(range)}`;
}
}
if (unmatchedImplementations.length) {
error += "\nUnmatched implementations:";
for (const impl of unmatchedImplementations) {
const end = impl.textSpan.start + impl.textSpan.length;
error += `\n (${impl.textSpan.start}, ${end}) in ${impl.fileName}: ${this.getFileContent(impl.fileName).slice(impl.textSpan.start, end)}`;
}
}
this.raiseError(error);
}
function implementationsAreEqual(a: ImplementationLocationInformation, b: ImplementationLocationInformation) {
return a.fileName === b.fileName && TestState.textSpansEqual(a.textSpan, b.textSpan);
}
}
public getMarkers(): Marker[] {
// Return a copy of the list
return this.testData.markers.slice(0);
@@ -2885,6 +2976,10 @@ namespace FourSlashInterface {
this.state.goToTypeDefinition(definitionIndex);
}
public implementation() {
this.state.goToImplementation();
}
public position(position: number, fileIndex?: number): void;
public position(position: number, fileName?: string): void;
public position(position: number, fileNameOrIndex?: any): void {
@@ -2985,6 +3080,10 @@ namespace FourSlashInterface {
this.state.verifyTypeDefinitionsCount(this.negative, expectedCount);
}
public implementationListIsEmpty() {
this.state.verifyImplementationListIsEmpty(this.negative);
}
public isValidBraceCompletionAtPosition(openingBrace: string) {
this.state.verifyBraceCompletionAtPosition(this.negative, openingBrace);
}
@@ -3253,6 +3352,10 @@ namespace FourSlashInterface {
public ProjectInfo(expected: string[]) {
this.state.verifyProjectInfo(expected);
}
public allRangesAppearInImplementationList(markerName: string) {
this.state.verifyRangesInImplementationList(markerName);
}
}
export class Edit {
+6
View File
@@ -435,6 +435,9 @@ namespace Harness.LanguageService {
getTypeDefinitionAtPosition(fileName: string, position: number): ts.DefinitionInfo[] {
return unwrapJSONCallResult(this.shim.getTypeDefinitionAtPosition(fileName, position));
}
getImplementationAtPosition(fileName: string, position: number): ts.ImplementationLocation[] {
return unwrapJSONCallResult(this.shim.getImplementationAtPosition(fileName, position));
}
getReferencesAtPosition(fileName: string, position: number): ts.ReferenceEntry[] {
return unwrapJSONCallResult(this.shim.getReferencesAtPosition(fileName, position));
}
@@ -489,6 +492,9 @@ namespace Harness.LanguageService {
getNonBoundSourceFile(fileName: string): ts.SourceFile {
throw new Error("SourceFile can not be marshaled across the shim layer.");
}
getSourceFile(fileName: string): ts.SourceFile {
throw new Error("SourceFile can not be marshaled across the shim layer.");
}
dispose(): void { this.shim.dispose({}); }
}
+6 -6
View File
@@ -7,7 +7,7 @@ namespace ts {
function parsesCorrectly(name: string, content: string) {
it(name, () => {
const typeAndDiagnostics = ts.parseJSDocTypeExpressionForTests(content);
assert.isTrue(typeAndDiagnostics && typeAndDiagnostics.diagnostics.length === 0);
assert.isTrue(typeAndDiagnostics && typeAndDiagnostics.diagnostics.length === 0, "no errors issued");
Harness.Baseline.runBaseline("JSDocParsing/TypeExpressions.parsesCorrectly." + name + ".json",
() => Utils.sourceFileToJSON(typeAndDiagnostics.jsDocTypeExpression.type));
@@ -36,6 +36,9 @@ namespace ts {
parsesCorrectly("recordType6", "{{foo, bar: number}}");
parsesCorrectly("recordType7", "{{foo: number, bar: number}}");
parsesCorrectly("recordType8", "{{function}}");
parsesCorrectly("trailingCommaInRecordType", "{{a,}}");
parsesCorrectly("callSignatureInRecordType", "{{(): number}}");
parsesCorrectly("methodInRecordType", "{{foo(): number}}");
parsesCorrectly("unionType", "{(number|string)}");
parsesCorrectly("topLevelNoParenUnionType", "{number|string}");
parsesCorrectly("functionType1", "{function()}");
@@ -63,7 +66,6 @@ namespace ts {
describe("parsesIncorrectly", () => {
parsesIncorrectly("emptyType", "{}");
parsesIncorrectly("trailingCommaInRecordType", "{{a,}}");
parsesIncorrectly("unionTypeWithTrailingBar", "{(a|)}");
parsesIncorrectly("unionTypeWithoutTypes", "{()}");
parsesIncorrectly("nullableTypeWithoutType", "{!}");
@@ -80,8 +82,6 @@ namespace ts {
parsesIncorrectly("tsConstructoType", "{new () => string}");
parsesIncorrectly("typeOfType", "{typeof M}");
parsesIncorrectly("namedParameter", "{function(a: number)}");
parsesIncorrectly("callSignatureInRecordType", "{{(): number}}");
parsesIncorrectly("methodInRecordType", "{{foo(): number}}");
parsesIncorrectly("tupleTypeWithComma", "{[,]}");
parsesIncorrectly("tupleTypeWithTrailingComma", "{[number,]}");
parsesIncorrectly("tupleTypeWithLeadingComma", "{[,number]}");
@@ -100,7 +100,7 @@ namespace ts {
}
Harness.Baseline.runBaseline("JSDocParsing/DocComments.parsesCorrectly." + name + ".json",
() => JSON.stringify(comment.jsDocComment,
() => JSON.stringify(comment.jsDoc,
(k, v) => v && v.pos !== undefined ? JSON.parse(Utils.sourceFileToJSON(v)) : v, 4));
});
}
@@ -115,7 +115,6 @@ namespace ts {
describe("parsesIncorrectly", () => {
parsesIncorrectly("emptyComment", "/***/");
parsesIncorrectly("threeAsterisks", "/*** */");
parsesIncorrectly("asteriskAfterPreamble", "/** * @type {number} */");
parsesIncorrectly("multipleTypes",
`/**
* @type {number}
@@ -167,6 +166,7 @@ namespace ts {
* @type {number}
*/`);
parsesCorrectly("asteriskAfterPreamble", "/** * @type {number} */");
parsesCorrectly("typeTag",
`/**
+15 -2
View File
@@ -1,7 +1,7 @@
interface Map<K, V> {
clear(): void;
delete(key: K): boolean;
forEach(callbackfn: (value: V, index: K, map: Map<K, V>) => void, thisArg?: any): void;
forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void;
get(key: K): V | undefined;
has(key: K): boolean;
set(key: K, value?: V): this;
@@ -15,6 +15,13 @@ interface MapConstructor {
}
declare var Map: MapConstructor;
interface ReadonlyMap<K, V> {
forEach(callbackfn: (value: V, key: K, map: ReadonlyMap<K, V>) => void, thisArg?: any): void;
get(key: K): V|undefined;
has(key: K): boolean;
readonly size: number;
}
interface WeakMap<K, V> {
delete(key: K): boolean;
get(key: K): V | undefined;
@@ -33,7 +40,7 @@ interface Set<T> {
add(value: T): this;
clear(): void;
delete(value: T): boolean;
forEach(callbackfn: (value: T, index: T, set: Set<T>) => void, thisArg?: any): void;
forEach(callbackfn: (value: T, value2: T, set: Set<T>) => void, thisArg?: any): void;
has(value: T): boolean;
readonly size: number;
}
@@ -45,6 +52,12 @@ interface SetConstructor {
}
declare var Set: SetConstructor;
interface ReadonlySet<T> {
forEach(callbackfn: (value: T, value2: T, set: ReadonlySet<T>) => void, thisArg?: any): void;
has(value: T): boolean;
readonly size: number;
}
interface WeakSet<T> {
add(value: T): this;
delete(value: T): boolean;
+2 -2
View File
@@ -21,7 +21,7 @@ interface Array<T> {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: T) => boolean, thisArg?: any): number;
findIndex(predicate: (value: T, index: number, obj: Array<T>) => boolean, thisArg?: any): number;
/**
* Returns the this object after filling the section identified by start and end with value
@@ -368,7 +368,7 @@ interface ReadonlyArray<T> {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: T) => boolean, thisArg?: any): number;
findIndex(predicate: (value: T, index: number, obj: Array<T>) => boolean, thisArg?: any): number;
}
interface RegExp {
+1 -2
View File
@@ -6,8 +6,7 @@ declare namespace Reflect {
function get(target: any, propertyKey: PropertyKey, receiver?: any): any;
function getOwnPropertyDescriptor(target: any, propertyKey: PropertyKey): PropertyDescriptor;
function getPrototypeOf(target: any): any;
function has(target: any, propertyKey: string): boolean;
function has(target: any, propertyKey: symbol): boolean;
function has(target: any, propertyKey: PropertyKey): boolean;
function isExtensible(target: any): boolean;
function ownKeys(target: any): Array<PropertyKey>;
function preventExtensions(target: any): boolean;
+9 -9
View File
@@ -1576,7 +1576,7 @@ interface Int8Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
/**
* Performs the specified action for each element in an array.
@@ -1849,7 +1849,7 @@ interface Uint8Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
/**
* Performs the specified action for each element in an array.
@@ -2123,7 +2123,7 @@ interface Uint8ClampedArray {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
/**
* Performs the specified action for each element in an array.
@@ -2396,7 +2396,7 @@ interface Int16Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
/**
* Performs the specified action for each element in an array.
@@ -2670,7 +2670,7 @@ interface Uint16Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
/**
* Performs the specified action for each element in an array.
@@ -2943,7 +2943,7 @@ interface Int32Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
/**
* Performs the specified action for each element in an array.
@@ -3216,7 +3216,7 @@ interface Uint32Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
/**
* Performs the specified action for each element in an array.
@@ -3489,7 +3489,7 @@ interface Float32Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
/**
* Performs the specified action for each element in an array.
@@ -3763,7 +3763,7 @@ interface Float64Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
/**
* Performs the specified action for each element in an array.
+26
View File
@@ -368,6 +368,28 @@ namespace ts.server {
});
}
getImplementationAtPosition(fileName: string, position: number): ImplementationLocation[] {
const lineOffset = this.positionToOneBasedLineOffset(fileName, position);
const args: protocol.FileLocationRequestArgs = {
file: fileName,
line: lineOffset.line,
offset: lineOffset.offset,
};
const request = this.processRequest<protocol.ImplementationRequest>(CommandNames.Implementation, args);
const response = this.processResponse<protocol.ImplementationResponse>(request);
return response.body.map(entry => {
const fileName = entry.file;
const start = this.lineOffsetToPosition(fileName, entry.start);
const end = this.lineOffsetToPosition(fileName, entry.end);
return {
fileName,
textSpan: ts.createTextSpanFromBounds(start, end)
};
});
}
findReferences(fileName: string, position: number): ReferencedSymbol[] {
// Not yet implemented.
return [];
@@ -656,6 +678,10 @@ namespace ts.server {
throw new Error("SourceFile objects are not serializable through the server protocol.");
}
getSourceFile(fileName: string): SourceFile {
throw new Error("SourceFile objects are not serializable through the server protocol.");
}
cleanupSemanticCache(): void {
throw new Error("cleanupSemanticCache is not available through the server layer.");
}
+15
View File
@@ -193,6 +193,14 @@ declare namespace ts.server.protocol {
export interface TypeDefinitionRequest extends FileLocationRequest {
}
/**
* Go to implementation request; value of command field is
* "implementation". Return response giving the file locations that
* implement the symbol found in file at location line, col.
*/
export interface ImplementationRequest extends FileLocationRequest {
}
/**
* Location in source code expressed as (one-based) line and character offset.
*/
@@ -240,6 +248,13 @@ declare namespace ts.server.protocol {
body?: FileSpan[];
}
/**
* Implementation response message. Gives text range for implementations.
*/
export interface ImplementationResponse extends Response {
body?: FileSpan[];
}
/**
* Get occurrences request; value of command field is
* "occurrences". Return response giving spans that are relevant
+27
View File
@@ -111,6 +111,7 @@ namespace ts.server {
export const Formatonkey = "formatonkey";
export const Geterr = "geterr";
export const GeterrForProject = "geterrForProject";
export const Implementation = "implementation";
export const SemanticDiagnosticsSync = "semanticDiagnosticsSync";
export const SyntacticDiagnosticsSync = "syntacticDiagnosticsSync";
export const NavBar = "navbar";
@@ -363,6 +364,28 @@ namespace ts.server {
}));
}
private getImplementation(line: number, offset: number, fileName: string): protocol.FileSpan[] {
const file = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(file);
if (!project || project.languageServiceDiabled) {
throw Errors.NoProject;
}
const compilerService = project.compilerService;
const implementations = compilerService.languageService.getImplementationAtPosition(file,
compilerService.host.lineOffsetToPosition(file, line, offset));
if (!implementations) {
return undefined;
}
return implementations.map(impl => ({
file: impl.fileName,
start: compilerService.host.positionToLineOffset(impl.fileName, impl.textSpan.start),
end: compilerService.host.positionToLineOffset(impl.fileName, ts.textSpanEnd(impl.textSpan))
}));
}
private getOccurrences(line: number, offset: number, fileName: string): protocol.OccurrencesResponseItem[] {
fileName = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(fileName);
@@ -1090,6 +1113,10 @@ namespace ts.server {
const defArgs = <protocol.FileLocationRequestArgs>request.arguments;
return { response: this.getTypeDefinition(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true };
},
[CommandNames.Implementation]: (request: protocol.Request) => {
const implArgs = <protocol.FileLocationRequestArgs>request.arguments;
return { response: this.getImplementation(implArgs.line, implArgs.offset, implArgs.file), responseRequired: true };
},
[CommandNames.References]: (request: protocol.Request) => {
const defArgs = <protocol.FileLocationRequestArgs>request.arguments;
return { response: this.getReferences(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true };
+34 -32
View File
@@ -698,9 +698,9 @@ namespace ts {
// See if this is a doc comment. If so, we'll classify certain portions of it
// specially.
const docCommentAndDiagnostics = parseIsolatedJSDocComment(sourceFile.text, start, width);
if (docCommentAndDiagnostics && docCommentAndDiagnostics.jsDocComment) {
docCommentAndDiagnostics.jsDocComment.parent = token;
classifyJSDocComment(docCommentAndDiagnostics.jsDocComment);
if (docCommentAndDiagnostics && docCommentAndDiagnostics.jsDoc) {
docCommentAndDiagnostics.jsDoc.parent = token;
classifyJSDocComment(docCommentAndDiagnostics.jsDoc);
return;
}
}
@@ -713,37 +713,39 @@ namespace ts {
pushClassification(start, width, ClassificationType.comment);
}
function classifyJSDocComment(docComment: JSDocComment) {
function classifyJSDocComment(docComment: JSDoc) {
let pos = docComment.pos;
for (const tag of docComment.tags) {
// As we walk through each tag, classify the portion of text from the end of
// the last tag (or the start of the entire doc comment) as 'comment'.
if (tag.pos !== pos) {
pushCommentRange(pos, tag.pos - pos);
if (docComment.tags) {
for (const tag of docComment.tags) {
// As we walk through each tag, classify the portion of text from the end of
// the last tag (or the start of the entire doc comment) as 'comment'.
if (tag.pos !== pos) {
pushCommentRange(pos, tag.pos - pos);
}
pushClassification(tag.atToken.pos, tag.atToken.end - tag.atToken.pos, ClassificationType.punctuation);
pushClassification(tag.tagName.pos, tag.tagName.end - tag.tagName.pos, ClassificationType.docCommentTagName);
pos = tag.tagName.end;
switch (tag.kind) {
case SyntaxKind.JSDocParameterTag:
processJSDocParameterTag(<JSDocParameterTag>tag);
break;
case SyntaxKind.JSDocTemplateTag:
processJSDocTemplateTag(<JSDocTemplateTag>tag);
break;
case SyntaxKind.JSDocTypeTag:
processElement((<JSDocTypeTag>tag).typeExpression);
break;
case SyntaxKind.JSDocReturnTag:
processElement((<JSDocReturnTag>tag).typeExpression);
break;
}
pos = tag.end;
}
pushClassification(tag.atToken.pos, tag.atToken.end - tag.atToken.pos, ClassificationType.punctuation);
pushClassification(tag.tagName.pos, tag.tagName.end - tag.tagName.pos, ClassificationType.docCommentTagName);
pos = tag.tagName.end;
switch (tag.kind) {
case SyntaxKind.JSDocParameterTag:
processJSDocParameterTag(<JSDocParameterTag>tag);
break;
case SyntaxKind.JSDocTemplateTag:
processJSDocTemplateTag(<JSDocTemplateTag>tag);
break;
case SyntaxKind.JSDocTypeTag:
processElement((<JSDocTypeTag>tag).typeExpression);
break;
case SyntaxKind.JSDocReturnTag:
processElement((<JSDocReturnTag>tag).typeExpression);
break;
}
pos = tag.end;
}
if (pos !== docComment.end) {
@@ -982,4 +984,4 @@ namespace ts {
}
}
}
}
}
+1 -1
View File
@@ -27,7 +27,7 @@ namespace ts.DocumentHighlights {
node.kind === SyntaxKind.StringLiteral ||
isLiteralNameOfPropertyDeclarationOrIndexAccess(node)) {
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFilesToSearch, /*findInStrings*/ false, /*findInComments*/ false);
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFilesToSearch, /*findInStrings*/ false, /*findInComments*/ false, /*implementations*/false);
return convertReferencedSymbols(referencedSymbols);
}
+316 -36
View File
@@ -17,42 +17,45 @@ namespace ts.FindAllReferences {
// case SyntaxKind.SuperKeyword: TODO:GH#9268
case SyntaxKind.ConstructorKeyword:
case SyntaxKind.StringLiteral:
return getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFiles, findInStrings, findInComments);
return getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFiles, findInStrings, findInComments, /*implementations*/false);
}
return undefined;
}
export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] {
// Labels
if (isLabelName(node)) {
if (isJumpStatementTarget(node)) {
const labelDefinition = getTargetLabel((<BreakOrContinueStatement>node.parent), (<Identifier>node).text);
// if we have a label definition, look within its statement for references, if not, then
// the label is undefined and we have no results..
return labelDefinition ? getLabelReferencesInNode(labelDefinition.parent, labelDefinition) : undefined;
export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean, implementations: boolean): ReferencedSymbol[] {
if (!implementations) {
// Labels
if (isLabelName(node)) {
if (isJumpStatementTarget(node)) {
const labelDefinition = getTargetLabel((<BreakOrContinueStatement>node.parent), (<Identifier>node).text);
// if we have a label definition, look within its statement for references, if not, then
// the label is undefined and we have no results..
return labelDefinition ? getLabelReferencesInNode(labelDefinition.parent, labelDefinition) : undefined;
}
else {
// it is a label definition and not a target, search within the parent labeledStatement
return getLabelReferencesInNode(node.parent, <Identifier>node);
}
}
else {
// it is a label definition and not a target, search within the parent labeledStatement
return getLabelReferencesInNode(node.parent, <Identifier>node);
if (isThis(node)) {
return getReferencesForThisKeyword(node, sourceFiles);
}
}
if (isThis(node)) {
return getReferencesForThisKeyword(node, sourceFiles);
}
if (node.kind === SyntaxKind.SuperKeyword) {
return getReferencesForSuperKeyword(node);
if (node.kind === SyntaxKind.SuperKeyword) {
return getReferencesForSuperKeyword(node);
}
}
// `getSymbolAtLocation` normally returns the symbol of the class when given the constructor keyword,
// so we have to specify that we want the constructor symbol.
const symbol = typeChecker.getSymbolAtLocation(node);
if (!symbol && node.kind === SyntaxKind.StringLiteral) {
if (!implementations && !symbol && node.kind === SyntaxKind.StringLiteral) {
return getReferencesForStringLiteral(<StringLiteral>node, sourceFiles);
}
// Could not find a symbol e.g. unknown identifier
if (!symbol) {
// Can't have references to something that we have no symbol for.
@@ -356,9 +359,9 @@ namespace ts.FindAllReferences {
}
/** 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
*/
* tuple of(searchSymbol, searchText, searchLocation, and searchMeaning).
* searchLocation: a node where the search value
*/
function getReferencesInNode(container: Node,
searchSymbol: Symbol,
searchText: string,
@@ -374,6 +377,9 @@ namespace ts.FindAllReferences {
const start = findInComments ? container.getFullStart() : container.getStart();
const possiblePositions = getPossibleSymbolReferencePositions(sourceFile, searchText, start, container.getEnd());
const parents = getParentSymbolsOfPropertyAccess();
const inheritsFromCache: Map<boolean> = createMap<boolean>();
if (possiblePositions.length) {
// Build the set of symbols to search for, initially it has only the current symbol
const searchSymbols = populateSearchSymbolSet(searchSymbol, searchLocation);
@@ -386,8 +392,8 @@ namespace ts.FindAllReferences {
// This wasn't the start of a token. Check to see if it might be a
// match in a comment or string if that's what the caller is asking
// for.
if ((findInStrings && isInString(sourceFile, position)) ||
(findInComments && isInNonReferenceComment(sourceFile, position))) {
if (!implementations && ((findInStrings && isInString(sourceFile, position)) ||
(findInComments && isInNonReferenceComment(sourceFile, position)))) {
// In the case where we're looking inside comments/strings, we don't have
// an actual definition. So just use 'undefined' here. Features like
@@ -415,11 +421,10 @@ namespace ts.FindAllReferences {
const referenceSymbolDeclaration = referenceSymbol.valueDeclaration;
const shorthandValueSymbol = typeChecker.getShorthandAssignmentValueSymbol(referenceSymbolDeclaration);
const relatedSymbol = getRelatedSymbol(searchSymbols, referenceSymbol, referenceLocation,
/*searchLocationIsConstructor*/ searchLocation.kind === SyntaxKind.ConstructorKeyword);
/*searchLocationIsConstructor*/ searchLocation.kind === SyntaxKind.ConstructorKeyword, parents, inheritsFromCache);
if (relatedSymbol) {
const referencedSymbol = getReferencedSymbol(relatedSymbol);
referencedSymbol.references.push(getReferenceEntryFromNode(referenceLocation));
addReferenceToRelatedSymbol(referenceLocation, relatedSymbol);
}
/* Because in short-hand property assignment, an identifier which stored as name of the short-hand property assignment
* has two meaning : property name and property value. Therefore when we do findAllReference at the position where
@@ -428,8 +433,7 @@ namespace ts.FindAllReferences {
* position of property accessing, the referenceEntry of such position will be handled in the first case.
*/
else if (!(referenceSymbol.flags & SymbolFlags.Transient) && searchSymbols.indexOf(shorthandValueSymbol) >= 0) {
const referencedSymbol = getReferencedSymbol(shorthandValueSymbol);
referencedSymbol.references.push(getReferenceEntryFromNode(referenceSymbolDeclaration.name));
addReferenceToRelatedSymbol(referenceSymbolDeclaration.name, shorthandValueSymbol);
}
else if (searchLocation.kind === SyntaxKind.ConstructorKeyword) {
findAdditionalConstructorReferences(referenceSymbol, referenceLocation);
@@ -437,9 +441,34 @@ namespace ts.FindAllReferences {
}
});
}
return;
/* If we are just looking for implementations and this is a property access expression, we need to get the
* symbol of the local type of the symbol the property is being accessed on. This is because our search
* symbol may have a different parent symbol if the local type's symbol does not declare the property
* being accessed (i.e. it is declared in some parent class or interface)
*/
function getParentSymbolsOfPropertyAccess(): Symbol[] | undefined {
if (implementations) {
const propertyAccessExpression = getPropertyAccessExpressionFromRightHandSide(searchLocation);
if (propertyAccessExpression) {
const localParentType = typeChecker.getTypeAtLocation(propertyAccessExpression.expression);
if (localParentType) {
if (localParentType.symbol && localParentType.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) && localParentType.symbol !== searchSymbol.parent) {
return [localParentType.symbol];
}
else if (localParentType.flags & TypeFlags.UnionOrIntersection) {
return getSymbolsForClassAndInterfaceComponents(<UnionOrIntersectionType>localParentType);
}
}
}
}
}
function getPropertyAccessExpressionFromRightHandSide(node: Node): PropertyAccessExpression {
return isRightSideOfPropertyAccess(node) && <PropertyAccessExpression>node.parent;
}
/** Adds references when a constructor is used with `new this()` in its own class and `super()` calls in subclasses. */
function findAdditionalConstructorReferences(referenceSymbol: Symbol, referenceLocation: Node): void {
Debug.assert(isClassLike(searchSymbol.valueDeclaration));
@@ -534,6 +563,200 @@ namespace ts.FindAllReferences {
return result[index];
}
function addReferenceToRelatedSymbol(node: Node, relatedSymbol: Symbol) {
const references = getReferencedSymbol(relatedSymbol).references;
if (implementations) {
getImplementationReferenceEntryForNode(node, references);
}
else {
references.push(getReferenceEntryFromNode(node));
}
}
}
function getImplementationReferenceEntryForNode(refNode: Node, result: ReferenceEntry[]): void {
// Check if we found a function/propertyAssignment/method with an implementation or initializer
if (isDeclarationName(refNode) && isImplementation(refNode.parent)) {
result.push(getReferenceEntryFromNode(refNode.parent));
}
else if (refNode.kind === SyntaxKind.Identifier) {
if (refNode.parent.kind === SyntaxKind.ShorthandPropertyAssignment) {
// Go ahead and dereference the shorthand assignment by going to its definition
getReferenceEntriesForShorthandPropertyAssignment(refNode, typeChecker, result);
}
// Check if the node is within an extends or implements clause
const containingClass = getContainingClassIfInHeritageClause(refNode);
if (containingClass) {
result.push(getReferenceEntryFromNode(containingClass));
return;
}
// If we got a type reference, try and see if the reference applies to any expressions that can implement an interface
const containingTypeReference = getContainingTypeReference(refNode);
if (containingTypeReference) {
const parent = containingTypeReference.parent;
if (isVariableLike(parent) && parent.type === containingTypeReference && parent.initializer && isImplementationExpression(parent.initializer)) {
maybeAdd(getReferenceEntryFromNode(parent.initializer));
}
else if (isFunctionLike(parent) && parent.type === containingTypeReference && parent.body) {
if (parent.body.kind === SyntaxKind.Block) {
forEachReturnStatement(<Block>parent.body, returnStatement => {
if (returnStatement.expression && isImplementationExpression(returnStatement.expression)) {
maybeAdd(getReferenceEntryFromNode(returnStatement.expression));
}
});
}
else if (isImplementationExpression(<Expression>parent.body)) {
maybeAdd(getReferenceEntryFromNode(parent.body));
}
}
else if (isAssertionExpression(parent) && isImplementationExpression(parent.expression)) {
maybeAdd(getReferenceEntryFromNode(parent.expression));
}
}
}
// Type nodes can contain multiple references to the same type. For example:
// let x: Foo & (Foo & Bar) = ...
// Because we are returning the implementation locations and not the identifier locations,
// duplicate entries would be returned here as each of the type references is part of
// the same implementation. For that reason, check before we add a new entry
function maybeAdd(a: ReferenceEntry) {
if (!forEach(result, b => a.fileName === b.fileName && a.textSpan.start === b.textSpan.start && a.textSpan.length === b.textSpan.length)) {
result.push(a);
}
}
}
function getSymbolsForClassAndInterfaceComponents(type: UnionOrIntersectionType, result: Symbol[] = []): Symbol[] {
for (const componentType of type.types) {
if (componentType.symbol && componentType.symbol.getFlags() & (SymbolFlags.Class | SymbolFlags.Interface)) {
result.push(componentType.symbol);
}
if (componentType.getFlags() & TypeFlags.UnionOrIntersection) {
getSymbolsForClassAndInterfaceComponents(<UnionOrIntersectionType>componentType, result);
}
}
return result;
}
function getContainingTypeReference(node: Node): Node {
let topLevelTypeReference: Node = undefined;
while (node) {
if (isTypeNode(node)) {
topLevelTypeReference = node;
}
node = node.parent;
}
return topLevelTypeReference;
}
function getContainingClassIfInHeritageClause(node: Node): ClassLikeDeclaration {
if (node && node.parent) {
if (node.kind === SyntaxKind.ExpressionWithTypeArguments
&& node.parent.kind === SyntaxKind.HeritageClause
&& isClassLike(node.parent.parent)) {
return node.parent.parent;
}
else if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PropertyAccessExpression) {
return getContainingClassIfInHeritageClause(node.parent);
}
}
return undefined;
}
/**
* Returns true if this is an expression that can be considered an implementation
*/
function isImplementationExpression(node: Expression): boolean {
// Unwrap parentheses
if (node.kind === SyntaxKind.ParenthesizedExpression) {
return isImplementationExpression((<ParenthesizedExpression>node).expression);
}
return node.kind === SyntaxKind.ArrowFunction ||
node.kind === SyntaxKind.FunctionExpression ||
node.kind === SyntaxKind.ObjectLiteralExpression ||
node.kind === SyntaxKind.ClassExpression ||
node.kind === SyntaxKind.ArrayLiteralExpression;
}
/**
* Determines if the parent symbol occurs somewhere in the child's ancestry. If the parent symbol
* is an interface, determines if some ancestor of the child symbol extends or inherits from it.
* Also takes in a cache of previous results which makes this slightly more efficient and is
* necessary to avoid potential loops like so:
* class A extends B { }
* class B extends A { }
*
* We traverse the AST rather than using the type checker because users are typically only interested
* in explicit implementations of an interface/class when calling "Go to Implementation". Sibling
* implementations of types that share a common ancestor with the type whose implementation we are
* searching for need to be filtered out of the results. The type checker doesn't let us make the
* distinction between structurally compatible implementations and explicit implementations, so we
* must use the AST.
*
* @param child A class or interface Symbol
* @param parent Another class or interface Symbol
* @param cachedResults A map of symbol id pairs (i.e. "child,parent") to booleans indicating previous results
*/
function explicitlyInheritsFrom(child: Symbol, parent: Symbol, cachedResults: Map<boolean>): boolean {
const parentIsInterface = parent.getFlags() & SymbolFlags.Interface;
return searchHierarchy(child);
function searchHierarchy(symbol: Symbol): boolean {
if (symbol === parent) {
return true;
}
const key = getSymbolId(symbol) + "," + getSymbolId(parent);
if (key in cachedResults) {
return cachedResults[key];
}
// Set the key so that we don't infinitely recurse
cachedResults[key] = false;
const inherits = forEach(symbol.getDeclarations(), declaration => {
if (isClassLike(declaration)) {
if (parentIsInterface) {
const interfaceReferences = getClassImplementsHeritageClauseElements(declaration);
if (interfaceReferences) {
for (const typeReference of interfaceReferences) {
if (searchTypeReference(typeReference)) {
return true;
}
}
}
}
return searchTypeReference(getClassExtendsHeritageClauseElement(declaration));
}
else if (declaration.kind === SyntaxKind.InterfaceDeclaration) {
if (parentIsInterface) {
return forEach(getInterfaceBaseTypeNodes(<InterfaceDeclaration>declaration), searchTypeReference);
}
}
return false;
});
cachedResults[key] = inherits;
return inherits;
}
function searchTypeReference(typeReference: ExpressionWithTypeArguments): boolean {
if (typeReference) {
const type = typeChecker.getTypeAtLocation(typeReference);
if (type && type.symbol) {
return searchHierarchy(type.symbol);
}
}
return false;
}
}
function getReferencesForSuperKeyword(superKeyword: Node): ReferencedSymbol[] {
@@ -696,6 +919,7 @@ namespace ts.FindAllReferences {
}
}
function getReferencesForStringLiteral(node: StringLiteral, sourceFiles: SourceFile[]): ReferencedSymbol[] {
const type = getStringLiteralTypeForNode(node, typeChecker);
@@ -821,7 +1045,7 @@ namespace ts.FindAllReferences {
}
// Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions
if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
if (!implementations && rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ createMap<Symbol>());
}
});
@@ -888,7 +1112,7 @@ namespace ts.FindAllReferences {
}
}
function getRelatedSymbol(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node, searchLocationIsConstructor: boolean): Symbol | undefined {
function getRelatedSymbol(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node, searchLocationIsConstructor: boolean, parents: Symbol[] | undefined, cache: Map<boolean>): Symbol {
if (contains(searchSymbols, referenceSymbol)) {
// If we are searching for constructor uses, they must be 'new' expressions.
return (!searchLocationIsConstructor || isNewExpressionTarget(referenceLocation)) && referenceSymbol;
@@ -898,7 +1122,7 @@ namespace ts.FindAllReferences {
// symbols but by looking up for related symbol of this alias so it can handle multiple level of indirectness.
const aliasSymbol = getAliasSymbolForPropertyNameSymbol(referenceSymbol, referenceLocation);
if (aliasSymbol) {
return getRelatedSymbol(searchSymbols, aliasSymbol, referenceLocation, searchLocationIsConstructor);
return getRelatedSymbol(searchSymbols, aliasSymbol, referenceLocation, searchLocationIsConstructor, parents, cache);
}
// If the reference location is in an object literal, try to get the contextual type for the
@@ -941,8 +1165,16 @@ namespace ts.FindAllReferences {
}
// 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
// see if any is in the list. If we were passed a parent symbol, only include types that are subtypes of the
// parent symbol
if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
// Parents will only be defined if implementations is true
if (parents) {
if (!forEach(parents, parent => explicitlyInheritsFrom(rootSymbol.parent, parent, cache))) {
return undefined;
}
}
const result: Symbol[] = [];
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ createMap<Symbol>());
return forEach(result, s => searchSymbols.indexOf(s) >= 0 ? s : undefined);
@@ -1035,7 +1267,55 @@ namespace ts.FindAllReferences {
return referenceEntries;
}
function getReferenceEntryFromNode(node: Node): ReferenceEntry {
function isImplementation(node: Node): boolean {
if (!node) {
return false;
}
else if (isVariableLike(node)) {
if (node.initializer) {
return true;
}
else if (node.kind === SyntaxKind.VariableDeclaration) {
const parentStatement = getParentStatementOfVariableDeclaration(<VariableDeclaration>node);
return parentStatement && hasModifier(parentStatement, ModifierFlags.Ambient);
}
}
else if (isFunctionLike(node)) {
return !!node.body || hasModifier(node, ModifierFlags.Ambient);
}
else {
switch (node.kind) {
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.ModuleDeclaration:
return true;
}
}
return false;
}
function getParentStatementOfVariableDeclaration(node: VariableDeclaration): VariableStatement {
if (node.parent && node.parent.parent && node.parent.parent.kind === SyntaxKind.VariableStatement) {
Debug.assert(node.parent.kind === SyntaxKind.VariableDeclarationList);
return <VariableStatement>node.parent.parent;
}
}
export function getReferenceEntriesForShorthandPropertyAssignment(node: Node, typeChecker: TypeChecker, result: ReferenceEntry[]): void {
const refSymbol = typeChecker.getSymbolAtLocation(node);
const shorthandSymbol = typeChecker.getShorthandAssignmentValueSymbol(refSymbol.valueDeclaration);
if (shorthandSymbol) {
for (const declaration of shorthandSymbol.getDeclarations()) {
if (getMeaningFromDeclaration(declaration) & SemanticMeaning.Value) {
result.push(getReferenceEntryFromNode(declaration));
}
}
}
}
export function getReferenceEntryFromNode(node: Node): ReferenceEntry {
let start = node.getStart();
let end = node.getEnd();
+27
View File
@@ -0,0 +1,27 @@
/* @internal */
namespace ts.GoToImplementation {
export function getImplementationAtPosition(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFiles: SourceFile[], node: Node): ImplementationLocation[] {
// If invoked directly on a shorthand property assignment, then return
// the declaration of the symbol being assigned (not the symbol being assigned to).
if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) {
const result: ReferenceEntry[] = [];
FindAllReferences.getReferenceEntriesForShorthandPropertyAssignment(node, typeChecker, result);
return result.length > 0 ? result : undefined;
}
else if (node.kind === SyntaxKind.SuperKeyword || isSuperProperty(node.parent)) {
// References to and accesses on the super keyword only have one possible implementation, so no
// need to "Find all References"
const symbol = typeChecker.getSymbolAtLocation(node);
return symbol.valueDeclaration && [FindAllReferences.getReferenceEntryFromNode(symbol.valueDeclaration)];
}
else {
// Perform "Find all References" and retrieve only those that are implementations
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken,
node, sourceFiles, /*findInStrings*/false, /*findInComments*/false, /*implementations*/true);
const result = flatMap(referencedSymbols, symbol =>
map(symbol.references, ({ textSpan, fileName }) => ({ textSpan, fileName })));
return result && result.length > 0 ? result : undefined;
}
}
}
+32 -334
View File
@@ -44,349 +44,47 @@ namespace ts.JsDoc {
let jsDocCompletionEntries: CompletionEntry[];
export function getJsDocCommentsFromDeclarations(declarations: Declaration[], name: string, canUseParsedParamTagComments: boolean) {
// Only collect doc comments from duplicate declarations once:
// In case of a union property there might be same declaration multiple times
// which only varies in type parameter
// Eg. const a: Array<string> | Array<number>; a.length
// The property length will have two declarations of property length coming
// from Array<T> - Array<string> and Array<number>
const documentationComment = <SymbolDisplayPart[]>[];
const docComments = getJsDocCommentsSeparatedByNewLines();
ts.forEach(docComments, docComment => {
if (documentationComment.length) {
documentationComment.push(lineBreakPart());
forEachUnique(declarations, declaration => {
const comments = getJSDocComments(declaration, /*checkParentVariableStatement*/ true);
if (!comments) {
return;
}
for (const comment of comments) {
if (comment) {
if (documentationComment.length) {
documentationComment.push(lineBreakPart());
}
documentationComment.push(textPart(comment));
}
}
documentationComment.push(docComment);
});
return documentationComment;
}
function getJsDocCommentsSeparatedByNewLines() {
const paramTag = "@param";
const jsDocCommentParts: SymbolDisplayPart[] = [];
ts.forEach(declarations, (declaration, indexOfDeclaration) => {
// Make sure we are collecting doc comment from declaration once,
// In case of union property there might be same declaration multiple times
// which only varies in type parameter
// Eg. const a: Array<string> | Array<number>; a.length
// The property length will have two declarations of property length coming
// from Array<T> - Array<string> and Array<number>
if (indexOf(declarations, declaration) === indexOfDeclaration) {
const sourceFileOfDeclaration = 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 === SyntaxKind.Parameter) {
if ((declaration.parent.kind === SyntaxKind.FunctionExpression || declaration.parent.kind === SyntaxKind.ArrowFunction) &&
declaration.parent.parent.kind === SyntaxKind.VariableDeclaration) {
addCommentParts(declaration.parent.parent.parent, sourceFileOfDeclaration, getCleanedParamJsDocComment);
}
addCommentParts(declaration.parent, sourceFileOfDeclaration, getCleanedParamJsDocComment);
}
// If this is left side of dotted module declaration, there is no doc comments associated with this node
if (declaration.kind === SyntaxKind.ModuleDeclaration && (<ModuleDeclaration>declaration).body && (<ModuleDeclaration>declaration).body.kind === SyntaxKind.ModuleDeclaration) {
return;
}
if ((declaration.kind === SyntaxKind.FunctionExpression || declaration.kind === SyntaxKind.ArrowFunction) &&
declaration.parent.kind === SyntaxKind.VariableDeclaration) {
addCommentParts(declaration.parent.parent, sourceFileOfDeclaration, getCleanedJsDocComment);
}
// If this is dotted module name, get the doc comments from the parent
while (declaration.kind === SyntaxKind.ModuleDeclaration && declaration.parent.kind === SyntaxKind.ModuleDeclaration) {
declaration = <ModuleDeclaration>declaration.parent;
}
addCommentParts(declaration.kind === SyntaxKind.VariableDeclaration ? declaration.parent.parent : declaration,
sourceFileOfDeclaration,
getCleanedJsDocComment);
if (declaration.kind === SyntaxKind.VariableDeclaration) {
const init = (declaration as VariableDeclaration).initializer;
if (init && (init.kind === SyntaxKind.FunctionExpression || init.kind === SyntaxKind.ArrowFunction)) {
// Get the cleaned js doc comment text from the initializer
addCommentParts(init, sourceFileOfDeclaration, getCleanedJsDocComment);
}
}
}
});
return jsDocCommentParts;
function addCommentParts(commented: Node,
sourceFileOfDeclaration: SourceFile,
getCommentPart: (pos: number, end: number, file: SourceFile) => SymbolDisplayPart[]): void {
const ranges = getJsDocCommentTextRange(commented, sourceFileOfDeclaration);
// Get the cleaned js doc comment text from the declaration
ts.forEach(ranges, jsDocCommentTextRange => {
const cleanedComment = getCommentPart(jsDocCommentTextRange.pos, jsDocCommentTextRange.end, sourceFileOfDeclaration);
if (cleanedComment) {
addRange(jsDocCommentParts, cleanedComment);
}
});
}
function getJsDocCommentTextRange(node: Node, sourceFile: SourceFile): TextRange[] {
return ts.map(getJsDocComments(node, sourceFile),
jsDocComment => {
return {
pos: jsDocComment.pos + "/*".length, // Consume /* from the comment
end: jsDocComment.end - "*/".length // Trim off comment end indicator
};
});
}
function consumeWhiteSpacesOnTheLine(pos: number, end: number, sourceFile: SourceFile, maxSpacesToRemove?: number) {
if (maxSpacesToRemove !== undefined) {
end = Math.min(end, pos + maxSpacesToRemove);
}
for (; pos < end; pos++) {
const ch = sourceFile.text.charCodeAt(pos);
if (!isWhiteSpaceSingleLine(ch)) {
return pos;
}
}
return end;
}
function consumeLineBreaks(pos: number, end: number, sourceFile: SourceFile) {
while (pos < end && isLineBreak(sourceFile.text.charCodeAt(pos))) {
pos++;
}
return pos;
}
function isName(pos: number, end: number, sourceFile: SourceFile, name: string) {
return pos + name.length < end &&
sourceFile.text.substr(pos, name.length) === name &&
isWhiteSpace(sourceFile.text.charCodeAt(pos + name.length));
}
function isParamTag(pos: number, end: number, sourceFile: SourceFile) {
// If it is @param tag
return isName(pos, end, sourceFile, paramTag);
}
function pushDocCommentLineText(docComments: SymbolDisplayPart[], text: string, blankLineCount: number) {
// Add the empty lines in between texts
while (blankLineCount) {
blankLineCount--;
docComments.push(textPart(""));
}
docComments.push(textPart(text));
}
function getCleanedJsDocComment(pos: number, end: number, sourceFile: SourceFile) {
let spacesToRemoveAfterAsterisk: number;
const docComments: SymbolDisplayPart[] = [];
let blankLineCount = 0;
let isInParamTag = false;
while (pos < end) {
let 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) === CharacterCodes.asterisk) {
const 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 && !isLineBreak(sourceFile.text.charCodeAt(pos))) {
spacesToRemoveAfterAsterisk = pos - lineStartPos;
}
}
else if (spacesToRemoveAfterAsterisk === undefined) {
spacesToRemoveAfterAsterisk = 0;
}
// Analyze text on this line
while (pos < end && !isLineBreak(sourceFile.text.charCodeAt(pos))) {
const 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: number, end: number, sourceFile: SourceFile) {
let paramHelpStringMargin: number;
const paramDocComments: SymbolDisplayPart[] = [];
while (pos < end) {
if (isParamTag(pos, end, sourceFile)) {
let blankLineCount = 0;
let recordedParamTag = false;
// Consume leading spaces
pos = consumeWhiteSpaces(pos + paramTag.length);
if (pos >= end) {
break;
}
// Ignore type expression
if (sourceFile.text.charCodeAt(pos) === CharacterCodes.openBrace) {
pos++;
for (let curlies = 1; pos < end; pos++) {
const charCode = sourceFile.text.charCodeAt(pos);
// { character means we need to find another } to match the found one
if (charCode === CharacterCodes.openBrace) {
curlies++;
continue;
}
// } char
if (charCode === CharacterCodes.closeBrace) {
curlies--;
if (curlies === 0) {
// We do not have any more } to match the type expression is ignored completely
pos++;
break;
}
else {
// there are more { to be matched with }
continue;
}
}
// Found start of another tag
if (charCode === 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;
}
let paramHelpString = "";
const firstLineParamHelpStringPos = pos;
while (pos < end) {
const ch = sourceFile.text.charCodeAt(pos);
// at line break, set this comment line text and go to next line
if (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 === 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 search of param tag with symbol name
if (sourceFile.text.charCodeAt(pos) === CharacterCodes.at) {
continue;
}
}
// Next character
pos++;
}
return paramDocComments;
function consumeWhiteSpaces(pos: number) {
while (pos < end && isWhiteSpaceSingleLine(sourceFile.text.charCodeAt(pos))) {
pos++;
}
return pos;
}
function setPosForParamHelpStringOnNextLine(firstLineParamHelpStringPos: number) {
// Get the pos after consuming line breaks
pos = consumeLineBreaks(pos, end, sourceFile);
if (pos >= end) {
return;
}
if (paramHelpStringMargin === undefined) {
paramHelpStringMargin = sourceFile.getLineAndCharacterOfPosition(firstLineParamHelpStringPos).character;
}
// Now consume white spaces max
const startOfLinePos = pos;
pos = consumeWhiteSpacesOnTheLine(pos, end, sourceFile, paramHelpStringMargin);
if (pos >= end) {
return;
}
const consumedSpaces = pos - startOfLinePos;
if (consumedSpaces < paramHelpStringMargin) {
const ch = sourceFile.text.charCodeAt(pos);
if (ch === CharacterCodes.asterisk) {
// Consume more spaces after asterisk
pos = consumeWhiteSpacesOnTheLine(pos + 1, end, sourceFile, paramHelpStringMargin - consumedSpaces - 1);
}
/**
* Iterates through 'array' by index and performs the callback on each element of array until the callback
* returns a truthy value, then returns that value.
* If no such value is found, the callback is applied to each element of array and undefined is returned.
*/
function forEachUnique<T, U>(array: T[], callback: (element: T, index: number) => U): U {
if (array) {
for (let i = 0, len = array.length; i < len; i++) {
if (indexOf(array, array[i]) === i) {
const result = callback(array[i], i);
if (result) {
return result;
}
}
}
}
return undefined;
}
export function getAllJsDocCompletionEntries(): CompletionEntry[] {
+6 -8
View File
@@ -218,15 +218,13 @@ namespace ts.NavigationBar {
break;
default:
if (node.jsDocComments) {
for (const jsDocComment of node.jsDocComments) {
for (const tag of jsDocComment.tags) {
if (tag.kind === SyntaxKind.JSDocTypedefTag) {
addLeafNode(tag);
}
forEach(node.jsDocComments, jsDocComment => {
forEach(jsDocComment.tags, tag => {
if (tag.kind === SyntaxKind.JSDocTypedefTag) {
addLeafNode(tag);
}
}
}
});
});
forEachChild(node, addChildrenRecursively);
}
+16 -2
View File
@@ -10,6 +10,7 @@
/// <reference path='documentRegistry.ts' />
/// <reference path='findAllReferences.ts' />
/// <reference path='goToDefinition.ts' />
/// <reference path='goToImplementation.ts' />
/// <reference path='jsDoc.ts' />
/// <reference path='jsTyping.ts' />
/// <reference path='navigateTo.ts' />
@@ -42,7 +43,7 @@ namespace ts {
public end: number;
public flags: NodeFlags;
public parent: Node;
public jsDocComments: JSDocComment[];
public jsDocComments: JSDoc[];
public original: Node;
public transformFlags: TransformFlags;
public excludeTransformFlags: TransformFlags;
@@ -215,7 +216,7 @@ namespace ts {
public end: number;
public flags: NodeFlags;
public parent: Node;
public jsDocComments: JSDocComment[];
public jsDocComments: JSDoc[];
public __tokenTag: any;
constructor(pos: number, end: number) {
@@ -1271,6 +1272,13 @@ namespace ts {
return GoToDefinition.getDefinitionAtPosition(program, getValidSourceFile(fileName), position);
}
/// Goto implementation
function getImplementationAtPosition(fileName: string, position: number): ImplementationLocation[] {
synchronizeHostData();
return GoToImplementation.getImplementationAtPosition(program.getTypeChecker(), cancellationToken,
program.getSourceFiles(), getTouchingPropertyName(getValidSourceFile(fileName), position));
}
function getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] {
synchronizeHostData();
return GoToDefinition.getTypeDefinitionAtPosition(program.getTypeChecker(), getValidSourceFile(fileName), position);
@@ -1393,6 +1401,10 @@ namespace ts {
return syntaxTreeCache.getCurrentSourceFile(fileName);
}
function getSourceFile(fileName: string): SourceFile {
return getNonBoundSourceFile(fileName);
}
function getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TextSpan {
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
@@ -1781,6 +1793,7 @@ namespace ts {
getSignatureHelpItems,
getQuickInfoAtPosition,
getDefinitionAtPosition,
getImplementationAtPosition,
getTypeDefinitionAtPosition,
getReferencesAtPosition,
findReferences,
@@ -1803,6 +1816,7 @@ namespace ts {
isValidBraceCompletionAtPosition,
getEmitOutput,
getNonBoundSourceFile,
getSourceFile,
getProgram
};
}
+19
View File
@@ -177,6 +177,12 @@ namespace ts {
*/
getTypeDefinitionAtPosition(fileName: string, position: number): string;
/**
* Returns a JSON-encoded value of the type:
* { fileName: string; textSpan: { start: number; length: number}; }[]
*/
getImplementationAtPosition(fileName: string, position: number): string;
/**
* Returns a JSON-encoded value of the type:
* { fileName: string; textSpan: { start: number; length: number}; isWriteAccess: boolean, isDefinition?: boolean }[]
@@ -798,6 +804,19 @@ namespace ts {
);
}
/// GOTO Implementation
/**
* Computes the implementation location of the symbol
* at the requested position.
*/
public getImplementationAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
`getImplementationAtPosition('${fileName}', ${position})`,
() => this.languageService.getImplementationAtPosition(fileName, position)
);
}
public getRenameInfo(fileName: string, position: number): string {
return this.forwardJSONCall(
`getRenameInfo('${fileName}', ${position})`,
+1
View File
@@ -49,6 +49,7 @@
"documentRegistry.ts",
"findAllReferences.ts",
"goToDefinition.ts",
"goToImplementation.ts",
"jsDoc.ts",
"jsTyping.ts",
"navigateTo.ts",
+12
View File
@@ -209,6 +209,7 @@ namespace ts {
getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[];
getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[];
getImplementationAtPosition(fileName: string, position: number): ImplementationLocation[];
getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[];
findReferences(fileName: string, position: number): ReferencedSymbol[];
@@ -239,6 +240,12 @@ namespace ts {
/* @internal */ getNonBoundSourceFile(fileName: string): SourceFile;
/**
* @internal
* @deprecated Use ts.createSourceFile instead.
*/
getSourceFile(fileName: string): SourceFile;
dispose(): void;
}
@@ -297,6 +304,11 @@ namespace ts {
isDefinition: boolean;
}
export interface ImplementationLocation {
textSpan: TextSpan;
fileName: string;
}
export interface DocumentHighlights {
fileName: string;
highlightSpans: HighlightSpan[];
+6 -4
View File
@@ -953,9 +953,11 @@ namespace ts {
if (node) {
if (node.jsDocComments) {
for (const jsDocComment of node.jsDocComments) {
for (const tag of jsDocComment.tags) {
if (tag.pos <= position && position <= tag.end) {
return tag;
if (jsDocComment.tags) {
for (const tag of jsDocComment.tags) {
if (tag.pos <= position && position <= tag.end) {
return tag;
}
}
}
}
@@ -1353,4 +1355,4 @@ namespace ts {
}
return { configJsonObject, diagnostics };
}
}
}
@@ -0,0 +1,6 @@
{
"kind": "JSDocComment",
"pos": 0,
"end": 23,
"comment": "* @type {number} "
}
@@ -27,7 +27,8 @@
"pos": 15,
"end": 21
}
}
},
"comment": ""
},
"length": 1,
"pos": 8,
@@ -27,7 +27,8 @@
"pos": 15,
"end": 21
}
}
},
"comment": ""
},
"length": 1,
"pos": 8,
@@ -6,7 +6,7 @@
"0": {
"kind": "JSDocReturnTag",
"pos": 8,
"end": 15,
"end": 16,
"atToken": {
"kind": "AtToken",
"pos": 8,
@@ -17,10 +17,11 @@
"pos": 9,
"end": 15,
"text": "return"
}
},
"comment": ""
},
"length": 1,
"pos": 8,
"end": 15
"end": 16
}
}
@@ -6,7 +6,7 @@
"0": {
"kind": "JSDocTypeTag",
"pos": 8,
"end": 13,
"end": 14,
"atToken": {
"kind": "AtToken",
"pos": 8,
@@ -17,10 +17,11 @@
"pos": 9,
"end": 13,
"text": "type"
}
},
"comment": ""
},
"length": 1,
"pos": 8,
"end": 13
"end": 14
}
}
@@ -33,7 +33,14 @@
"pos": 24,
"end": 29,
"text": "name1"
}
},
"parameterName": {
"kind": "Identifier",
"pos": 24,
"end": 29,
"text": "name1"
},
"comment": ""
},
"length": 1,
"pos": 8,
@@ -33,7 +33,14 @@
"pos": 24,
"end": 29,
"text": "name1"
}
},
"parameterName": {
"kind": "Identifier",
"pos": 24,
"end": 29,
"text": "name1"
},
"comment": "Description text follows"
},
"length": 1,
"pos": 8,
@@ -34,7 +34,14 @@
"end": 30,
"text": "name1"
},
"isBracketed": true
"parameterName": {
"kind": "Identifier",
"pos": 25,
"end": 30,
"text": "name1"
},
"isBracketed": true,
"comment": "Description text follows"
},
"length": 1,
"pos": 8,
@@ -34,7 +34,14 @@
"end": 31,
"text": "name1"
},
"isBracketed": true
"parameterName": {
"kind": "Identifier",
"pos": 26,
"end": 31,
"text": "name1"
},
"isBracketed": true,
"comment": "Description text follows"
},
"length": 1,
"pos": 8,
@@ -33,7 +33,14 @@
"pos": 22,
"end": 28
}
}
},
"parameterName": {
"kind": "Identifier",
"pos": 15,
"end": 20,
"text": "name1"
},
"comment": ""
},
"length": 1,
"pos": 8,
@@ -33,7 +33,14 @@
"pos": 22,
"end": 28
}
}
},
"parameterName": {
"kind": "Identifier",
"pos": 15,
"end": 20,
"text": "name1"
},
"comment": "Description"
},
"length": 1,
"pos": 8,
@@ -23,7 +23,14 @@
"pos": 15,
"end": 18,
"text": "foo"
}
},
"parameterName": {
"kind": "Identifier",
"pos": 15,
"end": 18,
"text": "foo"
},
"comment": ""
},
"length": 1,
"pos": 8,
@@ -27,7 +27,8 @@
"pos": 17,
"end": 23
}
}
},
"comment": ""
},
"length": 1,
"pos": 8,
@@ -27,7 +27,8 @@
"pos": 17,
"end": 23
}
}
},
"comment": "Description text follows"
},
"length": 1,
"pos": 8,
@@ -27,7 +27,8 @@
"pos": 18,
"end": 24
}
}
},
"comment": ""
},
"length": 1,
"pos": 8,
@@ -6,7 +6,7 @@
"0": {
"kind": "JSDocTemplateTag",
"pos": 8,
"end": 19,
"end": 20,
"atToken": {
"kind": "AtToken",
"pos": 8,
@@ -22,7 +22,7 @@
"0": {
"kind": "TypeParameter",
"pos": 18,
"end": 19,
"end": 20,
"name": {
"kind": "Identifier",
"pos": 18,
@@ -31,12 +31,13 @@
}
},
"length": 1,
"pos": 17,
"end": 19
}
"pos": 18,
"end": 20
},
"comment": ""
},
"length": 1,
"pos": 8,
"end": 19
"end": 20
}
}
@@ -6,7 +6,7 @@
"0": {
"kind": "JSDocTemplateTag",
"pos": 8,
"end": 21,
"end": 22,
"atToken": {
"kind": "AtToken",
"pos": 8,
@@ -33,7 +33,7 @@
"1": {
"kind": "TypeParameter",
"pos": 20,
"end": 21,
"end": 22,
"name": {
"kind": "Identifier",
"pos": 20,
@@ -42,12 +42,13 @@
}
},
"length": 2,
"pos": 17,
"end": 21
}
"pos": 18,
"end": 22
},
"comment": ""
},
"length": 1,
"pos": 8,
"end": 21
"end": 22
}
}
@@ -6,7 +6,7 @@
"0": {
"kind": "JSDocTemplateTag",
"pos": 8,
"end": 22,
"end": 23,
"atToken": {
"kind": "AtToken",
"pos": 8,
@@ -22,7 +22,7 @@
"0": {
"kind": "TypeParameter",
"pos": 18,
"end": 19,
"end": 20,
"name": {
"kind": "Identifier",
"pos": 18,
@@ -33,7 +33,7 @@
"1": {
"kind": "TypeParameter",
"pos": 21,
"end": 22,
"end": 23,
"name": {
"kind": "Identifier",
"pos": 21,
@@ -42,12 +42,13 @@
}
},
"length": 2,
"pos": 17,
"end": 22
}
"pos": 18,
"end": 23
},
"comment": ""
},
"length": 1,
"pos": 8,
"end": 22
"end": 23
}
}
@@ -6,7 +6,7 @@
"0": {
"kind": "JSDocTemplateTag",
"pos": 8,
"end": 22,
"end": 23,
"atToken": {
"kind": "AtToken",
"pos": 8,
@@ -33,7 +33,7 @@
"1": {
"kind": "TypeParameter",
"pos": 21,
"end": 22,
"end": 23,
"name": {
"kind": "Identifier",
"pos": 21,
@@ -42,12 +42,13 @@
}
},
"length": 2,
"pos": 17,
"end": 22
}
"pos": 18,
"end": 23
},
"comment": ""
},
"length": 1,
"pos": 8,
"end": 22
"end": 23
}
}
@@ -6,7 +6,7 @@
"0": {
"kind": "JSDocTemplateTag",
"pos": 8,
"end": 23,
"end": 24,
"atToken": {
"kind": "AtToken",
"pos": 8,
@@ -22,7 +22,7 @@
"0": {
"kind": "TypeParameter",
"pos": 18,
"end": 19,
"end": 20,
"name": {
"kind": "Identifier",
"pos": 18,
@@ -33,7 +33,7 @@
"1": {
"kind": "TypeParameter",
"pos": 22,
"end": 23,
"end": 24,
"name": {
"kind": "Identifier",
"pos": 22,
@@ -42,12 +42,13 @@
}
},
"length": 2,
"pos": 17,
"end": 23
}
"pos": 18,
"end": 24
},
"comment": ""
},
"length": 1,
"pos": 8,
"end": 23
"end": 24
}
}
@@ -6,7 +6,7 @@
"0": {
"kind": "JSDocTemplateTag",
"pos": 8,
"end": 23,
"end": 24,
"atToken": {
"kind": "AtToken",
"pos": 8,
@@ -22,7 +22,7 @@
"0": {
"kind": "TypeParameter",
"pos": 18,
"end": 19,
"end": 20,
"name": {
"kind": "Identifier",
"pos": 18,
@@ -33,7 +33,7 @@
"1": {
"kind": "TypeParameter",
"pos": 22,
"end": 23,
"end": 24,
"name": {
"kind": "Identifier",
"pos": 22,
@@ -42,12 +42,13 @@
}
},
"length": 2,
"pos": 17,
"end": 23
}
"pos": 18,
"end": 24
},
"comment": "Description of type parameters."
},
"length": 1,
"pos": 8,
"end": 23
"end": 24
}
}
@@ -33,7 +33,14 @@
"pos": 24,
"end": 29,
"text": "name1"
}
},
"parameterName": {
"kind": "Identifier",
"pos": 24,
"end": 29,
"text": "name1"
},
"comment": ""
},
"1": {
"kind": "JSDocParameterTag",
@@ -65,7 +72,14 @@
"pos": 50,
"end": 55,
"text": "name2"
}
},
"parameterName": {
"kind": "Identifier",
"pos": 50,
"end": 55,
"text": "name2"
},
"comment": ""
},
"length": 2,
"pos": 8,
@@ -33,10 +33,56 @@
"pos": 24,
"end": 29,
"text": "name1"
}
},
"parameterName": {
"kind": "Identifier",
"pos": 24,
"end": 29,
"text": "name1"
},
"comment": ""
},
"length": 1,
"1": {
"kind": "JSDocParameterTag",
"pos": 30,
"end": 51,
"atToken": {
"kind": "AtToken",
"pos": 30,
"end": 31
},
"tagName": {
"kind": "Identifier",
"pos": 31,
"end": 36,
"text": "param"
},
"typeExpression": {
"kind": "JSDocTypeExpression",
"pos": 37,
"end": 45,
"type": {
"kind": "NumberKeyword",
"pos": 38,
"end": 44
}
},
"postParameterName": {
"kind": "Identifier",
"pos": 46,
"end": 51,
"text": "name2"
},
"parameterName": {
"kind": "Identifier",
"pos": 46,
"end": 51,
"text": "name2"
},
"comment": ""
},
"length": 2,
"pos": 8,
"end": 29
"end": 51
}
}
@@ -27,7 +27,8 @@
"pos": 15,
"end": 21
}
}
},
"comment": ""
},
"length": 1,
"pos": 8,
@@ -6,7 +6,7 @@
"0": {
"kind": "JSDocTypedefTag",
"pos": 8,
"end": 97,
"end": 98,
"atToken": {
"kind": "AtToken",
"pos": 8,
@@ -26,15 +26,15 @@
},
"jsDocTypeLiteral": {
"kind": "JSDocTypeLiteral",
"pos": 23,
"end": 97,
"pos": 26,
"end": 98,
"jsDocTypeTag": {
"kind": "JSDocTypeTag",
"pos": 27,
"pos": 28,
"end": 42,
"atToken": {
"kind": "AtToken",
"pos": 27,
"pos": 28,
"end": 29
},
"tagName": {
@@ -63,11 +63,11 @@
"jsDocPropertyTags": [
{
"kind": "JSDocPropertyTag",
"pos": 46,
"end": 69,
"pos": 47,
"end": 72,
"atToken": {
"kind": "AtToken",
"pos": 46,
"pos": 47,
"end": 48
},
"tagName": {
@@ -95,11 +95,11 @@
},
{
"kind": "JSDocPropertyTag",
"pos": 73,
"end": 97,
"pos": 74,
"end": 98,
"atToken": {
"kind": "AtToken",
"pos": 73,
"pos": 74,
"end": 75
},
"tagName": {
@@ -126,10 +126,11 @@
}
}
]
}
},
"comment": ""
},
"length": 1,
"pos": 8,
"end": 97
"end": 98
}
}
@@ -0,0 +1,30 @@
{
"kind": "JSDocRecordType",
"pos": 1,
"end": 13,
"literal": {
"kind": "TypeLiteral",
"pos": 1,
"end": 13,
"members": {
"0": {
"kind": "CallSignature",
"pos": 2,
"end": 12,
"parameters": {
"length": 0,
"pos": 3,
"end": 3
},
"type": {
"kind": "NumberKeyword",
"pos": 5,
"end": 12
}
},
"length": 1,
"pos": 2,
"end": 12
}
}
}
@@ -0,0 +1,36 @@
{
"kind": "JSDocRecordType",
"pos": 1,
"end": 16,
"literal": {
"kind": "TypeLiteral",
"pos": 1,
"end": 16,
"members": {
"0": {
"kind": "MethodSignature",
"pos": 2,
"end": 15,
"name": {
"kind": "Identifier",
"pos": 2,
"end": 5,
"text": "foo"
},
"parameters": {
"length": 0,
"pos": 6,
"end": 6
},
"type": {
"kind": "NumberKeyword",
"pos": 8,
"end": 15
}
},
"length": 1,
"pos": 2,
"end": 15
}
}
}
@@ -2,9 +2,14 @@
"kind": "JSDocRecordType",
"pos": 1,
"end": 3,
"members": {
"length": 0,
"pos": 2,
"end": 2
"literal": {
"kind": "TypeLiteral",
"pos": 1,
"end": 3,
"members": {
"length": 0,
"pos": 2,
"end": 2
}
}
}
@@ -2,20 +2,25 @@
"kind": "JSDocRecordType",
"pos": 1,
"end": 6,
"members": {
"0": {
"kind": "JSDocRecordMember",
"pos": 2,
"end": 5,
"name": {
"kind": "Identifier",
"literal": {
"kind": "TypeLiteral",
"pos": 1,
"end": 6,
"members": {
"0": {
"kind": "PropertySignature",
"pos": 2,
"end": 5,
"text": "foo"
}
},
"length": 1,
"pos": 2,
"end": 5
"name": {
"kind": "Identifier",
"pos": 2,
"end": 5,
"text": "foo"
}
},
"length": 1,
"pos": 2,
"end": 5
}
}
}
@@ -2,25 +2,30 @@
"kind": "JSDocRecordType",
"pos": 1,
"end": 14,
"members": {
"0": {
"kind": "JSDocRecordMember",
"pos": 2,
"end": 13,
"name": {
"kind": "Identifier",
"literal": {
"kind": "TypeLiteral",
"pos": 1,
"end": 14,
"members": {
"0": {
"kind": "PropertySignature",
"pos": 2,
"end": 5,
"text": "foo"
"end": 13,
"name": {
"kind": "Identifier",
"pos": 2,
"end": 5,
"text": "foo"
},
"type": {
"kind": "NumberKeyword",
"pos": 6,
"end": 13
}
},
"type": {
"kind": "NumberKeyword",
"pos": 6,
"end": 13
}
},
"length": 1,
"pos": 2,
"end": 13
"length": 1,
"pos": 2,
"end": 13
}
}
}
@@ -2,31 +2,36 @@
"kind": "JSDocRecordType",
"pos": 1,
"end": 11,
"members": {
"0": {
"kind": "JSDocRecordMember",
"pos": 2,
"end": 5,
"name": {
"kind": "Identifier",
"literal": {
"kind": "TypeLiteral",
"pos": 1,
"end": 11,
"members": {
"0": {
"kind": "PropertySignature",
"pos": 2,
"end": 5,
"text": "foo"
}
},
"1": {
"kind": "JSDocRecordMember",
"pos": 6,
"end": 10,
"name": {
"kind": "Identifier",
"end": 6,
"name": {
"kind": "Identifier",
"pos": 2,
"end": 5,
"text": "foo"
}
},
"1": {
"kind": "PropertySignature",
"pos": 6,
"end": 10,
"text": "bar"
}
},
"length": 2,
"pos": 2,
"end": 10
"name": {
"kind": "Identifier",
"pos": 6,
"end": 10,
"text": "bar"
}
},
"length": 2,
"pos": 2,
"end": 10
}
}
}
@@ -2,36 +2,41 @@
"kind": "JSDocRecordType",
"pos": 1,
"end": 19,
"members": {
"0": {
"kind": "JSDocRecordMember",
"pos": 2,
"end": 13,
"name": {
"kind": "Identifier",
"literal": {
"kind": "TypeLiteral",
"pos": 1,
"end": 19,
"members": {
"0": {
"kind": "PropertySignature",
"pos": 2,
"end": 5,
"text": "foo"
"end": 14,
"name": {
"kind": "Identifier",
"pos": 2,
"end": 5,
"text": "foo"
},
"type": {
"kind": "NumberKeyword",
"pos": 6,
"end": 13
}
},
"type": {
"kind": "NumberKeyword",
"pos": 6,
"end": 13
}
},
"1": {
"kind": "JSDocRecordMember",
"pos": 14,
"end": 18,
"name": {
"kind": "Identifier",
"1": {
"kind": "PropertySignature",
"pos": 14,
"end": 18,
"text": "bar"
}
},
"length": 2,
"pos": 2,
"end": 18
"name": {
"kind": "Identifier",
"pos": 14,
"end": 18,
"text": "bar"
}
},
"length": 2,
"pos": 2,
"end": 18
}
}
}
@@ -2,36 +2,41 @@
"kind": "JSDocRecordType",
"pos": 1,
"end": 19,
"members": {
"0": {
"kind": "JSDocRecordMember",
"pos": 2,
"end": 5,
"name": {
"kind": "Identifier",
"literal": {
"kind": "TypeLiteral",
"pos": 1,
"end": 19,
"members": {
"0": {
"kind": "PropertySignature",
"pos": 2,
"end": 5,
"text": "foo"
}
},
"1": {
"kind": "JSDocRecordMember",
"pos": 6,
"end": 18,
"name": {
"kind": "Identifier",
"pos": 6,
"end": 10,
"text": "bar"
"end": 6,
"name": {
"kind": "Identifier",
"pos": 2,
"end": 5,
"text": "foo"
}
},
"type": {
"kind": "NumberKeyword",
"pos": 11,
"end": 18
}
},
"length": 2,
"pos": 2,
"end": 18
"1": {
"kind": "PropertySignature",
"pos": 6,
"end": 18,
"name": {
"kind": "Identifier",
"pos": 6,
"end": 10,
"text": "bar"
},
"type": {
"kind": "NumberKeyword",
"pos": 11,
"end": 18
}
},
"length": 2,
"pos": 2,
"end": 18
}
}
}
@@ -2,41 +2,46 @@
"kind": "JSDocRecordType",
"pos": 1,
"end": 27,
"members": {
"0": {
"kind": "JSDocRecordMember",
"pos": 2,
"end": 13,
"name": {
"kind": "Identifier",
"literal": {
"kind": "TypeLiteral",
"pos": 1,
"end": 27,
"members": {
"0": {
"kind": "PropertySignature",
"pos": 2,
"end": 5,
"text": "foo"
"end": 14,
"name": {
"kind": "Identifier",
"pos": 2,
"end": 5,
"text": "foo"
},
"type": {
"kind": "NumberKeyword",
"pos": 6,
"end": 13
}
},
"type": {
"kind": "NumberKeyword",
"pos": 6,
"end": 13
}
},
"1": {
"kind": "JSDocRecordMember",
"pos": 14,
"end": 26,
"name": {
"kind": "Identifier",
"1": {
"kind": "PropertySignature",
"pos": 14,
"end": 18,
"text": "bar"
"end": 26,
"name": {
"kind": "Identifier",
"pos": 14,
"end": 18,
"text": "bar"
},
"type": {
"kind": "NumberKeyword",
"pos": 19,
"end": 26
}
},
"type": {
"kind": "NumberKeyword",
"pos": 19,
"end": 26
}
},
"length": 2,
"pos": 2,
"end": 26
"length": 2,
"pos": 2,
"end": 26
}
}
}
@@ -2,21 +2,26 @@
"kind": "JSDocRecordType",
"pos": 1,
"end": 11,
"members": {
"0": {
"kind": "JSDocRecordMember",
"pos": 2,
"end": 10,
"name": {
"kind": "Identifier",
"literal": {
"kind": "TypeLiteral",
"pos": 1,
"end": 11,
"members": {
"0": {
"kind": "PropertySignature",
"pos": 2,
"end": 10,
"originalKeywordKind": "FunctionKeyword",
"text": "function"
}
},
"length": 1,
"pos": 2,
"end": 10
"name": {
"kind": "Identifier",
"pos": 2,
"end": 10,
"originalKeywordKind": "FunctionKeyword",
"text": "function"
}
},
"length": 1,
"pos": 2,
"end": 10
}
}
}
@@ -0,0 +1,26 @@
{
"kind": "JSDocRecordType",
"pos": 1,
"end": 5,
"literal": {
"kind": "TypeLiteral",
"pos": 1,
"end": 5,
"members": {
"0": {
"kind": "PropertySignature",
"pos": 2,
"end": 4,
"name": {
"kind": "Identifier",
"pos": 2,
"end": 3,
"text": "a"
}
},
"length": 1,
"pos": 2,
"end": 4
}
}
}
@@ -0,0 +1,20 @@
//// [commentInNamespaceDeclarationWithIdentifierPathName.ts]
namespace hello.hi.world
{
function foo() {}
// TODO, blah
}
//// [commentInNamespaceDeclarationWithIdentifierPathName.js]
var hello;
(function (hello) {
var hi;
(function (hi) {
var world;
(function (world) {
function foo() { }
// TODO, blah
})(world = hi.world || (hi.world = {}));
})(hi = hello.hi || (hello.hi = {}));
})(hello || (hello = {}));
@@ -0,0 +1,11 @@
=== tests/cases/compiler/commentInNamespaceDeclarationWithIdentifierPathName.ts ===
namespace hello.hi.world
>hello : Symbol(hello, Decl(commentInNamespaceDeclarationWithIdentifierPathName.ts, 0, 0))
>hi : Symbol(hi, Decl(commentInNamespaceDeclarationWithIdentifierPathName.ts, 0, 16))
>world : Symbol(world, Decl(commentInNamespaceDeclarationWithIdentifierPathName.ts, 0, 19))
{
function foo() {}
>foo : Symbol(foo, Decl(commentInNamespaceDeclarationWithIdentifierPathName.ts, 1, 1))
// TODO, blah
}
@@ -0,0 +1,11 @@
=== tests/cases/compiler/commentInNamespaceDeclarationWithIdentifierPathName.ts ===
namespace hello.hi.world
>hello : typeof hello
>hi : typeof hi
>world : typeof world
{
function foo() {}
>foo : () => void
// TODO, blah
}
@@ -0,0 +1,47 @@
//// [commentOnDecoratedClassDeclaration.ts]
declare function decorator(x: string): any;
/**
* Leading trivia
*/
@decorator("hello")
class Remote { }
/**
* Floating Comment
*/
@decorator("hi")
class AnotherRomote {
constructor() {}
}
//// [commentOnDecoratedClassDeclaration.js]
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
/**
* Leading trivia
*/
var Remote = (function () {
function Remote() {
}
return Remote;
}());
Remote = __decorate([
decorator("hello")
], Remote);
/**
* Floating Comment
*/
var AnotherRomote = (function () {
function AnotherRomote() {
}
return AnotherRomote;
}());
AnotherRomote = __decorate([
decorator("hi")
], AnotherRomote);
@@ -0,0 +1,26 @@
=== tests/cases/compiler/commentOnDecoratedClassDeclaration.ts ===
declare function decorator(x: string): any;
>decorator : Symbol(decorator, Decl(commentOnDecoratedClassDeclaration.ts, 0, 0))
>x : Symbol(x, Decl(commentOnDecoratedClassDeclaration.ts, 0, 27))
/**
* Leading trivia
*/
@decorator("hello")
>decorator : Symbol(decorator, Decl(commentOnDecoratedClassDeclaration.ts, 0, 0))
class Remote { }
>Remote : Symbol(Remote, Decl(commentOnDecoratedClassDeclaration.ts, 0, 43))
/**
* Floating Comment
*/
@decorator("hi")
>decorator : Symbol(decorator, Decl(commentOnDecoratedClassDeclaration.ts, 0, 0))
class AnotherRomote {
>AnotherRomote : Symbol(AnotherRomote, Decl(commentOnDecoratedClassDeclaration.ts, 6, 16))
constructor() {}
}
@@ -0,0 +1,30 @@
=== tests/cases/compiler/commentOnDecoratedClassDeclaration.ts ===
declare function decorator(x: string): any;
>decorator : (x: string) => any
>x : string
/**
* Leading trivia
*/
@decorator("hello")
>decorator("hello") : any
>decorator : (x: string) => any
>"hello" : "hello"
class Remote { }
>Remote : Remote
/**
* Floating Comment
*/
@decorator("hi")
>decorator("hi") : any
>decorator : (x: string) => any
>"hi" : "hi"
class AnotherRomote {
>AnotherRomote : AnotherRomote
constructor() {}
}
@@ -0,0 +1,19 @@
//// [commentOnExportEnumDeclaration.ts]
/**
* comment
*/
export enum Color {
r, g, b
}
//// [commentOnExportEnumDeclaration.js]
"use strict";
/**
* comment
*/
(function (Color) {
Color[Color["r"] = 0] = "r";
Color[Color["g"] = 1] = "g";
Color[Color["b"] = 2] = "b";
})(exports.Color || (exports.Color = {}));
var Color = exports.Color;
@@ -0,0 +1,12 @@
=== tests/cases/compiler/commentOnExportEnumDeclaration.ts ===
/**
* comment
*/
export enum Color {
>Color : Symbol(Color, Decl(commentOnExportEnumDeclaration.ts, 0, 0))
r, g, b
>r : Symbol(Color.r, Decl(commentOnExportEnumDeclaration.ts, 3, 19))
>g : Symbol(Color.g, Decl(commentOnExportEnumDeclaration.ts, 4, 6))
>b : Symbol(Color.b, Decl(commentOnExportEnumDeclaration.ts, 4, 9))
}
@@ -0,0 +1,12 @@
=== tests/cases/compiler/commentOnExportEnumDeclaration.ts ===
/**
* comment
*/
export enum Color {
>Color : Color
r, g, b
>r : Color.r
>g : Color.g
>b : Color.b
}
@@ -62,21 +62,21 @@ declare function isHTMLCollection(sourceObj: any): sourceObj is HTMLCollection;
>HTMLCollection : HTMLCollection
type EventTargetLike = {a: string} | HTMLCollection | NodeList;
>EventTargetLike : EventTargetLike
>EventTargetLike : NodeList | HTMLCollection | { a: string; }
>a : string
>HTMLCollection : HTMLCollection
>NodeList : NodeList
var sourceObj: EventTargetLike = <any>undefined;
>sourceObj : EventTargetLike
>EventTargetLike : EventTargetLike
>sourceObj : NodeList | HTMLCollection | { a: string; }
>EventTargetLike : NodeList | HTMLCollection | { a: string; }
><any>undefined : any
>undefined : undefined
if (isNodeList(sourceObj)) {
>isNodeList(sourceObj) : boolean
>isNodeList : (sourceObj: any) => sourceObj is NodeList
>sourceObj : EventTargetLike
>sourceObj : NodeList | HTMLCollection | { a: string; }
sourceObj.length;
>sourceObj.length : number
@@ -87,7 +87,7 @@ if (isNodeList(sourceObj)) {
if (isHTMLCollection(sourceObj)) {
>isHTMLCollection(sourceObj) : boolean
>isHTMLCollection : (sourceObj: any) => sourceObj is HTMLCollection
>sourceObj : EventTargetLike
>sourceObj : NodeList | HTMLCollection | { a: string; }
sourceObj.length;
>sourceObj.length : number
@@ -99,7 +99,7 @@ if (isNodeList(sourceObj) || isHTMLCollection(sourceObj)) {
>isNodeList(sourceObj) || isHTMLCollection(sourceObj) : boolean
>isNodeList(sourceObj) : boolean
>isNodeList : (sourceObj: any) => sourceObj is NodeList
>sourceObj : EventTargetLike
>sourceObj : NodeList | HTMLCollection | { a: string; }
>isHTMLCollection(sourceObj) : boolean
>isHTMLCollection : (sourceObj: any) => sourceObj is HTMLCollection
>sourceObj : HTMLCollection | { a: string; }
@@ -0,0 +1,10 @@
//// [declarationEmitArrayTypesFromGenericArrayUsage.ts]
interface A extends Array<string> { }
//// [declarationEmitArrayTypesFromGenericArrayUsage.js]
//// [declarationEmitArrayTypesFromGenericArrayUsage.d.ts]
interface A extends Array<string> {
}
@@ -0,0 +1,5 @@
=== tests/cases/compiler/declarationEmitArrayTypesFromGenericArrayUsage.ts ===
interface A extends Array<string> { }
>A : Symbol(A, Decl(declarationEmitArrayTypesFromGenericArrayUsage.ts, 0, 0))
>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
@@ -0,0 +1,5 @@
=== tests/cases/compiler/declarationEmitArrayTypesFromGenericArrayUsage.ts ===
interface A extends Array<string> { }
>A : A
>Array : T[]
@@ -1,4 +1,4 @@
//// [declarationEmit_bindingPatterns.ts]
//// [declarationEmitBindingPatterns.ts]
const k = ({x: z = 'y'}) => { }
@@ -6,7 +6,7 @@ var a;
function f({} = a, [] = a, { p: {} = a} = a) {
}
//// [declarationEmit_bindingPatterns.js]
//// [declarationEmitBindingPatterns.js]
var k = function (_a) {
var _b = _a.x, z = _b === void 0 ? 'y' : _b;
};
@@ -18,7 +18,7 @@ function f(_a, _b, _c) {
}
//// [declarationEmit_bindingPatterns.d.ts]
//// [declarationEmitBindingPatterns.d.ts]
declare const k: ({x: z}: {
x?: string;
}) => void;
@@ -0,0 +1,17 @@
=== tests/cases/compiler/declarationEmitBindingPatterns.ts ===
const k = ({x: z = 'y'}) => { }
>k : Symbol(k, Decl(declarationEmitBindingPatterns.ts, 1, 5))
>x : Symbol(x)
>z : Symbol(z, Decl(declarationEmitBindingPatterns.ts, 1, 12))
var a;
>a : Symbol(a, Decl(declarationEmitBindingPatterns.ts, 3, 3))
function f({} = a, [] = a, { p: {} = a} = a) {
>f : Symbol(f, Decl(declarationEmitBindingPatterns.ts, 3, 6))
>a : Symbol(a, Decl(declarationEmitBindingPatterns.ts, 3, 3))
>a : Symbol(a, Decl(declarationEmitBindingPatterns.ts, 3, 3))
>a : Symbol(a, Decl(declarationEmitBindingPatterns.ts, 3, 3))
>a : Symbol(a, Decl(declarationEmitBindingPatterns.ts, 3, 3))
}
@@ -1,4 +1,4 @@
=== tests/cases/compiler/declarationEmit_bindingPatterns.ts ===
=== tests/cases/compiler/declarationEmitBindingPatterns.ts ===
const k = ({x: z = 'y'}) => { }
>k : ({x: z}: { x?: string; }) => void
@@ -1,4 +1,4 @@
//// [declarationEmit_classMemberNameConflict.ts]
//// [declarationEmitClassMemberNameConflict.ts]
export class C1 {
C1() { } // has to be the same as the class name
@@ -36,7 +36,7 @@ export class C4 {
}
}
//// [declarationEmit_classMemberNameConflict.js]
//// [declarationEmitClassMemberNameConflict.js]
"use strict";
var C1 = (function () {
function C1() {
@@ -93,7 +93,7 @@ var C4 = (function () {
exports.C4 = C4;
//// [declarationEmit_classMemberNameConflict.d.ts]
//// [declarationEmitClassMemberNameConflict.d.ts]
export declare class C1 {
C1(): void;
bar(): (t: typeof C1) => void;
@@ -0,0 +1,70 @@
=== tests/cases/compiler/declarationEmitClassMemberNameConflict.ts ===
export class C1 {
>C1 : Symbol(C1, Decl(declarationEmitClassMemberNameConflict.ts, 0, 0))
C1() { } // has to be the same as the class name
>C1 : Symbol(C1.C1, Decl(declarationEmitClassMemberNameConflict.ts, 1, 17))
bar() {
>bar : Symbol(C1.bar, Decl(declarationEmitClassMemberNameConflict.ts, 2, 12))
return function (t: typeof C1) {
>t : Symbol(t, Decl(declarationEmitClassMemberNameConflict.ts, 5, 25))
>C1 : Symbol(C1, Decl(declarationEmitClassMemberNameConflict.ts, 0, 0))
};
}
}
export class C2 {
>C2 : Symbol(C2, Decl(declarationEmitClassMemberNameConflict.ts, 8, 1))
C2: any // has to be the same as the class name
>C2 : Symbol(C2.C2, Decl(declarationEmitClassMemberNameConflict.ts, 10, 17))
bar() {
>bar : Symbol(C2.bar, Decl(declarationEmitClassMemberNameConflict.ts, 11, 11))
return function (t: typeof C2) {
>t : Symbol(t, Decl(declarationEmitClassMemberNameConflict.ts, 14, 25))
>C2 : Symbol(C2, Decl(declarationEmitClassMemberNameConflict.ts, 8, 1))
};
}
}
export class C3 {
>C3 : Symbol(C3, Decl(declarationEmitClassMemberNameConflict.ts, 17, 1))
get C3() { return 0; } // has to be the same as the class name
>C3 : Symbol(C3.C3, Decl(declarationEmitClassMemberNameConflict.ts, 19, 17))
bar() {
>bar : Symbol(C3.bar, Decl(declarationEmitClassMemberNameConflict.ts, 20, 26))
return function (t: typeof C3) {
>t : Symbol(t, Decl(declarationEmitClassMemberNameConflict.ts, 23, 25))
>C3 : Symbol(C3, Decl(declarationEmitClassMemberNameConflict.ts, 17, 1))
};
}
}
export class C4 {
>C4 : Symbol(C4, Decl(declarationEmitClassMemberNameConflict.ts, 26, 1))
set C4(v) { } // has to be the same as the class name
>C4 : Symbol(C4.C4, Decl(declarationEmitClassMemberNameConflict.ts, 28, 17))
>v : Symbol(v, Decl(declarationEmitClassMemberNameConflict.ts, 29, 11))
bar() {
>bar : Symbol(C4.bar, Decl(declarationEmitClassMemberNameConflict.ts, 29, 17))
return function (t: typeof C4) {
>t : Symbol(t, Decl(declarationEmitClassMemberNameConflict.ts, 32, 25))
>C4 : Symbol(C4, Decl(declarationEmitClassMemberNameConflict.ts, 26, 1))
};
}
}
@@ -1,4 +1,4 @@
=== tests/cases/compiler/declarationEmit_classMemberNameConflict.ts ===
=== tests/cases/compiler/declarationEmitClassMemberNameConflict.ts ===
export class C1 {
>C1 : C1
@@ -1,4 +1,4 @@
//// [declarationEmit_classMemberNameConflict2.ts]
//// [declarationEmitClassMemberNameConflict2.ts]
const Bar = 'bar';
@@ -21,7 +21,7 @@ class Foo {
Hello2 = Hello1;
}
//// [declarationEmit_classMemberNameConflict2.js]
//// [declarationEmitClassMemberNameConflict2.js]
var Bar = 'bar';
var Hello;
(function (Hello) {
@@ -44,7 +44,7 @@ var Foo = (function () {
}());
//// [declarationEmit_classMemberNameConflict2.d.ts]
//// [declarationEmitClassMemberNameConflict2.d.ts]
declare const Bar: "bar";
declare enum Hello {
World = 0,
@@ -0,0 +1,37 @@
=== tests/cases/compiler/declarationEmitClassMemberNameConflict2.ts ===
const Bar = 'bar';
>Bar : Symbol(Bar, Decl(declarationEmitClassMemberNameConflict2.ts, 1, 5))
enum Hello {
>Hello : Symbol(Hello, Decl(declarationEmitClassMemberNameConflict2.ts, 1, 18))
World
>World : Symbol(Hello.World, Decl(declarationEmitClassMemberNameConflict2.ts, 3, 12))
}
enum Hello1 {
>Hello1 : Symbol(Hello1, Decl(declarationEmitClassMemberNameConflict2.ts, 5, 1))
World1
>World1 : Symbol(Hello1.World1, Decl(declarationEmitClassMemberNameConflict2.ts, 7, 13))
}
class Foo {
>Foo : Symbol(Foo, Decl(declarationEmitClassMemberNameConflict2.ts, 9, 1))
// Same names + string => OK
Bar = Bar;
>Bar : Symbol(Foo.Bar, Decl(declarationEmitClassMemberNameConflict2.ts, 11, 11))
>Bar : Symbol(Bar, Decl(declarationEmitClassMemberNameConflict2.ts, 1, 5))
// Same names + enum => OK
Hello = Hello;
>Hello : Symbol(Foo.Hello, Decl(declarationEmitClassMemberNameConflict2.ts, 13, 14))
>Hello : Symbol(Hello, Decl(declarationEmitClassMemberNameConflict2.ts, 1, 18))
// Different names + enum => OK
Hello2 = Hello1;
>Hello2 : Symbol(Foo.Hello2, Decl(declarationEmitClassMemberNameConflict2.ts, 16, 18))
>Hello1 : Symbol(Hello1, Decl(declarationEmitClassMemberNameConflict2.ts, 5, 1))
}
@@ -1,4 +1,4 @@
=== tests/cases/compiler/declarationEmit_classMemberNameConflict2.ts ===
=== tests/cases/compiler/declarationEmitClassMemberNameConflict2.ts ===
const Bar = 'bar';
>Bar : "bar"
@@ -1,4 +1,4 @@
//// [tests/cases/compiler/declarationEmit_exportAssignment.ts] ////
//// [tests/cases/compiler/declarationEmitExportAssignment.ts] ////
//// [utils.ts]
@@ -1,4 +1,4 @@
//// [tests/cases/compiler/declarationEmit_exportDeclaration.ts] ////
//// [tests/cases/compiler/declarationEmitExportDeclaration.ts] ////
//// [utils.ts]
@@ -1,4 +1,4 @@
//// [declarationEmit_expressionInExtends.ts]
//// [declarationEmitExpressionInExtends.ts]
var x: {
new<T>(s: any): Q;
@@ -14,7 +14,7 @@ class B extends x<string> {
var q: B;
q.s;
//// [declarationEmit_expressionInExtends.js]
//// [declarationEmitExpressionInExtends.js]
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
@@ -38,7 +38,7 @@ var q;
q.s;
//// [declarationEmit_expressionInExtends.d.ts]
//// [declarationEmitExpressionInExtends.d.ts]
declare var x: {
new <T>(s: any): Q;
};
@@ -0,0 +1,32 @@
=== tests/cases/compiler/declarationEmitExpressionInExtends.ts ===
var x: {
>x : Symbol(x, Decl(declarationEmitExpressionInExtends.ts, 1, 3))
new<T>(s: any): Q;
>T : Symbol(T, Decl(declarationEmitExpressionInExtends.ts, 2, 8))
>s : Symbol(s, Decl(declarationEmitExpressionInExtends.ts, 2, 11))
>Q : Symbol(Q, Decl(declarationEmitExpressionInExtends.ts, 3, 1))
}
class Q {
>Q : Symbol(Q, Decl(declarationEmitExpressionInExtends.ts, 3, 1))
s: string;
>s : Symbol(Q.s, Decl(declarationEmitExpressionInExtends.ts, 5, 9))
}
class B extends x<string> {
>B : Symbol(B, Decl(declarationEmitExpressionInExtends.ts, 7, 1))
>x : Symbol(x, Decl(declarationEmitExpressionInExtends.ts, 1, 3))
}
var q: B;
>q : Symbol(q, Decl(declarationEmitExpressionInExtends.ts, 12, 3))
>B : Symbol(B, Decl(declarationEmitExpressionInExtends.ts, 7, 1))
q.s;
>q.s : Symbol(Q.s, Decl(declarationEmitExpressionInExtends.ts, 5, 9))
>q : Symbol(q, Decl(declarationEmitExpressionInExtends.ts, 12, 3))
>s : Symbol(Q.s, Decl(declarationEmitExpressionInExtends.ts, 5, 9))
@@ -1,4 +1,4 @@
=== tests/cases/compiler/declarationEmit_expressionInExtends.ts ===
=== tests/cases/compiler/declarationEmitExpressionInExtends.ts ===
var x: {
>x : new <T>(s: any) => Q
@@ -1,4 +1,4 @@
//// [declarationEmit_expressionInExtends2.ts]
//// [declarationEmitExpressionInExtends2.ts]
class C<T, U> {
x: T;
@@ -12,7 +12,7 @@ function getClass<T>(c: T) {
class MyClass extends getClass(2) <string, number> {
}
//// [declarationEmit_expressionInExtends2.js]
//// [declarationEmitExpressionInExtends2.js]
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
@@ -36,7 +36,7 @@ var MyClass = (function (_super) {
}(getClass(2)));
//// [declarationEmit_expressionInExtends2.d.ts]
//// [declarationEmitExpressionInExtends2.d.ts]
declare class C<T, U> {
x: T;
y: U;
@@ -0,0 +1,30 @@
=== tests/cases/compiler/declarationEmitExpressionInExtends2.ts ===
class C<T, U> {
>C : Symbol(C, Decl(declarationEmitExpressionInExtends2.ts, 0, 0))
>T : Symbol(T, Decl(declarationEmitExpressionInExtends2.ts, 1, 8))
>U : Symbol(U, Decl(declarationEmitExpressionInExtends2.ts, 1, 10))
x: T;
>x : Symbol(C.x, Decl(declarationEmitExpressionInExtends2.ts, 1, 15))
>T : Symbol(T, Decl(declarationEmitExpressionInExtends2.ts, 1, 8))
y: U;
>y : Symbol(C.y, Decl(declarationEmitExpressionInExtends2.ts, 2, 9))
>U : Symbol(U, Decl(declarationEmitExpressionInExtends2.ts, 1, 10))
}
function getClass<T>(c: T) {
>getClass : Symbol(getClass, Decl(declarationEmitExpressionInExtends2.ts, 4, 1))
>T : Symbol(T, Decl(declarationEmitExpressionInExtends2.ts, 6, 18))
>c : Symbol(c, Decl(declarationEmitExpressionInExtends2.ts, 6, 21))
>T : Symbol(T, Decl(declarationEmitExpressionInExtends2.ts, 6, 18))
return C;
>C : Symbol(C, Decl(declarationEmitExpressionInExtends2.ts, 0, 0))
}
class MyClass extends getClass(2) <string, number> {
>MyClass : Symbol(MyClass, Decl(declarationEmitExpressionInExtends2.ts, 8, 1))
>getClass : Symbol(getClass, Decl(declarationEmitExpressionInExtends2.ts, 4, 1))
}

Some files were not shown because too many files have changed in this diff Show More