-
Notifications
You must be signed in to change notification settings - Fork 13k
support @extends in jsdoc #18706
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
support @extends in jsdoc #18706
Changes from 1 commit
b21c46b
5ea3ca4
fbf8df6
0afaadb
932b1b0
5f3d6e7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -363,7 +363,8 @@ namespace ts { | |
JSDocVariadicType, | ||
JSDocComment, | ||
JSDocTag, | ||
JSDocAugmentsTag, | ||
JSDocAugmentsOrExtendsTag, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should keep |
||
JSDocExtendsTag, | ||
JSDocClassTag, | ||
JSDocParameterTag, | ||
JSDocReturnTag, | ||
|
@@ -2159,8 +2160,12 @@ namespace ts { | |
kind: SyntaxKind.JSDocTag; | ||
} | ||
|
||
export interface JSDocAugmentsTag extends JSDocTag { | ||
kind: SyntaxKind.JSDocAugmentsTag; | ||
/** | ||
* Note that `@extends` is a synonym of `@augments`. | ||
* Both are covered by this interface. | ||
*/ | ||
export interface JSDocAugmentsOrExtendsTag extends JSDocTag { | ||
kind: SyntaxKind.JSDocAugmentsOrExtendsTag; | ||
typeExpression: JSDocTypeExpression; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4072,8 +4072,8 @@ namespace ts { | |
} | ||
|
||
/** Gets the JSDoc augments tag for the node if present */ | ||
export function getJSDocAugmentsTag(node: Node): JSDocAugmentsTag | undefined { | ||
return getFirstJSDocTag(node, SyntaxKind.JSDocAugmentsTag) as JSDocAugmentsTag; | ||
export function getJSDocAugmentsOrExtendsTag(node: Node): JSDocAugmentsOrExtendsTag | undefined { | ||
return getFirstJSDocTag(node, SyntaxKind.JSDocAugmentsOrExtendsTag) as JSDocAugmentsOrExtendsTag; | ||
} | ||
|
||
/** Gets the JSDoc class tag for the node if present */ | ||
|
@@ -4765,8 +4765,8 @@ namespace ts { | |
return node.kind === SyntaxKind.JSDocComment; | ||
} | ||
|
||
export function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag { | ||
return node.kind === SyntaxKind.JSDocAugmentsTag; | ||
export function isJSDocAugmentsOrExtendsTag(node: Node): node is JSDocAugmentsOrExtendsTag { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is part of the public API now, we should not break that. |
||
return node.kind === SyntaxKind.JSDocAugmentsOrExtendsTag; | ||
} | ||
|
||
export function isJSDocParameterTag(node: Node): node is JSDocParameterTag { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,116 +1,116 @@ | ||
// @module: commonjs | ||
// @includebuiltfile: typescript_standalone.d.ts | ||
// @strict:true | ||
|
||
/* | ||
* Note: This test is a public API sample. The original sources can be found | ||
* at: https://github.com/YousefED/typescript-json-schema | ||
* https://github.com/vega/ts-json-schema-generator | ||
* Please log a "breaking change" issue for any API breaking change affecting this issue | ||
*/ | ||
|
||
declare var console: any; | ||
|
||
import * as ts from "typescript"; | ||
|
||
// excerpted from https://github.com/YousefED/typescript-json-schema | ||
// (converted from a method and modified; for example, `this: any` to compensate, among other changes) | ||
function parseCommentsIntoDefinition(this: any, | ||
symbol: ts.Symbol, | ||
definition: {description?: string, [s: string]: string | undefined}, | ||
otherAnnotations: { [s: string]: true}): void { | ||
if (!symbol) { | ||
return; | ||
} | ||
|
||
// the comments for a symbol | ||
let comments = symbol.getDocumentationComment(); | ||
|
||
if (comments.length) { | ||
definition.description = comments.map(comment => comment.kind === "lineBreak" ? comment.text : comment.text.trim().replace(/\r\n/g, "\n")).join(""); | ||
} | ||
|
||
// jsdocs are separate from comments | ||
const jsdocs = symbol.getJsDocTags(); | ||
jsdocs.forEach(doc => { | ||
// if we have @TJS-... annotations, we have to parse them | ||
const { name, text } = doc; | ||
if (this.userValidationKeywords[name]) { | ||
definition[name] = this.parseValue(text); | ||
} else { | ||
// special annotations | ||
otherAnnotations[doc.name] = true; | ||
} | ||
}); | ||
} | ||
|
||
|
||
// excerpted from https://github.com/vega/ts-json-schema-generator | ||
export interface Annotations { | ||
[name: string]: any; | ||
} | ||
function getAnnotations(this: any, node: ts.Node): Annotations | undefined { | ||
const symbol: ts.Symbol = (node as any).symbol; | ||
if (!symbol) { | ||
return undefined; | ||
} | ||
|
||
const jsDocTags: ts.JSDocTagInfo[] = symbol.getJsDocTags(); | ||
if (!jsDocTags || !jsDocTags.length) { | ||
return undefined; | ||
} | ||
|
||
const annotations: Annotations = jsDocTags.reduce((result: Annotations, jsDocTag: ts.JSDocTagInfo) => { | ||
const value = this.parseJsDocTag(jsDocTag); | ||
if (value !== undefined) { | ||
result[jsDocTag.name] = value; | ||
} | ||
|
||
return result; | ||
}, {}); | ||
return Object.keys(annotations).length ? annotations : undefined; | ||
} | ||
|
||
// these examples are artificial and mostly nonsensical | ||
function parseSpecificTags(node: ts.Node) { | ||
if (node.kind === ts.SyntaxKind.Parameter) { | ||
return ts.getJSDocParameterTags(node as ts.ParameterDeclaration); | ||
} | ||
if (node.kind === ts.SyntaxKind.FunctionDeclaration) { | ||
const func = node as ts.FunctionDeclaration; | ||
if (ts.hasJSDocParameterTags(func)) { | ||
const flat: ts.JSDocTag[] = []; | ||
for (const tags of func.parameters.map(ts.getJSDocParameterTags)) { | ||
if (tags) flat.push(...tags); | ||
} | ||
return flat; | ||
} | ||
} | ||
} | ||
|
||
function getReturnTypeFromJSDoc(node: ts.Node) { | ||
if (node.kind === ts.SyntaxKind.FunctionDeclaration) { | ||
return ts.getJSDocReturnType(node); | ||
} | ||
let type = ts.getJSDocType(node); | ||
if (type && type.kind === ts.SyntaxKind.FunctionType) { | ||
return (type as ts.FunctionTypeNode).type; | ||
} | ||
} | ||
|
||
function getAllTags(node: ts.Node) { | ||
ts.getJSDocTags(node); | ||
} | ||
|
||
function getSomeOtherTags(node: ts.Node) { | ||
const tags: (ts.JSDocTag | undefined)[] = []; | ||
tags.push(ts.getJSDocAugmentsTag(node)); | ||
tags.push(ts.getJSDocClassTag(node)); | ||
tags.push(ts.getJSDocReturnTag(node)); | ||
const type = ts.getJSDocTypeTag(node); | ||
if (type) { | ||
tags.push(type); | ||
} | ||
tags.push(ts.getJSDocTemplateTag(node)); | ||
return tags; | ||
} | ||
// @module: commonjs | ||
// @includebuiltfile: typescript_standalone.d.ts | ||
// @strict:true | ||
/* | ||
* Note: This test is a public API sample. The original sources can be found | ||
* at: https://github.com/YousefED/typescript-json-schema | ||
* https://github.com/vega/ts-json-schema-generator | ||
* Please log a "breaking change" issue for any API breaking change affecting this issue | ||
*/ | ||
declare var console: any; | ||
import * as ts from "typescript"; | ||
// excerpted from https://github.com/YousefED/typescript-json-schema | ||
// (converted from a method and modified; for example, `this: any` to compensate, among other changes) | ||
function parseCommentsIntoDefinition(this: any, | ||
symbol: ts.Symbol, | ||
definition: {description?: string, [s: string]: string | undefined}, | ||
otherAnnotations: { [s: string]: true}): void { | ||
if (!symbol) { | ||
return; | ||
} | ||
// the comments for a symbol | ||
let comments = symbol.getDocumentationComment(); | ||
if (comments.length) { | ||
definition.description = comments.map(comment => comment.kind === "lineBreak" ? comment.text : comment.text.trim().replace(/\r\n/g, "\n")).join(""); | ||
} | ||
// jsdocs are separate from comments | ||
const jsdocs = symbol.getJsDocTags(); | ||
jsdocs.forEach(doc => { | ||
// if we have @TJS-... annotations, we have to parse them | ||
const { name, text } = doc; | ||
if (this.userValidationKeywords[name]) { | ||
definition[name] = this.parseValue(text); | ||
} else { | ||
// special annotations | ||
otherAnnotations[doc.name] = true; | ||
} | ||
}); | ||
} | ||
// excerpted from https://github.com/vega/ts-json-schema-generator | ||
export interface Annotations { | ||
[name: string]: any; | ||
} | ||
function getAnnotations(this: any, node: ts.Node): Annotations | undefined { | ||
const symbol: ts.Symbol = (node as any).symbol; | ||
if (!symbol) { | ||
return undefined; | ||
} | ||
const jsDocTags: ts.JSDocTagInfo[] = symbol.getJsDocTags(); | ||
if (!jsDocTags || !jsDocTags.length) { | ||
return undefined; | ||
} | ||
const annotations: Annotations = jsDocTags.reduce((result: Annotations, jsDocTag: ts.JSDocTagInfo) => { | ||
const value = this.parseJsDocTag(jsDocTag); | ||
if (value !== undefined) { | ||
result[jsDocTag.name] = value; | ||
} | ||
return result; | ||
}, {}); | ||
return Object.keys(annotations).length ? annotations : undefined; | ||
} | ||
// these examples are artificial and mostly nonsensical | ||
function parseSpecificTags(node: ts.Node) { | ||
if (node.kind === ts.SyntaxKind.Parameter) { | ||
return ts.getJSDocParameterTags(node as ts.ParameterDeclaration); | ||
} | ||
if (node.kind === ts.SyntaxKind.FunctionDeclaration) { | ||
const func = node as ts.FunctionDeclaration; | ||
if (ts.hasJSDocParameterTags(func)) { | ||
const flat: ts.JSDocTag[] = []; | ||
for (const tags of func.parameters.map(ts.getJSDocParameterTags)) { | ||
if (tags) flat.push(...tags); | ||
} | ||
return flat; | ||
} | ||
} | ||
} | ||
function getReturnTypeFromJSDoc(node: ts.Node) { | ||
if (node.kind === ts.SyntaxKind.FunctionDeclaration) { | ||
return ts.getJSDocReturnType(node); | ||
} | ||
let type = ts.getJSDocType(node); | ||
if (type && type.kind === ts.SyntaxKind.FunctionType) { | ||
return (type as ts.FunctionTypeNode).type; | ||
} | ||
} | ||
function getAllTags(node: ts.Node) { | ||
ts.getJSDocTags(node); | ||
} | ||
function getSomeOtherTags(node: ts.Node) { | ||
const tags: (ts.JSDocTag | undefined)[] = []; | ||
tags.push(ts.getJSDocAugmentsOrExtendsTag(node)); | ||
tags.push(ts.getJSDocClassTag(node)); | ||
tags.push(ts.getJSDocReturnTag(node)); | ||
const type = ts.getJSDocTypeTag(node); | ||
if (type) { | ||
tags.push(type); | ||
} | ||
tags.push(ts.getJSDocTemplateTag(node)); | ||
return tags; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
///<reference path="fourslash.ts" /> | ||
|
||
// @allowJs: true | ||
// @Filename: dummy.js | ||
|
||
//// /** | ||
//// * @extends {Thing<string>} | ||
//// */ | ||
//// class MyStringThing extends Thing { | ||
//// constructor() { | ||
//// var x = this.mine; | ||
//// x/**/; | ||
//// } | ||
//// } | ||
|
||
// @Filename: declarations.d.ts | ||
//// declare class Thing<T> { | ||
//// mine: T; | ||
//// } | ||
|
||
goTo.marker(); | ||
verify.quickInfoIs("(local var) x: string"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like
SyntaxKind.JSDocExtendsTag
is never assigned anywhere?