mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-09 07:21:18 -05:00
Merge pull request #17352 from Microsoft/jsdoc-param-type-literals
Parse jsdoc `@param` type literals
This commit is contained in:
@@ -1504,9 +1504,9 @@ namespace ts {
|
||||
return declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes);
|
||||
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.JsxAttributes:
|
||||
// Interface/Object-types always have their children added to the 'members' of
|
||||
// their container. They are only accessible through an instance of their
|
||||
@@ -2103,8 +2103,9 @@ namespace ts {
|
||||
case SyntaxKind.ConstructorType:
|
||||
return bindFunctionOrConstructorType(<SignatureDeclaration>node);
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.MappedType:
|
||||
return bindAnonymousTypeWorker(node as TypeLiteralNode | MappedTypeNode);
|
||||
return bindAnonymousTypeWorker(node as TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral);
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
return bindObjectLiteralExpression(<ObjectLiteralExpression>node);
|
||||
case SyntaxKind.FunctionExpression:
|
||||
@@ -2162,13 +2163,17 @@ namespace ts {
|
||||
case SyntaxKind.ModuleBlock:
|
||||
return updateStrictModeStatementList((<Block | ModuleBlock>node).statements);
|
||||
|
||||
case SyntaxKind.JSDocParameterTag:
|
||||
if (node.parent.kind !== SyntaxKind.JSDocTypeLiteral) {
|
||||
break;
|
||||
}
|
||||
// falls through
|
||||
case SyntaxKind.JSDocPropertyTag:
|
||||
return declareSymbolAndAddToSymbolTable(node as JSDocPropertyTag,
|
||||
(node as JSDocPropertyTag).isBracketed || ((node as JSDocPropertyTag).typeExpression && (node as JSDocPropertyTag).typeExpression.type.kind === SyntaxKind.JSDocOptionalType) ?
|
||||
SymbolFlags.Property | SymbolFlags.Optional : SymbolFlags.Property,
|
||||
SymbolFlags.PropertyExcludes);
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
return bindAnonymousTypeWorker(node as JSDocTypeLiteral);
|
||||
const propTag = node as JSDocPropertyLikeTag;
|
||||
const flags = propTag.isBracketed || propTag.typeExpression.type.kind === SyntaxKind.JSDocOptionalType ?
|
||||
SymbolFlags.Property | SymbolFlags.Optional :
|
||||
SymbolFlags.Property;
|
||||
return declareSymbolAndAddToSymbolTable(propTag, flags, SymbolFlags.PropertyExcludes);
|
||||
case SyntaxKind.JSDocTypedefTag: {
|
||||
const { fullName } = node as JSDocTypedefTag;
|
||||
if (!fullName || fullName.kind === SyntaxKind.Identifier) {
|
||||
|
||||
@@ -4493,8 +4493,8 @@ namespace ts {
|
||||
if (declaration.kind === SyntaxKind.ExportAssignment) {
|
||||
return links.type = checkExpression((<ExportAssignment>declaration).expression);
|
||||
}
|
||||
if (isInJavaScriptFile(declaration) && declaration.kind === SyntaxKind.JSDocPropertyTag && (<JSDocPropertyTag>declaration).typeExpression) {
|
||||
return links.type = getTypeFromTypeNode((<JSDocPropertyTag>declaration).typeExpression.type);
|
||||
if (isInJavaScriptFile(declaration) && isJSDocPropertyLikeTag(declaration) && declaration.typeExpression) {
|
||||
return links.type = getTypeFromTypeNode(declaration.typeExpression.type);
|
||||
}
|
||||
// Handle variable, parameter or property
|
||||
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
|
||||
@@ -5074,20 +5074,9 @@ namespace ts {
|
||||
return unknownType;
|
||||
}
|
||||
|
||||
let declaration: JSDocTypedefTag | TypeAliasDeclaration = getDeclarationOfKind<JSDocTypedefTag>(symbol, SyntaxKind.JSDocTypedefTag);
|
||||
let type: Type;
|
||||
if (declaration) {
|
||||
if (declaration.jsDocTypeLiteral) {
|
||||
type = getTypeFromTypeNode(declaration.jsDocTypeLiteral);
|
||||
}
|
||||
else {
|
||||
type = getTypeFromTypeNode(declaration.typeExpression.type);
|
||||
}
|
||||
}
|
||||
else {
|
||||
declaration = getDeclarationOfKind<TypeAliasDeclaration>(symbol, SyntaxKind.TypeAliasDeclaration);
|
||||
type = getTypeFromTypeNode(declaration.type);
|
||||
}
|
||||
const declaration = <JSDocTypedefTag | TypeAliasDeclaration>findDeclaration(
|
||||
symbol, d => d.kind === SyntaxKind.JSDocTypedefTag || d.kind === SyntaxKind.TypeAliasDeclaration);
|
||||
let type = getTypeFromTypeNode(declaration.kind === SyntaxKind.JSDocTypedefTag ? declaration.typeExpression : declaration.type);
|
||||
|
||||
if (popTypeResolution()) {
|
||||
const typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
|
||||
@@ -7662,9 +7651,12 @@ namespace ts {
|
||||
links.resolvedType = emptyTypeLiteralType;
|
||||
}
|
||||
else {
|
||||
const type = createObjectType(ObjectFlags.Anonymous, node.symbol);
|
||||
let type = createObjectType(ObjectFlags.Anonymous, node.symbol);
|
||||
type.aliasSymbol = aliasSymbol;
|
||||
type.aliasTypeArguments = getAliasTypeArgumentsForTypeNode(node);
|
||||
if (isJSDocTypeLiteral(node) && node.isArrayType) {
|
||||
type = createArrayType(type);
|
||||
}
|
||||
links.resolvedType = type;
|
||||
}
|
||||
}
|
||||
@@ -7898,7 +7890,8 @@ namespace ts {
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
case SyntaxKind.JSDocNonNullableType:
|
||||
case SyntaxKind.JSDocOptionalType:
|
||||
return getTypeFromTypeNode((<ParenthesizedTypeNode | JSDocTypeReferencingNode>node).type);
|
||||
case SyntaxKind.JSDocTypeExpression:
|
||||
return getTypeFromTypeNode((<ParenthesizedTypeNode | JSDocTypeReferencingNode | JSDocTypeExpression>node).type);
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.TypeLiteral:
|
||||
@@ -22646,8 +22639,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (entityName.parent!.kind === SyntaxKind.JSDocParameterTag) {
|
||||
const parameter = getParameterFromJSDoc(entityName.parent as JSDocParameterTag);
|
||||
return parameter && parameter.symbol;
|
||||
return getParameterSymbolFromJSDoc(entityName.parent as JSDocParameterTag);
|
||||
}
|
||||
|
||||
if (entityName.parent.kind === SyntaxKind.TypeParameter && entityName.parent.parent.kind === SyntaxKind.JSDocTemplateTag) {
|
||||
|
||||
@@ -59,6 +59,9 @@ namespace ts {
|
||||
* @param node a given node to visit its children
|
||||
* @param cbNode a callback to be invoked for all child nodes
|
||||
* @param cbNodes a callback to be invoked for embedded array
|
||||
*
|
||||
* @remarks `forEachChild` must visit the children of a node in the order
|
||||
* that they appear in the source code. The language service depends on this property to locate nodes by position.
|
||||
*/
|
||||
export function forEachChild<T>(node: Node, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
|
||||
if (!node || node.kind <= SyntaxKind.LastToken) {
|
||||
@@ -407,9 +410,15 @@ namespace ts {
|
||||
case SyntaxKind.JSDocComment:
|
||||
return visitNodes(cbNode, cbNodes, (<JSDoc>node).tags);
|
||||
case SyntaxKind.JSDocParameterTag:
|
||||
return visitNode(cbNode, (<JSDocParameterTag>node).preParameterName) ||
|
||||
visitNode(cbNode, (<JSDocParameterTag>node).typeExpression) ||
|
||||
visitNode(cbNode, (<JSDocParameterTag>node).postParameterName);
|
||||
case SyntaxKind.JSDocPropertyTag:
|
||||
if ((node as JSDocPropertyLikeTag).isNameFirst) {
|
||||
return visitNode(cbNode, (<JSDocPropertyLikeTag>node).name) ||
|
||||
visitNode(cbNode, (<JSDocPropertyLikeTag>node).typeExpression);
|
||||
}
|
||||
else {
|
||||
return visitNode(cbNode, (<JSDocPropertyLikeTag>node).typeExpression) ||
|
||||
visitNode(cbNode, (<JSDocPropertyLikeTag>node).name);
|
||||
}
|
||||
case SyntaxKind.JSDocReturnTag:
|
||||
return visitNode(cbNode, (<JSDocReturnTag>node).typeExpression);
|
||||
case SyntaxKind.JSDocTypeTag:
|
||||
@@ -419,15 +428,20 @@ namespace ts {
|
||||
case SyntaxKind.JSDocTemplateTag:
|
||||
return visitNodes(cbNode, cbNodes, (<JSDocTemplateTag>node).typeParameters);
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
return visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression) ||
|
||||
visitNode(cbNode, (<JSDocTypedefTag>node).fullName) ||
|
||||
visitNode(cbNode, (<JSDocTypedefTag>node).name) ||
|
||||
visitNode(cbNode, (<JSDocTypedefTag>node).jsDocTypeLiteral);
|
||||
if ((node as JSDocTypedefTag).typeExpression &&
|
||||
(node as JSDocTypedefTag).typeExpression.kind === SyntaxKind.JSDocTypeExpression) {
|
||||
return visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression) ||
|
||||
visitNode(cbNode, (<JSDocTypedefTag>node).fullName);
|
||||
}
|
||||
else {
|
||||
return visitNode(cbNode, (<JSDocTypedefTag>node).fullName) ||
|
||||
visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression);
|
||||
}
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
return visitNodes(cbNode, cbNodes, (<JSDocTypeLiteral>node).jsDocPropertyTags);
|
||||
case SyntaxKind.JSDocPropertyTag:
|
||||
return visitNode(cbNode, (<JSDocPropertyTag>node).typeExpression) ||
|
||||
visitNode(cbNode, (<JSDocPropertyTag>node).name);
|
||||
for (const tag of (node as JSDocTypeLiteral).jsDocPropertyTags) {
|
||||
visitNode(cbNode, tag);
|
||||
}
|
||||
return;
|
||||
case SyntaxKind.PartiallyEmittedExpression:
|
||||
return visitNode(cbNode, (<PartiallyEmittedExpression>node).expression);
|
||||
}
|
||||
@@ -1949,14 +1963,18 @@ namespace ts {
|
||||
break;
|
||||
}
|
||||
dotPos = scanner.getStartPos();
|
||||
const node: QualifiedName = <QualifiedName>createNode(SyntaxKind.QualifiedName, entity.pos);
|
||||
node.left = entity;
|
||||
node.right = parseRightSideOfDot(allowReservedWords);
|
||||
entity = finishNode(node);
|
||||
entity = createQualifiedName(entity, parseRightSideOfDot(allowReservedWords));
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
function createQualifiedName(entity: EntityName, name: Identifier): QualifiedName {
|
||||
const node = createNode(SyntaxKind.QualifiedName, entity.pos) as QualifiedName;
|
||||
node.left = entity;
|
||||
node.right = name;
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseRightSideOfDot(allowIdentifierNames: boolean): Identifier {
|
||||
// Technically a keyword is valid here as all identifiers and keywords are identifier names.
|
||||
// However, often we'll encounter this in error situations when the identifier or keyword
|
||||
@@ -6163,6 +6181,11 @@ namespace ts {
|
||||
SavingComments,
|
||||
}
|
||||
|
||||
const enum PropertyLikeParse {
|
||||
Property,
|
||||
Parameter,
|
||||
}
|
||||
|
||||
export function parseJSDocCommentWorker(start: number, length: number): JSDoc {
|
||||
const content = sourceText;
|
||||
start = start || 0;
|
||||
@@ -6342,7 +6365,7 @@ namespace ts {
|
||||
case "arg":
|
||||
case "argument":
|
||||
case "param":
|
||||
tag = parseParameterOrPropertyTag(atToken, tagName, /*shouldParseParamTag*/ true);
|
||||
tag = parseParameterOrPropertyTag(atToken, tagName, PropertyLikeParse.Parameter);
|
||||
break;
|
||||
case "return":
|
||||
case "returns":
|
||||
@@ -6465,10 +6488,10 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
function parseBracketNameInPropertyAndParamTag(): { name: Identifier, isBracketed: boolean } {
|
||||
// Looking for something like '[foo]' or 'foo'
|
||||
function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } {
|
||||
// Looking for something like '[foo]', 'foo', '[foo.bar]' or 'foo.bar'
|
||||
const isBracketed = parseOptional(SyntaxKind.OpenBracketToken);
|
||||
const name = parseJSDocIdentifierName(/*createIfMissing*/ true);
|
||||
const name = parseJSDocEntityName();
|
||||
if (isBracketed) {
|
||||
skipWhitespace();
|
||||
|
||||
@@ -6483,33 +6506,72 @@ namespace ts {
|
||||
return { name, isBracketed };
|
||||
}
|
||||
|
||||
function parseParameterOrPropertyTag(atToken: AtToken, tagName: Identifier, shouldParseParamTag: boolean): JSDocPropertyTag | JSDocParameterTag {
|
||||
function isObjectOrObjectArrayTypeReference(node: TypeNode): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
return true;
|
||||
case SyntaxKind.ArrayType:
|
||||
return isObjectOrObjectArrayTypeReference((node as ArrayTypeNode).elementType);
|
||||
default:
|
||||
return isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) && node.typeName.escapedText === "Object";
|
||||
}
|
||||
}
|
||||
|
||||
function parseParameterOrPropertyTag(atToken: AtToken, tagName: Identifier, target: PropertyLikeParse.Parameter): JSDocParameterTag;
|
||||
function parseParameterOrPropertyTag(atToken: AtToken, tagName: Identifier, target: PropertyLikeParse.Property): JSDocPropertyTag;
|
||||
function parseParameterOrPropertyTag(atToken: AtToken, tagName: Identifier, target: PropertyLikeParse): JSDocPropertyLikeTag {
|
||||
let typeExpression = tryParseTypeExpression();
|
||||
let isNameFirst = !typeExpression;
|
||||
skipWhitespace();
|
||||
|
||||
const { name, isBracketed } = parseBracketNameInPropertyAndParamTag();
|
||||
skipWhitespace();
|
||||
|
||||
let preName: Identifier, postName: Identifier;
|
||||
if (typeExpression) {
|
||||
postName = name;
|
||||
}
|
||||
else {
|
||||
preName = name;
|
||||
if (isNameFirst) {
|
||||
typeExpression = tryParseTypeExpression();
|
||||
}
|
||||
|
||||
const result = shouldParseParamTag ?
|
||||
const result: JSDocPropertyLikeTag = target === PropertyLikeParse.Parameter ?
|
||||
<JSDocParameterTag>createNode(SyntaxKind.JSDocParameterTag, atToken.pos) :
|
||||
<JSDocPropertyTag>createNode(SyntaxKind.JSDocPropertyTag, atToken.pos);
|
||||
const nestedTypeLiteral = parseNestedTypeLiteral(typeExpression, name);
|
||||
if (nestedTypeLiteral) {
|
||||
typeExpression = nestedTypeLiteral;
|
||||
isNameFirst = true;
|
||||
}
|
||||
result.atToken = atToken;
|
||||
result.tagName = tagName;
|
||||
result.preParameterName = preName;
|
||||
result.typeExpression = typeExpression;
|
||||
result.postParameterName = postName;
|
||||
result.name = postName || preName;
|
||||
result.name = name;
|
||||
result.isNameFirst = isNameFirst;
|
||||
result.isBracketed = isBracketed;
|
||||
return finishNode(result);
|
||||
|
||||
}
|
||||
|
||||
function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression, name: EntityName) {
|
||||
if (typeExpression && isObjectOrObjectArrayTypeReference(typeExpression.type)) {
|
||||
const typeLiteralExpression = <JSDocTypeExpression>createNode(SyntaxKind.JSDocTypeExpression, scanner.getTokenPos());
|
||||
let child: JSDocParameterTag | false;
|
||||
let jsdocTypeLiteral: JSDocTypeLiteral;
|
||||
const start = scanner.getStartPos();
|
||||
let children: JSDocParameterTag[];
|
||||
while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.Parameter, name))) {
|
||||
if (!children) {
|
||||
children = [];
|
||||
}
|
||||
children.push(child);
|
||||
}
|
||||
if (children) {
|
||||
jsdocTypeLiteral = <JSDocTypeLiteral>createNode(SyntaxKind.JSDocTypeLiteral, start);
|
||||
jsdocTypeLiteral.jsDocPropertyTags = children;
|
||||
if (typeExpression.type.kind === SyntaxKind.ArrayType) {
|
||||
jsdocTypeLiteral.isArrayType = true;
|
||||
}
|
||||
typeLiteralExpression.type = finishNode(jsdocTypeLiteral);
|
||||
return finishNode(typeLiteralExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseReturnTag(atToken: AtToken, tagName: Identifier): JSDocReturnTag {
|
||||
@@ -6573,69 +6635,44 @@ namespace ts {
|
||||
rightNode = rightNode.body;
|
||||
}
|
||||
}
|
||||
typedefTag.typeExpression = typeExpression;
|
||||
skipWhitespace();
|
||||
|
||||
if (typeExpression) {
|
||||
if (isObjectTypeReference(typeExpression.type)) {
|
||||
typedefTag.jsDocTypeLiteral = scanChildTags();
|
||||
typedefTag.typeExpression = typeExpression;
|
||||
if (!typeExpression || isObjectOrObjectArrayTypeReference(typeExpression.type)) {
|
||||
let child: JSDocTypeTag | JSDocPropertyTag | false;
|
||||
let jsdocTypeLiteral: JSDocTypeLiteral;
|
||||
let alreadyHasTypeTag = false;
|
||||
const start = scanner.getStartPos();
|
||||
while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.Property))) {
|
||||
if (!jsdocTypeLiteral) {
|
||||
jsdocTypeLiteral = <JSDocTypeLiteral>createNode(SyntaxKind.JSDocTypeLiteral, start);
|
||||
}
|
||||
if (child.kind === SyntaxKind.JSDocTypeTag) {
|
||||
if (alreadyHasTypeTag) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
jsdocTypeLiteral.jsDocTypeTag = child;
|
||||
alreadyHasTypeTag = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!jsdocTypeLiteral.jsDocPropertyTags) {
|
||||
jsdocTypeLiteral.jsDocPropertyTags = [] as MutableNodeArray<JSDocPropertyTag>;
|
||||
}
|
||||
(jsdocTypeLiteral.jsDocPropertyTags as MutableNodeArray<JSDocPropertyTag>).push(child);
|
||||
}
|
||||
}
|
||||
if (!typedefTag.jsDocTypeLiteral) {
|
||||
typedefTag.jsDocTypeLiteral = <JSDocTypeLiteral>typeExpression.type;
|
||||
if (jsdocTypeLiteral) {
|
||||
if (typeExpression && typeExpression.type.kind === SyntaxKind.ArrayType) {
|
||||
jsdocTypeLiteral.isArrayType = true;
|
||||
}
|
||||
typedefTag.typeExpression = finishNode(jsdocTypeLiteral);
|
||||
}
|
||||
}
|
||||
else {
|
||||
typedefTag.jsDocTypeLiteral = scanChildTags();
|
||||
}
|
||||
|
||||
return finishNode(typedefTag);
|
||||
|
||||
function isObjectTypeReference(node: TypeNode) {
|
||||
return node.kind === SyntaxKind.ObjectKeyword ||
|
||||
isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) && node.typeName.escapedText === "Object";
|
||||
}
|
||||
|
||||
function scanChildTags(): JSDocTypeLiteral {
|
||||
const jsDocTypeLiteral = <JSDocTypeLiteral>createNode(SyntaxKind.JSDocTypeLiteral, scanner.getStartPos());
|
||||
let resumePos = scanner.getStartPos();
|
||||
let canParseTag = true;
|
||||
let seenAsterisk = false;
|
||||
let parentTagTerminated = false;
|
||||
|
||||
while (token() !== SyntaxKind.EndOfFileToken && !parentTagTerminated) {
|
||||
nextJSDocToken();
|
||||
switch (token()) {
|
||||
case SyntaxKind.AtToken:
|
||||
if (canParseTag) {
|
||||
parentTagTerminated = !tryParseChildTag(jsDocTypeLiteral);
|
||||
if (!parentTagTerminated) {
|
||||
resumePos = scanner.getStartPos();
|
||||
}
|
||||
}
|
||||
seenAsterisk = false;
|
||||
break;
|
||||
case SyntaxKind.NewLineTrivia:
|
||||
resumePos = scanner.getStartPos() - 1;
|
||||
canParseTag = true;
|
||||
seenAsterisk = false;
|
||||
break;
|
||||
case SyntaxKind.AsteriskToken:
|
||||
if (seenAsterisk) {
|
||||
canParseTag = false;
|
||||
}
|
||||
seenAsterisk = true;
|
||||
break;
|
||||
case SyntaxKind.Identifier:
|
||||
canParseTag = false;
|
||||
break;
|
||||
case SyntaxKind.EndOfFileToken:
|
||||
break;
|
||||
}
|
||||
}
|
||||
scanner.setTextPos(resumePos);
|
||||
return finishNode(jsDocTypeLiteral);
|
||||
}
|
||||
|
||||
function parseJSDocTypeNameWithNamespace(flags: NodeFlags) {
|
||||
const pos = scanner.getTokenPos();
|
||||
const typeNameOrNamespaceName = parseJSDocIdentifierName();
|
||||
@@ -6655,8 +6692,58 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function escapedTextsEqual(a: EntityName, b: EntityName): boolean {
|
||||
while (!ts.isIdentifier(a) || !ts.isIdentifier(b)) {
|
||||
if (!ts.isIdentifier(a) && !ts.isIdentifier(b) && a.right.escapedText === b.right.escapedText) {
|
||||
a = a.left;
|
||||
b = b.left;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return a.escapedText === b.escapedText;
|
||||
}
|
||||
|
||||
function tryParseChildTag(parentTag: JSDocTypeLiteral): boolean {
|
||||
function parseChildParameterOrPropertyTag(target: PropertyLikeParse.Property): JSDocTypeTag | JSDocPropertyTag | false;
|
||||
function parseChildParameterOrPropertyTag(target: PropertyLikeParse.Parameter, name: EntityName): JSDocParameterTag | false;
|
||||
function parseChildParameterOrPropertyTag(target: PropertyLikeParse, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
|
||||
let canParseTag = true;
|
||||
let seenAsterisk = false;
|
||||
while (true) {
|
||||
nextJSDocToken();
|
||||
switch (token()) {
|
||||
case SyntaxKind.AtToken:
|
||||
if (canParseTag) {
|
||||
const child = tryParseChildTag(target);
|
||||
if (child && child.kind === SyntaxKind.JSDocParameterTag &&
|
||||
(ts.isIdentifier(child.name) || !escapedTextsEqual(name, child.name.left))) {
|
||||
return false;
|
||||
}
|
||||
return child;
|
||||
}
|
||||
seenAsterisk = false;
|
||||
break;
|
||||
case SyntaxKind.NewLineTrivia:
|
||||
canParseTag = true;
|
||||
seenAsterisk = false;
|
||||
break;
|
||||
case SyntaxKind.AsteriskToken:
|
||||
if (seenAsterisk) {
|
||||
canParseTag = false;
|
||||
}
|
||||
seenAsterisk = true;
|
||||
break;
|
||||
case SyntaxKind.Identifier:
|
||||
canParseTag = false;
|
||||
break;
|
||||
case SyntaxKind.EndOfFileToken:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tryParseChildTag(target: PropertyLikeParse): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
|
||||
Debug.assert(token() === SyntaxKind.AtToken);
|
||||
const atToken = <AtToken>createNode(SyntaxKind.AtToken, scanner.getStartPos());
|
||||
atToken.end = scanner.getTextPos();
|
||||
@@ -6667,27 +6754,16 @@ namespace ts {
|
||||
if (!tagName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (tagName.escapedText) {
|
||||
case "type":
|
||||
if (parentTag.jsDocTypeTag) {
|
||||
// already has a @type tag, terminate the parent tag now.
|
||||
return false;
|
||||
}
|
||||
parentTag.jsDocTypeTag = parseTypeTag(atToken, tagName);
|
||||
return true;
|
||||
return target === PropertyLikeParse.Property && parseTypeTag(atToken, tagName);
|
||||
case "prop":
|
||||
case "property":
|
||||
const propertyTag = parseParameterOrPropertyTag(atToken, tagName, /*shouldParseParamTag*/ false) as JSDocPropertyTag;
|
||||
if (propertyTag) {
|
||||
if (!parentTag.jsDocPropertyTags) {
|
||||
parentTag.jsDocPropertyTags = <MutableNodeArray<JSDocPropertyTag>>[];
|
||||
}
|
||||
(parentTag.jsDocPropertyTags as MutableNodeArray<JSDocPropertyTag>).push(propertyTag);
|
||||
return true;
|
||||
}
|
||||
// Error parsing property tag
|
||||
return false;
|
||||
return target === PropertyLikeParse.Property && parseParameterOrPropertyTag(atToken, tagName, target);
|
||||
case "arg":
|
||||
case "argument":
|
||||
case "param":
|
||||
return target === PropertyLikeParse.Parameter && parseParameterOrPropertyTag(atToken, tagName, target);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -6736,6 +6812,24 @@ namespace ts {
|
||||
return currentToken = scanner.scanJSDocToken();
|
||||
}
|
||||
|
||||
function parseJSDocEntityName(): EntityName {
|
||||
let entity: EntityName = parseJSDocIdentifierName(/*createIfMissing*/ true);
|
||||
if (parseOptional(SyntaxKind.OpenBracketToken)) {
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
// Note that y[] is accepted as an entity name, but the postfix brackets are not saved for checking.
|
||||
// Technically usejsdoc.org requires them for specifying a property of a type equivalent to Array<{ x: ...}>
|
||||
// but it's not worth it to enforce that restriction.
|
||||
}
|
||||
while (parseOptional(SyntaxKind.DotToken)) {
|
||||
const name = parseJSDocIdentifierName(/*createIfMissing*/ true);
|
||||
if (parseOptional(SyntaxKind.OpenBracketToken)) {
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
}
|
||||
entity = createQualifiedName(entity, name);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
function parseJSDocIdentifierName(createIfMissing = false): Identifier {
|
||||
return createJSDocIdentifier(tokenIsIdentifierOrKeyword(token()), createIfMissing);
|
||||
}
|
||||
|
||||
@@ -760,6 +760,7 @@ namespace ts {
|
||||
// SyntaxKind.ShorthandPropertyAssignment
|
||||
// SyntaxKind.EnumMember
|
||||
// SyntaxKind.JSDocPropertyTag
|
||||
// SyntaxKind.JSDocParameterTag
|
||||
export interface VariableLikeDeclaration extends NamedDeclaration {
|
||||
propertyName?: PropertyName;
|
||||
dotDotDotToken?: DotDotDotToken;
|
||||
@@ -2036,7 +2037,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// represents a top level: { type } expression in a JSDoc comment.
|
||||
export interface JSDocTypeExpression extends Node {
|
||||
export interface JSDocTypeExpression extends TypeNode {
|
||||
kind: SyntaxKind.JSDocTypeExpression;
|
||||
type: TypeNode;
|
||||
}
|
||||
@@ -2125,38 +2126,32 @@ namespace ts {
|
||||
kind: SyntaxKind.JSDocTypedefTag;
|
||||
fullName?: JSDocNamespaceDeclaration | Identifier;
|
||||
name?: Identifier;
|
||||
typeExpression?: JSDocTypeExpression;
|
||||
jsDocTypeLiteral?: JSDocTypeLiteral;
|
||||
typeExpression?: JSDocTypeExpression | JSDocTypeLiteral;
|
||||
}
|
||||
|
||||
export interface JSDocPropertyTag extends JSDocTag, TypeElement {
|
||||
export interface JSDocPropertyLikeTag extends JSDocTag, Declaration {
|
||||
parent: JSDoc;
|
||||
kind: SyntaxKind.JSDocPropertyTag;
|
||||
name: Identifier;
|
||||
/** the parameter name, if provided *before* the type (TypeScript-style) */
|
||||
preParameterName?: Identifier;
|
||||
/** the parameter name, if provided *after* the type (JSDoc-standard) */
|
||||
postParameterName?: Identifier;
|
||||
name: EntityName;
|
||||
typeExpression: JSDocTypeExpression;
|
||||
/** Whether the property name came before the type -- non-standard for JSDoc, but Typescript-like */
|
||||
isNameFirst: boolean;
|
||||
isBracketed: boolean;
|
||||
}
|
||||
|
||||
export interface JSDocPropertyTag extends JSDocPropertyLikeTag {
|
||||
kind: SyntaxKind.JSDocPropertyTag;
|
||||
}
|
||||
|
||||
export interface JSDocParameterTag extends JSDocPropertyLikeTag {
|
||||
kind: SyntaxKind.JSDocParameterTag;
|
||||
}
|
||||
|
||||
export interface JSDocTypeLiteral extends JSDocType {
|
||||
kind: SyntaxKind.JSDocTypeLiteral;
|
||||
jsDocPropertyTags?: NodeArray<JSDocPropertyTag>;
|
||||
jsDocPropertyTags?: ReadonlyArray<JSDocPropertyLikeTag>;
|
||||
jsDocTypeTag?: JSDocTypeTag;
|
||||
}
|
||||
|
||||
export interface JSDocParameterTag extends JSDocTag {
|
||||
kind: SyntaxKind.JSDocParameterTag;
|
||||
/** 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 */
|
||||
name: Identifier;
|
||||
isBracketed: boolean;
|
||||
/** If true, then this type literal represents an *array* of its type. */
|
||||
isArrayType?: boolean;
|
||||
}
|
||||
|
||||
export const enum FlowFlags {
|
||||
|
||||
@@ -1547,25 +1547,29 @@ namespace ts {
|
||||
export function getJSDocParameterTags(param: ParameterDeclaration): JSDocParameterTag[] | undefined {
|
||||
if (param.name && isIdentifier(param.name)) {
|
||||
const name = param.name.escapedText;
|
||||
return getJSDocTags(param.parent).filter((tag): tag is JSDocParameterTag => isJSDocParameterTag(tag) && tag.name.escapedText === name) as JSDocParameterTag[];
|
||||
}
|
||||
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;
|
||||
return getJSDocTags(param.parent).filter((tag): tag is JSDocParameterTag => isJSDocParameterTag(tag) && isIdentifier(tag.name) && tag.name.escapedText === name) as JSDocParameterTag[];
|
||||
}
|
||||
// a binding pattern doesn't have a name, so it's not possible to match it a jsdoc parameter, which is identified by name
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** Does the opposite of `getJSDocParameterTags`: given a JSDoc parameter, finds the parameter corresponding to it. */
|
||||
export function getParameterFromJSDoc(node: JSDocParameterTag): ParameterDeclaration | undefined {
|
||||
const name = node.name.escapedText;
|
||||
const grandParent = node.parent!.parent!;
|
||||
Debug.assert(node.parent!.kind === SyntaxKind.JSDocComment);
|
||||
if (!isFunctionLike(grandParent)) {
|
||||
export function getParameterSymbolFromJSDoc(node: JSDocParameterTag): Symbol | undefined {
|
||||
if (node.symbol) {
|
||||
return node.symbol;
|
||||
}
|
||||
if (!isIdentifier(node.name)) {
|
||||
return undefined;
|
||||
}
|
||||
return find(grandParent.parameters, p =>
|
||||
const name = node.name.escapedText;
|
||||
Debug.assert(node.parent!.kind === SyntaxKind.JSDocComment);
|
||||
const func = node.parent!.parent!;
|
||||
if (!isFunctionLike(func)) {
|
||||
return undefined;
|
||||
}
|
||||
const parameter = find(func.parameters, p =>
|
||||
p.name.kind === SyntaxKind.Identifier && p.name.escapedText === name);
|
||||
return parameter && parameter.symbol;
|
||||
}
|
||||
|
||||
export function getTypeParameterFromJsDoc(node: TypeParameterDeclaration & { parent: JSDocTemplateTag }): TypeParameterDeclaration | undefined {
|
||||
@@ -4057,6 +4061,9 @@ namespace ts {
|
||||
if (!declaration) {
|
||||
return undefined;
|
||||
}
|
||||
if (isJSDocPropertyLikeTag(declaration) && declaration.name.kind === SyntaxKind.QualifiedName) {
|
||||
return declaration.name.right;
|
||||
}
|
||||
if (declaration.kind === SyntaxKind.BinaryExpression) {
|
||||
const expr = declaration as BinaryExpression;
|
||||
switch (getSpecialPropertyAssignmentKind(expr)) {
|
||||
@@ -4715,6 +4722,10 @@ namespace ts {
|
||||
return node.kind === SyntaxKind.JSDocPropertyTag;
|
||||
}
|
||||
|
||||
export function isJSDocPropertyLikeTag(node: Node): node is JSDocPropertyLikeTag {
|
||||
return node.kind === SyntaxKind.JSDocPropertyTag || node.kind === SyntaxKind.JSDocParameterTag;
|
||||
}
|
||||
|
||||
export function isJSDocTypeLiteral(node: Node): node is JSDocTypeLiteral {
|
||||
return node.kind === SyntaxKind.JSDocTypeLiteral;
|
||||
}
|
||||
|
||||
@@ -755,10 +755,10 @@ namespace ts {
|
||||
return;
|
||||
|
||||
function processJSDocParameterTag(tag: JSDocParameterTag) {
|
||||
if (tag.preParameterName) {
|
||||
pushCommentRange(pos, tag.preParameterName.pos - pos);
|
||||
pushClassification(tag.preParameterName.pos, tag.preParameterName.end - tag.preParameterName.pos, ClassificationType.parameterName);
|
||||
pos = tag.preParameterName.end;
|
||||
if (tag.isNameFirst) {
|
||||
pushCommentRange(pos, tag.name.pos - pos);
|
||||
pushClassification(tag.name.pos, tag.name.end - tag.name.pos, ClassificationType.parameterName);
|
||||
pos = tag.name.end;
|
||||
}
|
||||
|
||||
if (tag.typeExpression) {
|
||||
@@ -767,10 +767,10 @@ namespace ts {
|
||||
pos = tag.typeExpression.end;
|
||||
}
|
||||
|
||||
if (tag.postParameterName) {
|
||||
pushCommentRange(pos, tag.postParameterName.pos - pos);
|
||||
pushClassification(tag.postParameterName.pos, tag.postParameterName.end - tag.postParameterName.pos, ClassificationType.parameterName);
|
||||
pos = tag.postParameterName.end;
|
||||
if (!tag.isNameFirst) {
|
||||
pushCommentRange(pos, tag.name.pos - pos);
|
||||
pushClassification(tag.name.pos, tag.name.end - tag.name.pos, ClassificationType.parameterName);
|
||||
pos = tag.name.end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,7 +420,7 @@ namespace ts.Completions {
|
||||
if (tag.tagName.pos <= position && position <= tag.tagName.end) {
|
||||
request = { kind: "JsDocTagName" };
|
||||
}
|
||||
if (isTagWithTypeExpression(tag) && tag.typeExpression) {
|
||||
if (isTagWithTypeExpression(tag) && tag.typeExpression && tag.typeExpression.kind === SyntaxKind.JSDocTypeExpression) {
|
||||
currentToken = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
if (!currentToken ||
|
||||
(!isDeclarationName(currentToken) &&
|
||||
|
||||
@@ -120,6 +120,9 @@ namespace ts.JsDoc {
|
||||
}
|
||||
|
||||
export function getJSDocParameterNameCompletions(tag: JSDocParameterTag): CompletionEntry[] {
|
||||
if (!isIdentifier(tag.name)) {
|
||||
return emptyArray;
|
||||
}
|
||||
const nameThusFar = tag.name.text;
|
||||
const jsdoc = tag.parent;
|
||||
const fn = jsdoc.parent;
|
||||
@@ -129,7 +132,7 @@ namespace ts.JsDoc {
|
||||
if (!isIdentifier(param.name)) return undefined;
|
||||
|
||||
const name = param.name.text;
|
||||
if (jsdoc.tags.some(t => t !== tag && isJSDocParameterTag(t) && t.name.escapedText === name)
|
||||
if (jsdoc.tags.some(t => t !== tag && isJSDocParameterTag(t) && isIdentifier(t.name) && t.name.escapedText === name)
|
||||
|| nameThusFar !== undefined && !startsWith(name, nameThusFar)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -28,18 +28,13 @@
|
||||
"end": 20
|
||||
}
|
||||
},
|
||||
"postParameterName": {
|
||||
"kind": "Identifier",
|
||||
"pos": 22,
|
||||
"end": 27,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
"pos": 22,
|
||||
"end": 27,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"isNameFirst": false,
|
||||
"isBracketed": false,
|
||||
"comment": "Description"
|
||||
},
|
||||
|
||||
@@ -28,18 +28,13 @@
|
||||
"end": 25
|
||||
}
|
||||
},
|
||||
"postParameterName": {
|
||||
"kind": "Identifier",
|
||||
"pos": 27,
|
||||
"end": 32,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
"pos": 27,
|
||||
"end": 32,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"isNameFirst": false,
|
||||
"isBracketed": false,
|
||||
"comment": "Description"
|
||||
},
|
||||
|
||||
@@ -28,18 +28,13 @@
|
||||
"end": 22
|
||||
}
|
||||
},
|
||||
"postParameterName": {
|
||||
"kind": "Identifier",
|
||||
"pos": 24,
|
||||
"end": 29,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
"pos": 24,
|
||||
"end": 29,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"isNameFirst": false,
|
||||
"isBracketed": false,
|
||||
"comment": ""
|
||||
},
|
||||
|
||||
@@ -28,18 +28,13 @@
|
||||
"end": 22
|
||||
}
|
||||
},
|
||||
"postParameterName": {
|
||||
"kind": "Identifier",
|
||||
"pos": 24,
|
||||
"end": 29,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
"pos": 24,
|
||||
"end": 29,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"isNameFirst": false,
|
||||
"isBracketed": false,
|
||||
"comment": "Description text follows"
|
||||
},
|
||||
|
||||
@@ -28,18 +28,13 @@
|
||||
"end": 22
|
||||
}
|
||||
},
|
||||
"postParameterName": {
|
||||
"kind": "Identifier",
|
||||
"pos": 25,
|
||||
"end": 30,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
"pos": 25,
|
||||
"end": 30,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"isNameFirst": false,
|
||||
"isBracketed": true,
|
||||
"comment": "Description text follows"
|
||||
},
|
||||
|
||||
@@ -28,18 +28,13 @@
|
||||
"end": 22
|
||||
}
|
||||
},
|
||||
"postParameterName": {
|
||||
"kind": "Identifier",
|
||||
"pos": 26,
|
||||
"end": 31,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
"pos": 26,
|
||||
"end": 31,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"isNameFirst": false,
|
||||
"isBracketed": true,
|
||||
"comment": "Description text follows"
|
||||
},
|
||||
|
||||
@@ -18,12 +18,6 @@
|
||||
"end": 14,
|
||||
"escapedText": "param"
|
||||
},
|
||||
"preParameterName": {
|
||||
"kind": "Identifier",
|
||||
"pos": 15,
|
||||
"end": 20,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"typeExpression": {
|
||||
"kind": "JSDocTypeExpression",
|
||||
"pos": 21,
|
||||
@@ -40,6 +34,7 @@
|
||||
"end": 20,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"isNameFirst": true,
|
||||
"isBracketed": false,
|
||||
"comment": ""
|
||||
},
|
||||
|
||||
@@ -18,12 +18,6 @@
|
||||
"end": 14,
|
||||
"escapedText": "param"
|
||||
},
|
||||
"preParameterName": {
|
||||
"kind": "Identifier",
|
||||
"pos": 15,
|
||||
"end": 20,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"typeExpression": {
|
||||
"kind": "JSDocTypeExpression",
|
||||
"pos": 21,
|
||||
@@ -40,6 +34,7 @@
|
||||
"end": 20,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"isNameFirst": true,
|
||||
"isBracketed": false,
|
||||
"comment": "Description"
|
||||
},
|
||||
|
||||
@@ -18,18 +18,13 @@
|
||||
"end": 14,
|
||||
"escapedText": "param"
|
||||
},
|
||||
"preParameterName": {
|
||||
"kind": "Identifier",
|
||||
"pos": 15,
|
||||
"end": 18,
|
||||
"escapedText": "foo"
|
||||
},
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
"pos": 15,
|
||||
"end": 18,
|
||||
"escapedText": "foo"
|
||||
},
|
||||
"isNameFirst": true,
|
||||
"isBracketed": false,
|
||||
"comment": ""
|
||||
},
|
||||
|
||||
@@ -28,18 +28,13 @@
|
||||
"end": 22
|
||||
}
|
||||
},
|
||||
"postParameterName": {
|
||||
"kind": "Identifier",
|
||||
"pos": 24,
|
||||
"end": 29,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
"pos": 24,
|
||||
"end": 29,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"isNameFirst": false,
|
||||
"isBracketed": false,
|
||||
"comment": ""
|
||||
},
|
||||
@@ -68,18 +63,13 @@
|
||||
"end": 48
|
||||
}
|
||||
},
|
||||
"postParameterName": {
|
||||
"kind": "Identifier",
|
||||
"pos": 50,
|
||||
"end": 55,
|
||||
"escapedText": "name2"
|
||||
},
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
"pos": 50,
|
||||
"end": 55,
|
||||
"escapedText": "name2"
|
||||
},
|
||||
"isNameFirst": false,
|
||||
"isBracketed": false,
|
||||
"comment": ""
|
||||
},
|
||||
|
||||
@@ -28,18 +28,13 @@
|
||||
"end": 22
|
||||
}
|
||||
},
|
||||
"postParameterName": {
|
||||
"kind": "Identifier",
|
||||
"pos": 24,
|
||||
"end": 29,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
"pos": 24,
|
||||
"end": 29,
|
||||
"escapedText": "name1"
|
||||
},
|
||||
"isNameFirst": false,
|
||||
"isBracketed": false,
|
||||
"comment": ""
|
||||
},
|
||||
@@ -68,18 +63,13 @@
|
||||
"end": 44
|
||||
}
|
||||
},
|
||||
"postParameterName": {
|
||||
"kind": "Identifier",
|
||||
"pos": 46,
|
||||
"end": 51,
|
||||
"escapedText": "name2"
|
||||
},
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
"pos": 46,
|
||||
"end": 51,
|
||||
"escapedText": "name2"
|
||||
},
|
||||
"isNameFirst": false,
|
||||
"isBracketed": false,
|
||||
"comment": ""
|
||||
},
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"end": 23,
|
||||
"escapedText": "People"
|
||||
},
|
||||
"jsDocTypeLiteral": {
|
||||
"typeExpression": {
|
||||
"kind": "JSDocTypeLiteral",
|
||||
"pos": 26,
|
||||
"end": 98,
|
||||
@@ -92,18 +92,13 @@
|
||||
"end": 64
|
||||
}
|
||||
},
|
||||
"postParameterName": {
|
||||
"kind": "Identifier",
|
||||
"pos": 66,
|
||||
"end": 69,
|
||||
"escapedText": "age"
|
||||
},
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
"pos": 66,
|
||||
"end": 69,
|
||||
"escapedText": "age"
|
||||
},
|
||||
"isNameFirst": false,
|
||||
"isBracketed": false
|
||||
},
|
||||
{
|
||||
@@ -131,18 +126,13 @@
|
||||
"end": 91
|
||||
}
|
||||
},
|
||||
"postParameterName": {
|
||||
"kind": "Identifier",
|
||||
"pos": 93,
|
||||
"end": 97,
|
||||
"escapedText": "name"
|
||||
},
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
"pos": 93,
|
||||
"end": 97,
|
||||
"escapedText": "name"
|
||||
},
|
||||
"isNameFirst": false,
|
||||
"isBracketed": false
|
||||
}
|
||||
]
|
||||
|
||||
132
tests/baselines/reference/jsdocParamTagTypeLiteral.symbols
Normal file
132
tests/baselines/reference/jsdocParamTagTypeLiteral.symbols
Normal file
@@ -0,0 +1,132 @@
|
||||
=== tests/cases/conformance/jsdoc/0.js ===
|
||||
/**
|
||||
* @param {Object} notSpecial
|
||||
* @param {string} unrelated - not actually related because it's not notSpecial.unrelated
|
||||
*/
|
||||
function normal(notSpecial) {
|
||||
>normal : Symbol(normal, Decl(0.js, 0, 0))
|
||||
>notSpecial : Symbol(notSpecial, Decl(0.js, 4, 16))
|
||||
|
||||
notSpecial; // should just be 'any'
|
||||
>notSpecial : Symbol(notSpecial, Decl(0.js, 4, 16))
|
||||
}
|
||||
normal(12);
|
||||
>normal : Symbol(normal, Decl(0.js, 0, 0))
|
||||
|
||||
/**
|
||||
* @param {Object} opts1 doc1
|
||||
* @param {string} opts1.x doc2
|
||||
* @param {string=} opts1.y doc3
|
||||
* @param {string} [opts1.z] doc4
|
||||
* @param {string} [opts1.w="hi"] doc5
|
||||
*/
|
||||
function foo1(opts1) {
|
||||
>foo1 : Symbol(foo1, Decl(0.js, 7, 11))
|
||||
>opts1 : Symbol(opts1, Decl(0.js, 16, 14))
|
||||
|
||||
opts1.x;
|
||||
>opts1.x : Symbol(x, Decl(0.js, 11, 3))
|
||||
>opts1 : Symbol(opts1, Decl(0.js, 16, 14))
|
||||
>x : Symbol(x, Decl(0.js, 11, 3))
|
||||
}
|
||||
|
||||
foo1({x: 'abc'});
|
||||
>foo1 : Symbol(foo1, Decl(0.js, 7, 11))
|
||||
>x : Symbol(x, Decl(0.js, 20, 6))
|
||||
|
||||
/**
|
||||
* @param {Object[]} opts2
|
||||
* @param {string} opts2[].anotherX
|
||||
* @param {string=} opts2[].anotherY
|
||||
*/
|
||||
function foo2(/** @param opts2 bad idea theatre! */opts2) {
|
||||
>foo2 : Symbol(foo2, Decl(0.js, 20, 17))
|
||||
>opts2 : Symbol(opts2, Decl(0.js, 27, 14))
|
||||
|
||||
opts2[0].anotherX;
|
||||
>opts2[0].anotherX : Symbol(anotherX, Decl(0.js, 24, 3))
|
||||
>opts2 : Symbol(opts2, Decl(0.js, 27, 14))
|
||||
>anotherX : Symbol(anotherX, Decl(0.js, 24, 3))
|
||||
}
|
||||
|
||||
foo2([{anotherX: "world"}]);
|
||||
>foo2 : Symbol(foo2, Decl(0.js, 20, 17))
|
||||
>anotherX : Symbol(anotherX, Decl(0.js, 31, 7))
|
||||
|
||||
/**
|
||||
* @param {object} opts3
|
||||
* @param {string} opts3.x
|
||||
*/
|
||||
function foo3(opts3) {
|
||||
>foo3 : Symbol(foo3, Decl(0.js, 31, 28))
|
||||
>opts3 : Symbol(opts3, Decl(0.js, 37, 14))
|
||||
|
||||
opts3.x;
|
||||
>opts3.x : Symbol(x, Decl(0.js, 35, 3))
|
||||
>opts3 : Symbol(opts3, Decl(0.js, 37, 14))
|
||||
>x : Symbol(x, Decl(0.js, 35, 3))
|
||||
}
|
||||
foo3({x: 'abc'});
|
||||
>foo3 : Symbol(foo3, Decl(0.js, 31, 28))
|
||||
>x : Symbol(x, Decl(0.js, 40, 6))
|
||||
|
||||
/**
|
||||
* @param {object[]} opts4
|
||||
* @param {string} opts4[].x
|
||||
* @param {string=} opts4[].y
|
||||
* @param {string} [opts4[].z]
|
||||
* @param {string} [opts4[].w="hi"]
|
||||
*/
|
||||
function foo4(opts4) {
|
||||
>foo4 : Symbol(foo4, Decl(0.js, 40, 17))
|
||||
>opts4 : Symbol(opts4, Decl(0.js, 49, 14))
|
||||
|
||||
opts4[0].x;
|
||||
>opts4[0].x : Symbol(x, Decl(0.js, 44, 3))
|
||||
>opts4 : Symbol(opts4, Decl(0.js, 49, 14))
|
||||
>x : Symbol(x, Decl(0.js, 44, 3))
|
||||
}
|
||||
|
||||
foo4([{ x: 'hi' }]);
|
||||
>foo4 : Symbol(foo4, Decl(0.js, 40, 17))
|
||||
>x : Symbol(x, Decl(0.js, 53, 7))
|
||||
|
||||
/**
|
||||
* @param {object[]} opts5 - Let's test out some multiple nesting levels
|
||||
* @param {string} opts5[].help - (This one is just normal)
|
||||
* @param {object} opts5[].what - Look at us go! Here's the first nest!
|
||||
* @param {string} opts5[].what.a - (Another normal one)
|
||||
* @param {Object[]} opts5[].what.bad - Now we're nesting inside a nested type
|
||||
* @param {string} opts5[].what.bad[].idea - I don't think you can get back out of this level...
|
||||
* @param {boolean} opts5[].what.bad[].oh - Oh ... that's how you do it.
|
||||
* @param {number} opts5[].unnest - Here we are almost all the way back at the beginning.
|
||||
*/
|
||||
function foo5(opts5) {
|
||||
>foo5 : Symbol(foo5, Decl(0.js, 53, 20))
|
||||
>opts5 : Symbol(opts5, Decl(0.js, 65, 14))
|
||||
|
||||
opts5[0].what.bad[0].idea;
|
||||
>opts5[0].what.bad[0].idea : Symbol(idea, Decl(0.js, 61, 3))
|
||||
>opts5[0].what.bad : Symbol(bad, Decl(0.js, 60, 3))
|
||||
>opts5[0].what : Symbol(what, Decl(0.js, 58, 3))
|
||||
>opts5 : Symbol(opts5, Decl(0.js, 65, 14))
|
||||
>what : Symbol(what, Decl(0.js, 58, 3))
|
||||
>bad : Symbol(bad, Decl(0.js, 60, 3))
|
||||
>idea : Symbol(idea, Decl(0.js, 61, 3))
|
||||
|
||||
opts5[0].unnest;
|
||||
>opts5[0].unnest : Symbol(unnest, Decl(0.js, 63, 3))
|
||||
>opts5 : Symbol(opts5, Decl(0.js, 65, 14))
|
||||
>unnest : Symbol(unnest, Decl(0.js, 63, 3))
|
||||
}
|
||||
|
||||
foo5([{ help: "help", what: { a: 'a', bad: [{ idea: 'idea', oh: false }] }, unnest: 1 }]);
|
||||
>foo5 : Symbol(foo5, Decl(0.js, 53, 20))
|
||||
>help : Symbol(help, Decl(0.js, 70, 7))
|
||||
>what : Symbol(what, Decl(0.js, 70, 21))
|
||||
>a : Symbol(a, Decl(0.js, 70, 29))
|
||||
>bad : Symbol(bad, Decl(0.js, 70, 37))
|
||||
>idea : Symbol(idea, Decl(0.js, 70, 45))
|
||||
>oh : Symbol(oh, Decl(0.js, 70, 59))
|
||||
>unnest : Symbol(unnest, Decl(0.js, 70, 75))
|
||||
|
||||
169
tests/baselines/reference/jsdocParamTagTypeLiteral.types
Normal file
169
tests/baselines/reference/jsdocParamTagTypeLiteral.types
Normal file
@@ -0,0 +1,169 @@
|
||||
=== tests/cases/conformance/jsdoc/0.js ===
|
||||
/**
|
||||
* @param {Object} notSpecial
|
||||
* @param {string} unrelated - not actually related because it's not notSpecial.unrelated
|
||||
*/
|
||||
function normal(notSpecial) {
|
||||
>normal : (notSpecial: any) => void
|
||||
>notSpecial : any
|
||||
|
||||
notSpecial; // should just be 'any'
|
||||
>notSpecial : any
|
||||
}
|
||||
normal(12);
|
||||
>normal(12) : void
|
||||
>normal : (notSpecial: any) => void
|
||||
>12 : 12
|
||||
|
||||
/**
|
||||
* @param {Object} opts1 doc1
|
||||
* @param {string} opts1.x doc2
|
||||
* @param {string=} opts1.y doc3
|
||||
* @param {string} [opts1.z] doc4
|
||||
* @param {string} [opts1.w="hi"] doc5
|
||||
*/
|
||||
function foo1(opts1) {
|
||||
>foo1 : (opts1: { x: string; y?: string; z?: string; w?: string; }) => void
|
||||
>opts1 : { x: string; y?: string; z?: string; w?: string; }
|
||||
|
||||
opts1.x;
|
||||
>opts1.x : string
|
||||
>opts1 : { x: string; y?: string; z?: string; w?: string; }
|
||||
>x : string
|
||||
}
|
||||
|
||||
foo1({x: 'abc'});
|
||||
>foo1({x: 'abc'}) : void
|
||||
>foo1 : (opts1: { x: string; y?: string; z?: string; w?: string; }) => void
|
||||
>{x: 'abc'} : { x: string; }
|
||||
>x : string
|
||||
>'abc' : "abc"
|
||||
|
||||
/**
|
||||
* @param {Object[]} opts2
|
||||
* @param {string} opts2[].anotherX
|
||||
* @param {string=} opts2[].anotherY
|
||||
*/
|
||||
function foo2(/** @param opts2 bad idea theatre! */opts2) {
|
||||
>foo2 : (opts2: { anotherX: string; anotherY?: string; }[]) => void
|
||||
>opts2 : { anotherX: string; anotherY?: string; }[]
|
||||
|
||||
opts2[0].anotherX;
|
||||
>opts2[0].anotherX : string
|
||||
>opts2[0] : { anotherX: string; anotherY?: string; }
|
||||
>opts2 : { anotherX: string; anotherY?: string; }[]
|
||||
>0 : 0
|
||||
>anotherX : string
|
||||
}
|
||||
|
||||
foo2([{anotherX: "world"}]);
|
||||
>foo2([{anotherX: "world"}]) : void
|
||||
>foo2 : (opts2: { anotherX: string; anotherY?: string; }[]) => void
|
||||
>[{anotherX: "world"}] : { anotherX: string; }[]
|
||||
>{anotherX: "world"} : { anotherX: string; }
|
||||
>anotherX : string
|
||||
>"world" : "world"
|
||||
|
||||
/**
|
||||
* @param {object} opts3
|
||||
* @param {string} opts3.x
|
||||
*/
|
||||
function foo3(opts3) {
|
||||
>foo3 : (opts3: { x: string; }) => void
|
||||
>opts3 : { x: string; }
|
||||
|
||||
opts3.x;
|
||||
>opts3.x : string
|
||||
>opts3 : { x: string; }
|
||||
>x : string
|
||||
}
|
||||
foo3({x: 'abc'});
|
||||
>foo3({x: 'abc'}) : void
|
||||
>foo3 : (opts3: { x: string; }) => void
|
||||
>{x: 'abc'} : { x: string; }
|
||||
>x : string
|
||||
>'abc' : "abc"
|
||||
|
||||
/**
|
||||
* @param {object[]} opts4
|
||||
* @param {string} opts4[].x
|
||||
* @param {string=} opts4[].y
|
||||
* @param {string} [opts4[].z]
|
||||
* @param {string} [opts4[].w="hi"]
|
||||
*/
|
||||
function foo4(opts4) {
|
||||
>foo4 : (opts4: { x: string; y?: string; z?: string; w?: string; }[]) => void
|
||||
>opts4 : { x: string; y?: string; z?: string; w?: string; }[]
|
||||
|
||||
opts4[0].x;
|
||||
>opts4[0].x : string
|
||||
>opts4[0] : { x: string; y?: string; z?: string; w?: string; }
|
||||
>opts4 : { x: string; y?: string; z?: string; w?: string; }[]
|
||||
>0 : 0
|
||||
>x : string
|
||||
}
|
||||
|
||||
foo4([{ x: 'hi' }]);
|
||||
>foo4([{ x: 'hi' }]) : void
|
||||
>foo4 : (opts4: { x: string; y?: string; z?: string; w?: string; }[]) => void
|
||||
>[{ x: 'hi' }] : { x: string; }[]
|
||||
>{ x: 'hi' } : { x: string; }
|
||||
>x : string
|
||||
>'hi' : "hi"
|
||||
|
||||
/**
|
||||
* @param {object[]} opts5 - Let's test out some multiple nesting levels
|
||||
* @param {string} opts5[].help - (This one is just normal)
|
||||
* @param {object} opts5[].what - Look at us go! Here's the first nest!
|
||||
* @param {string} opts5[].what.a - (Another normal one)
|
||||
* @param {Object[]} opts5[].what.bad - Now we're nesting inside a nested type
|
||||
* @param {string} opts5[].what.bad[].idea - I don't think you can get back out of this level...
|
||||
* @param {boolean} opts5[].what.bad[].oh - Oh ... that's how you do it.
|
||||
* @param {number} opts5[].unnest - Here we are almost all the way back at the beginning.
|
||||
*/
|
||||
function foo5(opts5) {
|
||||
>foo5 : (opts5: { help: string; what: { a: string; bad: { idea: string; oh: boolean; }[]; }; unnest: number; }[]) => void
|
||||
>opts5 : { help: string; what: { a: string; bad: { idea: string; oh: boolean; }[]; }; unnest: number; }[]
|
||||
|
||||
opts5[0].what.bad[0].idea;
|
||||
>opts5[0].what.bad[0].idea : string
|
||||
>opts5[0].what.bad[0] : { idea: string; oh: boolean; }
|
||||
>opts5[0].what.bad : { idea: string; oh: boolean; }[]
|
||||
>opts5[0].what : { a: string; bad: { idea: string; oh: boolean; }[]; }
|
||||
>opts5[0] : { help: string; what: { a: string; bad: { idea: string; oh: boolean; }[]; }; unnest: number; }
|
||||
>opts5 : { help: string; what: { a: string; bad: { idea: string; oh: boolean; }[]; }; unnest: number; }[]
|
||||
>0 : 0
|
||||
>what : { a: string; bad: { idea: string; oh: boolean; }[]; }
|
||||
>bad : { idea: string; oh: boolean; }[]
|
||||
>0 : 0
|
||||
>idea : string
|
||||
|
||||
opts5[0].unnest;
|
||||
>opts5[0].unnest : number
|
||||
>opts5[0] : { help: string; what: { a: string; bad: { idea: string; oh: boolean; }[]; }; unnest: number; }
|
||||
>opts5 : { help: string; what: { a: string; bad: { idea: string; oh: boolean; }[]; }; unnest: number; }[]
|
||||
>0 : 0
|
||||
>unnest : number
|
||||
}
|
||||
|
||||
foo5([{ help: "help", what: { a: 'a', bad: [{ idea: 'idea', oh: false }] }, unnest: 1 }]);
|
||||
>foo5([{ help: "help", what: { a: 'a', bad: [{ idea: 'idea', oh: false }] }, unnest: 1 }]) : void
|
||||
>foo5 : (opts5: { help: string; what: { a: string; bad: { idea: string; oh: boolean; }[]; }; unnest: number; }[]) => void
|
||||
>[{ help: "help", what: { a: 'a', bad: [{ idea: 'idea', oh: false }] }, unnest: 1 }] : { help: string; what: { a: string; bad: { idea: string; oh: false; }[]; }; unnest: number; }[]
|
||||
>{ help: "help", what: { a: 'a', bad: [{ idea: 'idea', oh: false }] }, unnest: 1 } : { help: string; what: { a: string; bad: { idea: string; oh: false; }[]; }; unnest: number; }
|
||||
>help : string
|
||||
>"help" : "help"
|
||||
>what : { a: string; bad: { idea: string; oh: false; }[]; }
|
||||
>{ a: 'a', bad: [{ idea: 'idea', oh: false }] } : { a: string; bad: { idea: string; oh: false; }[]; }
|
||||
>a : string
|
||||
>'a' : "a"
|
||||
>bad : { idea: string; oh: false; }[]
|
||||
>[{ idea: 'idea', oh: false }] : { idea: string; oh: false; }[]
|
||||
>{ idea: 'idea', oh: false } : { idea: string; oh: false; }
|
||||
>idea : string
|
||||
>'idea' : "idea"
|
||||
>oh : boolean
|
||||
>false : false
|
||||
>unnest : number
|
||||
>1 : 1
|
||||
|
||||
78
tests/cases/conformance/jsdoc/jsdocParamTagTypeLiteral.ts
Normal file
78
tests/cases/conformance/jsdoc/jsdocParamTagTypeLiteral.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
// @allowJS: true
|
||||
// @checkJs: true
|
||||
// @noEmit: true
|
||||
// @strict: true
|
||||
// @suppressOutputPathCheck: true
|
||||
|
||||
// @Filename: 0.js
|
||||
/**
|
||||
* @param {Object} notSpecial
|
||||
* @param {string} unrelated - not actually related because it's not notSpecial.unrelated
|
||||
*/
|
||||
function normal(notSpecial) {
|
||||
notSpecial; // should just be 'any'
|
||||
}
|
||||
normal(12);
|
||||
|
||||
/**
|
||||
* @param {Object} opts1 doc1
|
||||
* @param {string} opts1.x doc2
|
||||
* @param {string=} opts1.y doc3
|
||||
* @param {string} [opts1.z] doc4
|
||||
* @param {string} [opts1.w="hi"] doc5
|
||||
*/
|
||||
function foo1(opts1) {
|
||||
opts1.x;
|
||||
}
|
||||
|
||||
foo1({x: 'abc'});
|
||||
|
||||
/**
|
||||
* @param {Object[]} opts2
|
||||
* @param {string} opts2[].anotherX
|
||||
* @param {string=} opts2[].anotherY
|
||||
*/
|
||||
function foo2(/** @param opts2 bad idea theatre! */opts2) {
|
||||
opts2[0].anotherX;
|
||||
}
|
||||
|
||||
foo2([{anotherX: "world"}]);
|
||||
|
||||
/**
|
||||
* @param {object} opts3
|
||||
* @param {string} opts3.x
|
||||
*/
|
||||
function foo3(opts3) {
|
||||
opts3.x;
|
||||
}
|
||||
foo3({x: 'abc'});
|
||||
|
||||
/**
|
||||
* @param {object[]} opts4
|
||||
* @param {string} opts4[].x
|
||||
* @param {string=} opts4[].y
|
||||
* @param {string} [opts4[].z]
|
||||
* @param {string} [opts4[].w="hi"]
|
||||
*/
|
||||
function foo4(opts4) {
|
||||
opts4[0].x;
|
||||
}
|
||||
|
||||
foo4([{ x: 'hi' }]);
|
||||
|
||||
/**
|
||||
* @param {object[]} opts5 - Let's test out some multiple nesting levels
|
||||
* @param {string} opts5[].help - (This one is just normal)
|
||||
* @param {object} opts5[].what - Look at us go! Here's the first nest!
|
||||
* @param {string} opts5[].what.a - (Another normal one)
|
||||
* @param {Object[]} opts5[].what.bad - Now we're nesting inside a nested type
|
||||
* @param {string} opts5[].what.bad[].idea - I don't think you can get back out of this level...
|
||||
* @param {boolean} opts5[].what.bad[].oh - Oh ... that's how you do it.
|
||||
* @param {number} opts5[].unnest - Here we are almost all the way back at the beginning.
|
||||
*/
|
||||
function foo5(opts5) {
|
||||
opts5[0].what.bad[0].idea;
|
||||
opts5[0].unnest;
|
||||
}
|
||||
|
||||
foo5([{ help: "help", what: { a: 'a', bad: [{ idea: 'idea', oh: false }] }, unnest: 1 }]);
|
||||
22
tests/cases/fourslash/findAllReferencesJsDocTypeLiteral.ts
Normal file
22
tests/cases/fourslash/findAllReferencesJsDocTypeLiteral.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: foo.js
|
||||
/////**
|
||||
//// * @param {object} o - very important!
|
||||
//// * @param {string} o.x - a thing, its ok
|
||||
//// * @param {number} o.y - another thing
|
||||
//// * @param {Object} o.nested - very nested
|
||||
//// * @param {boolean} o.nested.[|great|] - much greatness
|
||||
//// * @param {number} o.nested.times - twice? probably!??
|
||||
//// */
|
||||
//// function f(o) { return o.nested.[|great|]; }
|
||||
|
||||
verify.rangesReferenceEachOther();
|
||||
|
||||
///**
|
||||
// * @param {object} [|o|] - very important!
|
||||
// * @param {string} o.x - a thing, its ok
|
||||
// */
|
||||
// function f([|o|]) { return [|o|].x; }
|
||||
Reference in New Issue
Block a user