mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-10 18:04:18 -05:00
Add callback tag, with type parameters (#23947)
* Add initial tests * Add types * Half of parsing (builds but does not pass tests) * Parsing done; types are uglier; doesn't crash but doesn't pass * Bind callback tag Builds but tests still don't pass * Only bind param tags inside callback tags * Fix binding switch to only handle param tags once * Checking is 1/3 done or so. Now I'm going to go rename some members to be more uniform. I hate unnnecessary conditionals. * Rename typeExpression to type (for some jsdoc) (maybe I'll rename more later) * Rename the rest of typeExpressions Turns out there is a constraint in services such that they all need to be named the same. * Few more checker changes * Revert "Rename the rest of typeExpressions" This reverts commitf41a96b24d. * Revert "Rename typeExpression to type (for some jsdoc)" This reverts commit7d2233a00e. * Finish undoing typeExpression rename * Rename and improve getTypeParametersForAliasSymbol Plus some other small fixes * Core checking works, but is flabbergastingly messy I'm serious. * Callback return types work now * Fix crash in services * Make github diff smaller * Try to make github diff even smaller * Fix rename for callback tag * Fix nav bar for callback tag Also clean up some now-redundant code there to find the name of typedefs. * Handle ooorder callback tags Also get rid of redundant typedef name code *in the binder*. It's everywhere! * Add ooorder callback tag test * Parse comments for typedef/callback+display param comments * Always export callbacks This requires almost no new code since it is basically the same as typedefs * Update baselines * Fix support for nested namespaced callbacks And add test * Callbacks support type parameters 1. Haven't run it with all tests 2. Haven't tested typedef tags yet 3. Still allows shared symbols when on function or class declarations. * Template tags are now bound correctly * Test oorder template tags It works. * Parser cleanup * Cleanup types and utilities As much as possible, and not as much as I would like. * Handle callback more often in services * Cleanup of binder and checker * More checker cleanup * Remove TODOs and one more cleanup * Support parameter-less callback tags * Remove extra bind call on template type parameters * Bind template tag containers Doesn't quite work with typedefs, but that's because it's now stricter, without the typedef fixes. I'm going to merge with jsdoc/callback and see how it goes. * Fix fourslash failures * Stop pre-binding js type aliases Next up, stop pre-binding js type parameters * Further cleanup of delayed js type alias binding * Stop prebinding template tags too This gets rid of prebinding entirely * Remove TODO * Fix lint * Finish merge with use-jsdoc-aliases * Update callback tag baselines * Rename getTypeParametersForAliasSymbol The real fix is *probably* to rename Type.aliasTypeArguments to aliasTypeParameters, but I want to make sure and then put it in a separate PR.
This commit is contained in:
committed by
GitHub
parent
dbd4ef4910
commit
aa7e2b0f07
@@ -118,7 +118,7 @@ namespace ts {
|
||||
let thisParentContainer: Node; // Container one level up
|
||||
let blockScopeContainer: Node;
|
||||
let lastContainer: Node;
|
||||
let delayedTypedefs: { typedef: JSDocTypedefTag, container: Node, lastContainer: Node, blockScopeContainer: Node, parent: Node }[];
|
||||
let delayedTypeAliases: (JSDocTypedefTag | JSDocCallbackTag)[];
|
||||
let seenThisKeyword: boolean;
|
||||
|
||||
// state used by control flow analysis
|
||||
@@ -188,7 +188,7 @@ namespace ts {
|
||||
thisParentContainer = undefined;
|
||||
blockScopeContainer = undefined;
|
||||
lastContainer = undefined;
|
||||
delayedTypedefs = undefined;
|
||||
delayedTypeAliases = undefined;
|
||||
seenThisKeyword = false;
|
||||
currentFlow = undefined;
|
||||
currentBreakTarget = undefined;
|
||||
@@ -273,6 +273,7 @@ namespace ts {
|
||||
return InternalSymbolName.Constructor;
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.JSDocSignature:
|
||||
return InternalSymbolName.Call;
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
@@ -301,9 +302,6 @@ namespace ts {
|
||||
const functionType = <JSDocFunctionType>node.parent;
|
||||
const index = functionType.parameters.indexOf(node as ParameterDeclaration);
|
||||
return "arg" + index as __String;
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
const name = getNameOfJSDocTypedef(node as JSDocTypedefTag);
|
||||
return typeof name !== "undefined" ? name.escapedText : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,8 +454,8 @@ namespace ts {
|
||||
// during global merging in the checker. Why? The only case when ambient module is permitted inside another module is module augmentation
|
||||
// and this case is specially handled. Module augmentations should only be merged with original module definition
|
||||
// and should never be merged directly with other augmentation, and the latter case would be possible if automatic merge is allowed.
|
||||
if (node.kind === SyntaxKind.JSDocTypedefTag) Debug.assert(isInJavaScriptFile(node)); // We shouldn't add symbols for JSDoc nodes if not in a JS file.
|
||||
if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypedefTag(node)) {
|
||||
if (isJSDocTypeAlias(node)) Debug.assert(isInJavaScriptFile(node)); // We shouldn't add symbols for JSDoc nodes if not in a JS file.
|
||||
if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypeAlias(node)) {
|
||||
if (hasModifier(node, ModifierFlags.Default) && !getDeclarationName(node)) {
|
||||
return declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes); // No local symbol for an unnamed default!
|
||||
}
|
||||
@@ -628,22 +626,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
function bindChildrenWorker(node: Node): void {
|
||||
// Binding of JsDocComment should be done before the current block scope container changes.
|
||||
// because the scope of JsDocComment should not be affected by whether the current node is a
|
||||
// container or not.
|
||||
if (hasJSDocNodes(node)) {
|
||||
if (isInJavaScriptFile(node)) {
|
||||
for (const j of node.jsDoc) {
|
||||
bind(j);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const j of node.jsDoc) {
|
||||
setParentPointers(node, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checkUnreachable(node)) {
|
||||
bindEachChild(node);
|
||||
return;
|
||||
@@ -709,11 +691,9 @@ namespace ts {
|
||||
case SyntaxKind.CallExpression:
|
||||
bindCallExpressionFlow(<CallExpression>node);
|
||||
break;
|
||||
case SyntaxKind.JSDocComment:
|
||||
bindJSDocComment(<JSDoc>node);
|
||||
break;
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
bindJSDocTypedefTag(<JSDocTypedefTag>node);
|
||||
case SyntaxKind.JSDocCallbackTag:
|
||||
bindJSDocTypeAlias(node as JSDocTypedefTag | JSDocCallbackTag);
|
||||
break;
|
||||
// In source files and blocks, bind functions first to match hoisting that occurs at runtime
|
||||
case SyntaxKind.SourceFile:
|
||||
@@ -728,6 +708,7 @@ namespace ts {
|
||||
bindEachChild(node);
|
||||
break;
|
||||
}
|
||||
bindJSDoc(node);
|
||||
}
|
||||
|
||||
function isNarrowingExpression(expr: Expression): boolean {
|
||||
@@ -1379,24 +1360,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function bindJSDocComment(node: JSDoc) {
|
||||
forEachChild(node, n => {
|
||||
if (n.kind !== SyntaxKind.JSDocTypedefTag) {
|
||||
bind(n);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function bindJSDocTypedefTag(node: JSDocTypedefTag) {
|
||||
forEachChild(node, n => {
|
||||
// if the node has a fullName "A.B.C", that means symbol "C" was already bound
|
||||
// when we visit "fullName"; so when we visit the name "C" as the next child of
|
||||
// the jsDocTypedefTag, we should skip binding it.
|
||||
if (node.fullName && n === node.name && node.fullName.kind !== SyntaxKind.Identifier) {
|
||||
return;
|
||||
}
|
||||
bind(n);
|
||||
});
|
||||
function bindJSDocTypeAlias(node: JSDocTypedefTag | JSDocCallbackTag) {
|
||||
if (node.fullName) {
|
||||
setParentPointers(node, node.fullName);
|
||||
}
|
||||
}
|
||||
|
||||
function bindCallExpressionFlow(node: CallExpression) {
|
||||
@@ -1456,6 +1423,7 @@ namespace ts {
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.JSDocSignature:
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
@@ -1545,6 +1513,7 @@ namespace ts {
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.JSDocSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
@@ -1555,6 +1524,8 @@ namespace ts {
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
case SyntaxKind.JSDocCallbackTag:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.MappedType:
|
||||
// All the children of these container types are never visible through another
|
||||
@@ -1650,7 +1621,7 @@ namespace ts {
|
||||
return state;
|
||||
}
|
||||
|
||||
function bindFunctionOrConstructorType(node: SignatureDeclaration): void {
|
||||
function bindFunctionOrConstructorType(node: SignatureDeclaration | JSDocSignature): void {
|
||||
// For a given function symbol "<...>(...) => T" we want to generate a symbol identical
|
||||
// to the one we would get for: { <...>(...): T }
|
||||
//
|
||||
@@ -1752,21 +1723,34 @@ namespace ts {
|
||||
}
|
||||
|
||||
function delayedBindJSDocTypedefTag() {
|
||||
if (!delayedTypedefs) {
|
||||
if (!delayedTypeAliases) {
|
||||
return;
|
||||
}
|
||||
const saveContainer = container;
|
||||
const saveLastContainer = lastContainer;
|
||||
const saveBlockScopeContainer = blockScopeContainer;
|
||||
const saveParent = parent;
|
||||
for (const delay of delayedTypedefs) {
|
||||
({ container, lastContainer, blockScopeContainer, parent } = delay);
|
||||
bindBlockScopedDeclaration(delay.typedef, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
|
||||
const saveCurrentFlow = currentFlow;
|
||||
for (const typeAlias of delayedTypeAliases) {
|
||||
const host = getJSDocHost(typeAlias);
|
||||
container = findAncestor(host.parent, n => !!(getContainerFlags(n) & ContainerFlags.IsContainer)) || file;
|
||||
blockScopeContainer = getEnclosingBlockScopeContainer(host) || file;
|
||||
currentFlow = { flags: FlowFlags.Start };
|
||||
parent = typeAlias;
|
||||
bind(typeAlias.typeExpression);
|
||||
if (!typeAlias.fullName || typeAlias.fullName.kind === SyntaxKind.Identifier) {
|
||||
parent = typeAlias.parent;
|
||||
bindBlockScopedDeclaration(typeAlias, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
|
||||
}
|
||||
else {
|
||||
bind(typeAlias.fullName);
|
||||
}
|
||||
}
|
||||
container = saveContainer;
|
||||
lastContainer = saveLastContainer;
|
||||
blockScopeContainer = saveBlockScopeContainer;
|
||||
parent = saveParent;
|
||||
currentFlow = saveCurrentFlow;
|
||||
}
|
||||
|
||||
// The binder visits every node in the syntax tree so it is a convenient place to perform a single localized
|
||||
@@ -1946,7 +1930,6 @@ namespace ts {
|
||||
// Here the current node is "foo", which is a container, but the scope of "MyType" should
|
||||
// not be inside "foo". Therefore we always bind @typedef before bind the parent node,
|
||||
// and skip binding this tag later when binding all the other jsdoc tags.
|
||||
if (isInJavaScriptFile(node)) bindJSDocTypedefTagIfAny(node);
|
||||
|
||||
// First we bind declaration nodes to a symbol if possible. We'll both create a symbol
|
||||
// and then potentially add the symbol to an appropriate symbol table. Possible
|
||||
@@ -1978,26 +1961,21 @@ namespace ts {
|
||||
}
|
||||
else if (!skipTransformFlagAggregation && (node.transformFlags & TransformFlags.HasComputedFlags) === 0) {
|
||||
subtreeTransformFlags |= computeTransformFlagsForNode(node, 0);
|
||||
bindJSDoc(node);
|
||||
}
|
||||
inStrictMode = saveInStrictMode;
|
||||
}
|
||||
|
||||
function bindJSDocTypedefTagIfAny(node: Node) {
|
||||
if (!hasJSDocNodes(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const jsDoc of node.jsDoc) {
|
||||
if (!jsDoc.tags) {
|
||||
continue;
|
||||
function bindJSDoc(node: Node) {
|
||||
if (hasJSDocNodes(node)) {
|
||||
if (isInJavaScriptFile(node)) {
|
||||
for (const j of node.jsDoc) {
|
||||
bind(j);
|
||||
}
|
||||
}
|
||||
|
||||
for (const tag of jsDoc.tags) {
|
||||
if (tag.kind === SyntaxKind.JSDocTypedefTag) {
|
||||
const savedParent = parent;
|
||||
parent = jsDoc;
|
||||
bind(tag);
|
||||
parent = savedParent;
|
||||
else {
|
||||
for (const j of node.jsDoc) {
|
||||
setParentPointers(node, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2036,10 +2014,10 @@ namespace ts {
|
||||
// current "blockScopeContainer" needs to be set to its immediate namespace parent.
|
||||
if ((<Identifier>node).isInJSDocNamespace) {
|
||||
let parentNode = node.parent;
|
||||
while (parentNode && parentNode.kind !== SyntaxKind.JSDocTypedefTag) {
|
||||
while (parentNode && !isJSDocTypeAlias(parentNode)) {
|
||||
parentNode = parentNode.parent;
|
||||
}
|
||||
bindBlockScopedDeclaration(<Declaration>parentNode, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
|
||||
bindBlockScopedDeclaration(parentNode as Declaration, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
|
||||
break;
|
||||
}
|
||||
// falls through
|
||||
@@ -2141,8 +2119,9 @@ namespace ts {
|
||||
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes);
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
case SyntaxKind.JSDocSignature:
|
||||
case SyntaxKind.ConstructorType:
|
||||
return bindFunctionOrConstructorType(<SignatureDeclaration>node);
|
||||
return bindFunctionOrConstructorType(<SignatureDeclaration | JSDocSignature>node);
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.MappedType:
|
||||
@@ -2205,6 +2184,9 @@ namespace ts {
|
||||
return updateStrictModeStatementList((<Block | ModuleBlock>node).statements);
|
||||
|
||||
case SyntaxKind.JSDocParameterTag:
|
||||
if (node.parent.kind === SyntaxKind.JSDocSignature) {
|
||||
return bindParameter(node as JSDocParameterTag);
|
||||
}
|
||||
if (node.parent.kind !== SyntaxKind.JSDocTypeLiteral) {
|
||||
break;
|
||||
}
|
||||
@@ -2215,13 +2197,9 @@ namespace ts {
|
||||
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) {
|
||||
(delayedTypedefs || (delayedTypedefs = [])).push({ typedef: node as JSDocTypedefTag, container, lastContainer, blockScopeContainer, parent });
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
case SyntaxKind.JSDocCallbackTag:
|
||||
return (delayedTypeAliases || (delayedTypeAliases = [])).push(node as JSDocTypedefTag | JSDocCallbackTag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2622,7 +2600,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function bindParameter(node: ParameterDeclaration) {
|
||||
function bindParameter(node: ParameterDeclaration | JSDocParameterTag) {
|
||||
if (node.kind === SyntaxKind.JSDocParameterTag && container.kind !== SyntaxKind.JSDocSignature) {
|
||||
return;
|
||||
}
|
||||
if (inStrictMode && !(node.flags & NodeFlags.Ambient)) {
|
||||
// It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a
|
||||
// strict mode FunctionLikeDeclaration or FunctionExpression(13.1)
|
||||
@@ -2630,7 +2611,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (isBindingPattern(node.name)) {
|
||||
bindAnonymousDeclaration(node, SymbolFlags.FunctionScopedVariable, "__" + node.parent.parameters.indexOf(node) as __String);
|
||||
bindAnonymousDeclaration(node, SymbolFlags.FunctionScopedVariable, "__" + (node as ParameterDeclaration).parent.parameters.indexOf(node as ParameterDeclaration) as __String);
|
||||
}
|
||||
else {
|
||||
declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes);
|
||||
@@ -2690,18 +2671,24 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getInferTypeContainer(node: Node): ConditionalTypeNode {
|
||||
while (node) {
|
||||
const parent = node.parent;
|
||||
if (parent && parent.kind === SyntaxKind.ConditionalType && (<ConditionalTypeNode>parent).extendsType === node) {
|
||||
return <ConditionalTypeNode>parent;
|
||||
}
|
||||
node = parent;
|
||||
}
|
||||
return undefined;
|
||||
const extendsType = findAncestor(node, n => n.parent && isConditionalTypeNode(n.parent) && n.parent.extendsType === n);
|
||||
return extendsType && extendsType.parent as ConditionalTypeNode;
|
||||
}
|
||||
|
||||
function bindTypeParameter(node: TypeParameterDeclaration) {
|
||||
if (node.parent.kind === SyntaxKind.InferType) {
|
||||
if (isJSDocTemplateTag(node.parent)) {
|
||||
const container = find((node.parent.parent as JSDoc).tags, isJSDocTypeAlias) || getHostSignatureFromJSDoc(node.parent);
|
||||
if (container) {
|
||||
if (!container.locals) {
|
||||
container.locals = createSymbolTable();
|
||||
}
|
||||
declareSymbol(container.locals, /*parent*/ undefined, node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
|
||||
}
|
||||
else {
|
||||
declareSymbolAndAddToSymbolTable(node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
|
||||
}
|
||||
}
|
||||
else if (node.parent.kind === SyntaxKind.InferType) {
|
||||
const container = getInferTypeContainer(node.parent);
|
||||
if (container) {
|
||||
if (!container.locals) {
|
||||
@@ -3804,6 +3791,6 @@ namespace ts {
|
||||
*/
|
||||
function setParentPointers(parent: Node, child: Node): void {
|
||||
child.parent = parent;
|
||||
forEachChild(child, (childsChild) => setParentPointers(child, childsChild));
|
||||
forEachChild(child, grandchild => setParentPointers(child, grandchild));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1577,9 +1577,11 @@ namespace ts {
|
||||
|
||||
function isTypeParameterSymbolDeclaredInContainer(symbol: Symbol, container: Node) {
|
||||
for (const decl of symbol.declarations) {
|
||||
const parent = isJSDocTemplateTag(decl.parent) ? getJSDocHost(decl.parent) : decl.parent;
|
||||
if (decl.kind === SyntaxKind.TypeParameter && parent === container) {
|
||||
return true;
|
||||
if (decl.kind === SyntaxKind.TypeParameter) {
|
||||
const parent = isJSDocTemplateTag(decl.parent) ? getJSDocHost(decl.parent) : decl.parent;
|
||||
if (parent === container) {
|
||||
return !(isJSDocTemplateTag(decl.parent) && find((decl.parent.parent as JSDoc).tags, isJSDocTypeAlias));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2089,7 +2091,7 @@ namespace ts {
|
||||
let symbol: Symbol;
|
||||
if (name.kind === SyntaxKind.Identifier) {
|
||||
const message = meaning === namespaceMeaning ? Diagnostics.Cannot_find_namespace_0 : Diagnostics.Cannot_find_name_0;
|
||||
const symbolFromJSPrototype = isInJavaScriptFile(name) ? resolveEntityNameFromJSPrototype(name, meaning) : undefined;
|
||||
const symbolFromJSPrototype = isInJavaScriptFile(name) ? resolveEntityNameFromJSSpecialAssignment(name, meaning) : undefined;
|
||||
symbol = resolveName(location || name, name.escapedText, meaning, ignoreErrors || symbolFromJSPrototype ? undefined : message, name, /*isUse*/ true);
|
||||
if (!symbol) {
|
||||
return symbolFromJSPrototype;
|
||||
@@ -2144,25 +2146,34 @@ namespace ts {
|
||||
}
|
||||
|
||||
/**
|
||||
* For prototype-property methods like `A.prototype.m = function () ...`, try to resolve names in the scope of `A` too.
|
||||
* 1. For prototype-property methods like `A.prototype.m = function () ...`, try to resolve names in the scope of `A` too.
|
||||
* Note that prototype-property assignment to locations outside the current file (eg globals) doesn't work, so
|
||||
* name resolution won't work either.
|
||||
* 2. For property assignments like `{ x: function f () { } }`, try to resolve names in the scope of `f` too.
|
||||
*/
|
||||
function resolveEntityNameFromJSPrototype(name: Identifier, meaning: SymbolFlags) {
|
||||
if (isJSDocTypeReference(name.parent) && isJSDocTag(name.parent.parent.parent)) {
|
||||
const host = getJSDocHost(name.parent.parent.parent as JSDocTag);
|
||||
if (isExpressionStatement(host) &&
|
||||
isBinaryExpression(host.expression) &&
|
||||
getSpecialPropertyAssignmentKind(host.expression) === SpecialPropertyAssignmentKind.PrototypeProperty) {
|
||||
const symbol = getSymbolOfNode(host.expression.left);
|
||||
if (symbol) {
|
||||
const secondaryLocation = symbol.parent.valueDeclaration;
|
||||
return resolveName(secondaryLocation, name.escapedText, meaning, /*nameNotFoundMessage*/ undefined, name, /*isUse*/ true);
|
||||
}
|
||||
function resolveEntityNameFromJSSpecialAssignment(name: Identifier, meaning: SymbolFlags) {
|
||||
if (isJSDocTypeReference(name.parent)) {
|
||||
const host = getJSDocHost(name.parent);
|
||||
if (host) {
|
||||
const secondaryLocation = getJSSpecialAssignmentSymbol(getJSDocHost(name.parent.parent.parent as JSDocTag));
|
||||
return secondaryLocation && resolveName(secondaryLocation, name.escapedText, meaning, /*nameNotFoundMessage*/ undefined, name, /*isUse*/ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getJSSpecialAssignmentSymbol(host: HasJSDoc): Declaration | undefined {
|
||||
if (isPropertyAssignment(host) && isFunctionLike(host.initializer)) {
|
||||
const symbol = getSymbolOfNode(host.initializer);
|
||||
return symbol && symbol.valueDeclaration;
|
||||
}
|
||||
else if (isExpressionStatement(host) &&
|
||||
isBinaryExpression(host.expression) &&
|
||||
getSpecialPropertyAssignmentKind(host.expression) === SpecialPropertyAssignmentKind.PrototypeProperty) {
|
||||
const symbol = getSymbolOfNode(host.expression.left);
|
||||
return symbol && symbol.parent.valueDeclaration;
|
||||
}
|
||||
}
|
||||
|
||||
function resolveExternalModuleName(location: Node, moduleReferenceExpression: Expression): Symbol {
|
||||
return resolveExternalModuleNameWorker(location, moduleReferenceExpression, Diagnostics.Cannot_find_module_0);
|
||||
}
|
||||
@@ -3606,8 +3617,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function symbolToParameterDeclaration(parameterSymbol: Symbol, context: NodeBuilderContext, preserveModifierFlags?: boolean): ParameterDeclaration {
|
||||
const parameterDeclaration = getDeclarationOfKind<ParameterDeclaration>(parameterSymbol, SyntaxKind.Parameter);
|
||||
Debug.assert(!!parameterDeclaration || isTransientSymbol(parameterSymbol));
|
||||
let parameterDeclaration: ParameterDeclaration | JSDocParameterTag = getDeclarationOfKind<ParameterDeclaration>(parameterSymbol, SyntaxKind.Parameter);
|
||||
if (!parameterDeclaration && !isTransientSymbol(parameterSymbol)) {
|
||||
parameterDeclaration = getDeclarationOfKind<JSDocParameterTag>(parameterSymbol, SyntaxKind.JSDocParameterTag);
|
||||
}
|
||||
|
||||
let parameterType = getTypeOfSymbol(parameterSymbol);
|
||||
if (parameterDeclaration && isRequiredInitializedParameter(parameterDeclaration)) {
|
||||
@@ -3620,8 +3633,8 @@ namespace ts {
|
||||
const dotDotDotToken = isRest ? createToken(SyntaxKind.DotDotDotToken) : undefined;
|
||||
const name = parameterDeclaration
|
||||
? parameterDeclaration.name ?
|
||||
parameterDeclaration.name.kind === SyntaxKind.Identifier ?
|
||||
setEmitFlags(getSynthesizedClone(parameterDeclaration.name), EmitFlags.NoAsciiEscaping) :
|
||||
parameterDeclaration.name.kind === SyntaxKind.Identifier ? setEmitFlags(getSynthesizedClone(parameterDeclaration.name), EmitFlags.NoAsciiEscaping) :
|
||||
parameterDeclaration.name.kind === SyntaxKind.QualifiedName ? setEmitFlags(getSynthesizedClone(parameterDeclaration.name.right), EmitFlags.NoAsciiEscaping) :
|
||||
cloneBindingName(parameterDeclaration.name) :
|
||||
symbolName(parameterSymbol)
|
||||
: symbolName(parameterSymbol);
|
||||
@@ -4026,8 +4039,9 @@ namespace ts {
|
||||
|
||||
function determineIfDeclarationIsVisible() {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.JSDocCallbackTag:
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
// Top-level jsdoc typedefs are considered exported
|
||||
// Top-level jsdoc type aliases are considered exported
|
||||
// First parent is comment node, second is hosting declaration or token; we only care about those tokens or declarations whose parent is a source file
|
||||
return !!(node.parent && node.parent.parent && node.parent.parent.parent && isSourceFile(node.parent.parent.parent));
|
||||
case SyntaxKind.BindingElement:
|
||||
@@ -4802,7 +4816,7 @@ namespace ts {
|
||||
if (symbol.flags & SymbolFlags.Prototype) {
|
||||
return links.type = getTypeOfPrototypeProperty(symbol);
|
||||
}
|
||||
// CommonsJS require/module/exports all have type any.
|
||||
// CommonsJS require and module both have type any.
|
||||
if (symbol === requireSymbol || symbol === moduleSymbol) {
|
||||
return links.type = anyType;
|
||||
}
|
||||
@@ -4837,7 +4851,7 @@ namespace ts {
|
||||
declaration.kind === SyntaxKind.PropertyAccessExpression && declaration.parent.kind === SyntaxKind.BinaryExpression) {
|
||||
type = getWidenedTypeFromJSSpecialPropertyDeclarations(symbol);
|
||||
}
|
||||
else if (isJSDocPropertyTag(declaration)
|
||||
else if (isJSDocPropertyLikeTag(declaration)
|
||||
|| isPropertyAccessExpression(declaration)
|
||||
|| isIdentifier(declaration)
|
||||
|| (isMethodDeclaration(declaration) && !isObjectLiteralMethod(declaration))
|
||||
@@ -5139,6 +5153,8 @@ namespace ts {
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.JSDocTemplateTag:
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
case SyntaxKind.JSDocCallbackTag:
|
||||
case SyntaxKind.MappedType:
|
||||
case SyntaxKind.ConditionalType:
|
||||
const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes);
|
||||
@@ -5168,9 +5184,11 @@ namespace ts {
|
||||
function getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol: Symbol): TypeParameter[] {
|
||||
let result: TypeParameter[];
|
||||
for (const node of symbol.declarations) {
|
||||
if (node.kind === SyntaxKind.InterfaceDeclaration || node.kind === SyntaxKind.ClassDeclaration ||
|
||||
node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.TypeAliasDeclaration || node.kind === SyntaxKind.JSDocTypedefTag) {
|
||||
const declaration = <InterfaceDeclaration | TypeAliasDeclaration | JSDocTypedefTag>node;
|
||||
if (node.kind === SyntaxKind.InterfaceDeclaration ||
|
||||
node.kind === SyntaxKind.ClassDeclaration ||
|
||||
node.kind === SyntaxKind.ClassExpression ||
|
||||
isTypeAlias(node)) {
|
||||
const declaration = <InterfaceDeclaration | TypeAliasDeclaration | JSDocTypedefTag | JSDocCallbackTag>node;
|
||||
const typeParameters = getEffectiveTypeParameterDeclarations(declaration);
|
||||
if (typeParameters) {
|
||||
result = appendTypeParameters(result, typeParameters);
|
||||
@@ -5466,9 +5484,9 @@ namespace ts {
|
||||
return unknownType;
|
||||
}
|
||||
|
||||
const declaration = <JSDocTypedefTag | TypeAliasDeclaration>find(symbol.declarations, d =>
|
||||
d.kind === SyntaxKind.JSDocTypedefTag || d.kind === SyntaxKind.TypeAliasDeclaration);
|
||||
const typeNode = declaration.kind === SyntaxKind.JSDocTypedefTag ? declaration.typeExpression : declaration.type;
|
||||
const declaration = <JSDocTypedefTag | JSDocCallbackTag | TypeAliasDeclaration>find(symbol.declarations, d =>
|
||||
isJSDocTypeAlias(d) || d.kind === SyntaxKind.TypeAliasDeclaration);
|
||||
const typeNode = isJSDocTypeAlias(declaration) ? declaration.typeExpression : declaration.type;
|
||||
// If typeNode is missing, we will error in checkJSDocTypedefTag.
|
||||
let type = typeNode ? getTypeFromTypeNode(typeNode) : unknownType;
|
||||
|
||||
@@ -6036,7 +6054,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function createSignature(
|
||||
declaration: SignatureDeclaration,
|
||||
declaration: SignatureDeclaration | JSDocSignature,
|
||||
typeParameters: TypeParameter[],
|
||||
thisParameter: Symbol | undefined,
|
||||
parameters: Symbol[],
|
||||
@@ -7046,8 +7064,8 @@ namespace ts {
|
||||
return symbol && withAugmentations ? getMergedSymbol(symbol) : symbol;
|
||||
}
|
||||
|
||||
function isOptionalParameter(node: ParameterDeclaration) {
|
||||
if (hasQuestionToken(node) || isJSDocOptionalParameter(node)) {
|
||||
function isOptionalParameter(node: ParameterDeclaration | JSDocParameterTag) {
|
||||
if (hasQuestionToken(node) || isOptionalJSDocParameterTag(node) || isJSDocOptionalParameter(node)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -7067,6 +7085,14 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function isOptionalJSDocParameterTag(node: Node): node is JSDocParameterTag {
|
||||
if (!isJSDocParameterTag(node)) {
|
||||
return false;
|
||||
}
|
||||
const { isBracketed, typeExpression } = node;
|
||||
return isBracketed || !!typeExpression && typeExpression.type.kind === SyntaxKind.JSDocOptionalType;
|
||||
}
|
||||
|
||||
function createTypePredicateFromTypePredicateNode(node: TypePredicateNode): IdentifierTypePredicate | ThisTypePredicate {
|
||||
const { parameterName } = node;
|
||||
const type = getTypeFromTypeNode(node.type);
|
||||
@@ -7142,7 +7168,7 @@ namespace ts {
|
||||
return typeArguments;
|
||||
}
|
||||
|
||||
function getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature {
|
||||
function getSignatureFromDeclaration(declaration: SignatureDeclaration | JSDocSignature): Signature {
|
||||
const links = getNodeLinks(declaration);
|
||||
if (!links.resolvedSignature) {
|
||||
const parameters: Symbol[] = [];
|
||||
@@ -7165,6 +7191,7 @@ namespace ts {
|
||||
const param = declaration.parameters[i];
|
||||
|
||||
let paramSymbol = param.symbol;
|
||||
const type = isJSDocParameterTag(param) ? (param.typeExpression && param.typeExpression.type) : param.type;
|
||||
// Include parameter symbol instead of property symbol in the signature
|
||||
if (paramSymbol && !!(paramSymbol.flags & SymbolFlags.Property) && !isBindingPattern(param.name)) {
|
||||
const resolvedSymbol = resolveName(param, paramSymbol.escapedName, SymbolFlags.Value, undefined, undefined, /*isUse*/ false);
|
||||
@@ -7178,13 +7205,14 @@ namespace ts {
|
||||
parameters.push(paramSymbol);
|
||||
}
|
||||
|
||||
if (param.type && param.type.kind === SyntaxKind.LiteralType) {
|
||||
if (type && type.kind === SyntaxKind.LiteralType) {
|
||||
hasLiteralTypes = true;
|
||||
}
|
||||
|
||||
// Record a new minimum argument count if this is not an optional parameter
|
||||
const isOptionalParameter = param.initializer || param.questionToken || param.dotDotDotToken ||
|
||||
iife && parameters.length > iife.arguments.length && !param.type ||
|
||||
const isOptionalParameter = isOptionalJSDocParameterTag(param) ||
|
||||
param.initializer || param.questionToken || param.dotDotDotToken ||
|
||||
iife && parameters.length > iife.arguments.length && !type ||
|
||||
isUntypedSignatureInJSFile ||
|
||||
isJSDocOptionalParameter(param);
|
||||
if (!isOptionalParameter) {
|
||||
@@ -7220,8 +7248,8 @@ namespace ts {
|
||||
* OR
|
||||
* 2. It has at least one parameter, and the last parameter has a matching `@param` with a type that starts with `...`
|
||||
*/
|
||||
function maybeAddJsSyntheticRestParameter(declaration: SignatureDeclaration, parameters: Symbol[]): boolean {
|
||||
if (!containsArgumentsReference(declaration)) {
|
||||
function maybeAddJsSyntheticRestParameter(declaration: SignatureDeclaration | JSDocSignature, parameters: Symbol[]): boolean {
|
||||
if (isJSDocSignature(declaration) || !containsArgumentsReference(declaration)) {
|
||||
return false;
|
||||
}
|
||||
const lastParam = lastOrUndefined(declaration.parameters);
|
||||
@@ -7240,9 +7268,9 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
function getSignatureReturnTypeFromDeclaration(declaration: SignatureDeclaration, isJSConstructSignature: boolean, classType: Type) {
|
||||
function getSignatureReturnTypeFromDeclaration(declaration: SignatureDeclaration | JSDocSignature, isJSConstructSignature: boolean, classType: Type) {
|
||||
if (isJSConstructSignature) {
|
||||
return getTypeFromTypeNode(declaration.parameters[0].type);
|
||||
return getTypeFromTypeNode((declaration.parameters[0] as ParameterDeclaration).type);
|
||||
}
|
||||
else if (classType) {
|
||||
return classType;
|
||||
@@ -7656,11 +7684,11 @@ namespace ts {
|
||||
const missingAugmentsTag = isJs && node.parent.kind !== SyntaxKind.JSDocAugmentsTag;
|
||||
const diag = minTypeArgumentCount === typeParameters.length
|
||||
? missingAugmentsTag
|
||||
? Diagnostics.Expected_0_type_arguments_provide_these_with_an_extends_tag
|
||||
: Diagnostics.Generic_type_0_requires_1_type_argument_s
|
||||
: missingAugmentsTag
|
||||
? Diagnostics.Expected_0_1_type_arguments_provide_these_with_an_extends_tag
|
||||
: Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments;
|
||||
? Diagnostics.Expected_0_type_arguments_provide_these_with_an_extends_tag
|
||||
: Diagnostics.Generic_type_0_requires_1_type_argument_s
|
||||
: missingAugmentsTag
|
||||
? Diagnostics.Expected_0_1_type_arguments_provide_these_with_an_extends_tag
|
||||
: Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments;
|
||||
const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType);
|
||||
error(node, diag, typeStr, minTypeArgumentCount, typeParameters.length);
|
||||
if (!isJs) {
|
||||
@@ -7675,7 +7703,7 @@ namespace ts {
|
||||
return createTypeReference(<GenericType>type, typeArguments);
|
||||
}
|
||||
return checkNoTypeArguments(node, symbol) ? type : unknownType;
|
||||
}
|
||||
}
|
||||
|
||||
function getTypeAliasInstantiation(symbol: Symbol, typeArguments: Type[]): Type {
|
||||
const type = getDeclaredTypeOfSymbol(symbol);
|
||||
@@ -7702,18 +7730,18 @@ namespace ts {
|
||||
const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters);
|
||||
if (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length) {
|
||||
error(node,
|
||||
minTypeArgumentCount === typeParameters.length
|
||||
? Diagnostics.Generic_type_0_requires_1_type_argument_s
|
||||
: Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments,
|
||||
symbolToString(symbol),
|
||||
minTypeArgumentCount,
|
||||
typeParameters.length);
|
||||
minTypeArgumentCount === typeParameters.length
|
||||
? Diagnostics.Generic_type_0_requires_1_type_argument_s
|
||||
: Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments,
|
||||
symbolToString(symbol),
|
||||
minTypeArgumentCount,
|
||||
typeParameters.length);
|
||||
return unknownType;
|
||||
}
|
||||
return getTypeAliasInstantiation(symbol, typeArguments);
|
||||
}
|
||||
return checkNoTypeArguments(node, symbol) ? type : unknownType;
|
||||
}
|
||||
}
|
||||
|
||||
function getTypeReferenceName(node: TypeReferenceType): EntityNameOrEntityNameExpression | undefined {
|
||||
switch (node.kind) {
|
||||
@@ -7828,7 +7856,7 @@ namespace ts {
|
||||
|
||||
function getConstrainedTypeVariable(typeVariable: TypeVariable, node: Node) {
|
||||
let constraints: Type[];
|
||||
while (node && !isStatement(node)) {
|
||||
while (node && !isStatement(node) && node.kind !== SyntaxKind.JSDocComment) {
|
||||
const parent = node.parent;
|
||||
if (parent.kind === SyntaxKind.ConditionalType && node === (<ConditionalTypeNode>parent).trueType) {
|
||||
const constraint = getImpliedConstraint(typeVariable, (<ConditionalTypeNode>parent).checkType, (<ConditionalTypeNode>parent).extendsType);
|
||||
@@ -8396,8 +8424,9 @@ namespace ts {
|
||||
function getTypeFromUnionTypeNode(node: UnionTypeNode): Type {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
const aliasSymbol = getAliasSymbolForTypeNode(node);
|
||||
links.resolvedType = getUnionType(map(node.types, getTypeFromTypeNode), UnionReduction.Literal,
|
||||
getAliasSymbolForTypeNode(node), getAliasTypeArgumentsForTypeNode(node));
|
||||
aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol));
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
@@ -8506,8 +8535,9 @@ namespace ts {
|
||||
function getTypeFromIntersectionTypeNode(node: IntersectionTypeNode): Type {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
const aliasSymbol = getAliasSymbolForTypeNode(node);
|
||||
links.resolvedType = getIntersectionType(map(node.types, getTypeFromTypeNode),
|
||||
getAliasSymbolForTypeNode(node), getAliasTypeArgumentsForTypeNode(node));
|
||||
aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol));
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
@@ -8816,7 +8846,7 @@ namespace ts {
|
||||
const type = <MappedType>createObjectType(ObjectFlags.Mapped, node.symbol);
|
||||
type.declaration = node;
|
||||
type.aliasSymbol = getAliasSymbolForTypeNode(node);
|
||||
type.aliasTypeArguments = getAliasTypeArgumentsForTypeNode(node);
|
||||
type.aliasTypeArguments = getTypeArgumentsForAliasSymbol(type.aliasSymbol);
|
||||
links.resolvedType = type;
|
||||
// Eagerly resolve the constraint type which forces an error if the constraint type circularly
|
||||
// references itself through one or more type aliases.
|
||||
@@ -8924,7 +8954,8 @@ namespace ts {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
const checkType = getTypeFromTypeNode(node.checkType);
|
||||
const aliasTypeArguments = getAliasTypeArgumentsForTypeNode(node);
|
||||
const aliasSymbol = getAliasSymbolForTypeNode(node);
|
||||
const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol);
|
||||
const allOuterTypeParameters = getOuterTypeParameters(node, /*includeThisTypes*/ true);
|
||||
const outerTypeParameters = aliasTypeArguments ? allOuterTypeParameters : filter(allOuterTypeParameters, tp => isPossiblyReferencedInConditionalType(tp, node));
|
||||
const root: ConditionalRoot = {
|
||||
@@ -8937,7 +8968,7 @@ namespace ts {
|
||||
inferTypeParameters: getInferTypeParameters(node),
|
||||
outerTypeParameters,
|
||||
instantiations: undefined,
|
||||
aliasSymbol: getAliasSymbolForTypeNode(node),
|
||||
aliasSymbol,
|
||||
aliasTypeArguments
|
||||
};
|
||||
links.resolvedType = getConditionalType(root, /*mapper*/ undefined);
|
||||
@@ -9041,7 +9072,7 @@ namespace ts {
|
||||
else {
|
||||
let type = createObjectType(ObjectFlags.Anonymous, node.symbol);
|
||||
type.aliasSymbol = aliasSymbol;
|
||||
type.aliasTypeArguments = getAliasTypeArgumentsForTypeNode(node);
|
||||
type.aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol);
|
||||
if (isJSDocTypeLiteral(node) && node.isArrayType) {
|
||||
type = createArrayType(type);
|
||||
}
|
||||
@@ -9052,11 +9083,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getAliasSymbolForTypeNode(node: TypeNode) {
|
||||
return (node.parent.kind === SyntaxKind.TypeAliasDeclaration || node.parent.kind === SyntaxKind.JSDocTypedefTag) ? getSymbolOfNode(node.parent) : undefined;
|
||||
return isTypeAlias(node.parent) ? getSymbolOfNode(node.parent) : undefined;
|
||||
}
|
||||
|
||||
function getAliasTypeArgumentsForTypeNode(node: TypeNode) {
|
||||
const symbol = getAliasSymbolForTypeNode(node);
|
||||
function getTypeArgumentsForAliasSymbol(symbol: Symbol) {
|
||||
return symbol ? getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol) : undefined;
|
||||
}
|
||||
|
||||
@@ -9314,6 +9344,7 @@ namespace ts {
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
case SyntaxKind.JSDocSignature:
|
||||
return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node);
|
||||
case SyntaxKind.TypeOperator:
|
||||
return getTypeFromTypeOperatorNode(<TypeOperatorNode>node);
|
||||
@@ -9991,8 +10022,8 @@ namespace ts {
|
||||
function compareTypePredicateRelatedTo(
|
||||
source: TypePredicate,
|
||||
target: TypePredicate,
|
||||
sourceDeclaration: SignatureDeclaration,
|
||||
targetDeclaration: SignatureDeclaration,
|
||||
sourceDeclaration: SignatureDeclaration | JSDocSignature,
|
||||
targetDeclaration: SignatureDeclaration | JSDocSignature,
|
||||
reportErrors: boolean,
|
||||
errorReporter: ErrorReporter,
|
||||
compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary): Ternary {
|
||||
@@ -21761,8 +21792,9 @@ namespace ts {
|
||||
switch (d.kind) {
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
// A jsdoc typedef is, by definition, a type alias
|
||||
// A jsdoc typedef and callback are, by definition, type aliases
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
case SyntaxKind.JSDocCallbackTag:
|
||||
return DeclarationSpaces.ExportType;
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
return isAmbientModule(d as ModuleDeclaration) || getModuleInstanceState(d as ModuleDeclaration) !== ModuleInstanceState.NonInstantiated
|
||||
@@ -22297,7 +22329,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkJSDocTypedefTag(node: JSDocTypedefTag) {
|
||||
function checkJSDocTypeAliasTag(node: JSDocTypedefTag | JSDocCallbackTag) {
|
||||
if (!node.typeExpression) {
|
||||
// If the node had `@property` tags, `typeExpression` would have been set to the first property tag.
|
||||
error(node.name, Diagnostics.JSDoc_typedef_tag_should_either_have_a_type_annotation_or_be_followed_by_property_or_member_tags);
|
||||
@@ -25212,7 +25244,8 @@ namespace ts {
|
||||
case SyntaxKind.JSDocAugmentsTag:
|
||||
return checkJSDocAugmentsTag(node as JSDocAugmentsTag);
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
return checkJSDocTypedefTag(node as JSDocTypedefTag);
|
||||
case SyntaxKind.JSDocCallbackTag:
|
||||
return checkJSDocTypeAliasTag(node as JSDocTypedefTag);
|
||||
case SyntaxKind.JSDocParameterTag:
|
||||
return checkJSDocParameterTag(node as JSDocParameterTag);
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
@@ -26423,9 +26456,10 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function isRequiredInitializedParameter(parameter: ParameterDeclaration) {
|
||||
function isRequiredInitializedParameter(parameter: ParameterDeclaration | JSDocParameterTag) {
|
||||
return strictNullChecks &&
|
||||
!isOptionalParameter(parameter) &&
|
||||
!isJSDocParameterTag(parameter) &&
|
||||
parameter.initializer &&
|
||||
!hasModifier(parameter, ModifierFlags.ParameterPropertyModifier);
|
||||
}
|
||||
|
||||
@@ -489,6 +489,15 @@ namespace ts {
|
||||
return visitNode(cbNode, (<JSDocTypedefTag>node).fullName) ||
|
||||
visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression);
|
||||
}
|
||||
case SyntaxKind.JSDocCallbackTag:
|
||||
return visitNode(cbNode, (node as JSDocCallbackTag).fullName) ||
|
||||
visitNode(cbNode, (node as JSDocCallbackTag).typeExpression);
|
||||
case SyntaxKind.JSDocSignature:
|
||||
return visitNodes(cbNode, cbNodes, node.decorators) ||
|
||||
visitNodes(cbNode, cbNodes, node.modifiers) ||
|
||||
visitNodes(cbNode, cbNodes, (<SignatureDeclaration>node).typeParameters) ||
|
||||
visitNodes(cbNode, cbNodes, (<SignatureDeclaration>node).parameters) ||
|
||||
visitNode(cbNode, (<SignatureDeclaration>node).type);
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
if ((node as JSDocTypeLiteral).jsDocPropertyTags) {
|
||||
for (const tag of (node as JSDocTypeLiteral).jsDocPropertyTags) {
|
||||
@@ -6331,8 +6340,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
const enum PropertyLikeParse {
|
||||
Property,
|
||||
Parameter,
|
||||
Property = 1 << 0,
|
||||
Parameter = 1 << 1,
|
||||
CallbackParameter = 1 << 2,
|
||||
}
|
||||
|
||||
export function parseJSDocCommentWorker(start: number, length: number): JSDoc {
|
||||
@@ -6386,7 +6396,7 @@ namespace ts {
|
||||
case SyntaxKind.AtToken:
|
||||
if (state === JSDocState.BeginningOfLine || state === JSDocState.SawAsterisk) {
|
||||
removeTrailingNewlines(comments);
|
||||
parseTag(indent);
|
||||
addTag(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 */`
|
||||
@@ -6503,8 +6513,7 @@ namespace ts {
|
||||
case "arg":
|
||||
case "argument":
|
||||
case "param":
|
||||
addTag(parseParameterOrPropertyTag(atToken, tagName, PropertyLikeParse.Parameter, indent));
|
||||
return;
|
||||
return parseParameterOrPropertyTag(atToken, tagName, PropertyLikeParse.Parameter, indent);
|
||||
case "return":
|
||||
case "returns":
|
||||
tag = parseReturnTag(atToken, tagName);
|
||||
@@ -6516,7 +6525,10 @@ namespace ts {
|
||||
tag = parseTypeTag(atToken, tagName);
|
||||
break;
|
||||
case "typedef":
|
||||
tag = parseTypedefTag(atToken, tagName);
|
||||
tag = parseTypedefTag(atToken, tagName, indent);
|
||||
break;
|
||||
case "callback":
|
||||
tag = parseCallbackTag(atToken, tagName, indent);
|
||||
break;
|
||||
default:
|
||||
tag = parseUnknownTag(atToken, tagName);
|
||||
@@ -6531,8 +6543,11 @@ namespace ts {
|
||||
// a badly malformed tag should not be added to the list of tags
|
||||
return;
|
||||
}
|
||||
tag.comment = parseTagComments(indent + tag.end - tag.pos);
|
||||
addTag(tag);
|
||||
if (!tag.comment) {
|
||||
// some tags, like typedef and callback, have already parsed their comments earlier
|
||||
tag.comment = parseTagComments(indent + tag.end - tag.pos);
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
function parseTagComments(indent: number): string | undefined {
|
||||
@@ -6605,6 +6620,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function addTag(tag: JSDocTag): void {
|
||||
if (!tag) {
|
||||
return;
|
||||
}
|
||||
if (!tags) {
|
||||
tags = [tag];
|
||||
tagsPos = tag.pos;
|
||||
@@ -6665,9 +6683,9 @@ namespace ts {
|
||||
typeExpression = tryParseTypeExpression();
|
||||
}
|
||||
|
||||
const result = target === PropertyLikeParse.Parameter ?
|
||||
<JSDocParameterTag>createNode(SyntaxKind.JSDocParameterTag, atToken.pos) :
|
||||
<JSDocPropertyTag>createNode(SyntaxKind.JSDocPropertyTag, atToken.pos);
|
||||
const result = target === PropertyLikeParse.Property ?
|
||||
<JSDocPropertyTag>createNode(SyntaxKind.JSDocPropertyTag, atToken.pos) :
|
||||
<JSDocParameterTag>createNode(SyntaxKind.JSDocParameterTag, atToken.pos);
|
||||
let comment: string | undefined;
|
||||
if (indent !== undefined) comment = parseTagComments(indent + scanner.getStartPos() - atToken.pos);
|
||||
const nestedTypeLiteral = parseNestedTypeLiteral(typeExpression, name, target);
|
||||
@@ -6771,27 +6789,17 @@ namespace ts {
|
||||
return finishNode(tag);
|
||||
}
|
||||
|
||||
function parseTypedefTag(atToken: AtToken, tagName: Identifier): JSDocTypedefTag {
|
||||
function parseTypedefTag(atToken: AtToken, tagName: Identifier, indent: number): JSDocTypedefTag {
|
||||
const typeExpression = tryParseTypeExpression();
|
||||
skipWhitespace();
|
||||
|
||||
const typedefTag = <JSDocTypedefTag>createNode(SyntaxKind.JSDocTypedefTag, atToken.pos);
|
||||
typedefTag.atToken = atToken;
|
||||
typedefTag.tagName = tagName;
|
||||
typedefTag.fullName = parseJSDocTypeNameWithNamespace(/*flags*/ 0);
|
||||
if (typedefTag.fullName) {
|
||||
let rightNode = typedefTag.fullName;
|
||||
while (true) {
|
||||
if (rightNode.kind === SyntaxKind.Identifier || !rightNode.body) {
|
||||
// if node is identifier - use it as name
|
||||
// otherwise use name of the rightmost part that we were able to parse
|
||||
typedefTag.name = rightNode.kind === SyntaxKind.Identifier ? rightNode : rightNode.name;
|
||||
break;
|
||||
}
|
||||
rightNode = rightNode.body;
|
||||
}
|
||||
}
|
||||
typedefTag.fullName = parseJSDocTypeNameWithNamespace();
|
||||
typedefTag.name = getJSDocTypeAliasName(typedefTag.fullName);
|
||||
skipWhitespace();
|
||||
typedefTag.comment = parseTagComments(indent);
|
||||
|
||||
typedefTag.typeExpression = typeExpression;
|
||||
if (!typeExpression || isObjectOrObjectArrayTypeReference(typeExpression.type)) {
|
||||
@@ -6826,23 +6834,69 @@ namespace ts {
|
||||
}
|
||||
|
||||
return finishNode(typedefTag);
|
||||
}
|
||||
|
||||
function parseJSDocTypeNameWithNamespace(flags: NodeFlags) {
|
||||
const pos = scanner.getTokenPos();
|
||||
const typeNameOrNamespaceName = parseJSDocIdentifierName();
|
||||
function parseJSDocTypeNameWithNamespace(nested?: boolean) {
|
||||
const pos = scanner.getTokenPos();
|
||||
const typeNameOrNamespaceName = parseJSDocIdentifierName();
|
||||
|
||||
if (typeNameOrNamespaceName && parseOptional(SyntaxKind.DotToken)) {
|
||||
const jsDocNamespaceNode = <JSDocNamespaceDeclaration>createNode(SyntaxKind.ModuleDeclaration, pos);
|
||||
jsDocNamespaceNode.flags |= flags;
|
||||
jsDocNamespaceNode.name = typeNameOrNamespaceName;
|
||||
jsDocNamespaceNode.body = parseJSDocTypeNameWithNamespace(NodeFlags.NestedNamespace);
|
||||
return finishNode(jsDocNamespaceNode);
|
||||
if (typeNameOrNamespaceName && parseOptional(SyntaxKind.DotToken)) {
|
||||
const jsDocNamespaceNode = <JSDocNamespaceDeclaration>createNode(SyntaxKind.ModuleDeclaration, pos);
|
||||
if (nested) {
|
||||
jsDocNamespaceNode.flags |= NodeFlags.NestedNamespace;
|
||||
}
|
||||
jsDocNamespaceNode.name = typeNameOrNamespaceName;
|
||||
jsDocNamespaceNode.body = parseJSDocTypeNameWithNamespace(/*nested*/ true);
|
||||
return finishNode(jsDocNamespaceNode);
|
||||
}
|
||||
|
||||
if (typeNameOrNamespaceName && flags & NodeFlags.NestedNamespace) {
|
||||
typeNameOrNamespaceName.isInJSDocNamespace = true;
|
||||
if (typeNameOrNamespaceName && nested) {
|
||||
typeNameOrNamespaceName.isInJSDocNamespace = true;
|
||||
}
|
||||
return typeNameOrNamespaceName;
|
||||
}
|
||||
|
||||
function parseCallbackTag(atToken: AtToken, tagName: Identifier, indent: number): JSDocCallbackTag {
|
||||
const callbackTag = createNode(SyntaxKind.JSDocCallbackTag, atToken.pos) as JSDocCallbackTag;
|
||||
callbackTag.atToken = atToken;
|
||||
callbackTag.tagName = tagName;
|
||||
callbackTag.fullName = parseJSDocTypeNameWithNamespace();
|
||||
callbackTag.name = getJSDocTypeAliasName(callbackTag.fullName);
|
||||
skipWhitespace();
|
||||
callbackTag.comment = parseTagComments(indent);
|
||||
|
||||
let child: JSDocParameterTag | false;
|
||||
const start = scanner.getStartPos();
|
||||
const jsdocSignature = createNode(SyntaxKind.JSDocSignature, start) as JSDocSignature;
|
||||
jsdocSignature.parameters = [];
|
||||
while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter) as JSDocParameterTag)) {
|
||||
jsdocSignature.parameters = append(jsdocSignature.parameters as MutableNodeArray<JSDocParameterTag>, child);
|
||||
}
|
||||
const returnTag = tryParse(() => {
|
||||
if (token() === SyntaxKind.AtToken) {
|
||||
nextJSDocToken();
|
||||
const tag = parseTag(indent);
|
||||
if (tag && tag.kind === SyntaxKind.JSDocReturnTag) {
|
||||
return tag as JSDocReturnTag;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (returnTag) {
|
||||
jsdocSignature.type = returnTag;
|
||||
}
|
||||
callbackTag.typeExpression = finishNode(jsdocSignature);
|
||||
return finishNode(callbackTag);
|
||||
}
|
||||
|
||||
function getJSDocTypeAliasName(fullName: JSDocNamespaceBody | undefined) {
|
||||
if (fullName) {
|
||||
let rightNode = fullName;
|
||||
while (true) {
|
||||
if (ts.isIdentifier(rightNode) || !rightNode.body) {
|
||||
return ts.isIdentifier(rightNode) ? rightNode : rightNode.name;
|
||||
}
|
||||
rightNode = rightNode.body;
|
||||
}
|
||||
return typeNameOrNamespaceName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6872,6 +6926,7 @@ namespace ts {
|
||||
if (canParseTag) {
|
||||
const child = tryParseChildTag(target);
|
||||
if (child && child.kind === SyntaxKind.JSDocParameterTag &&
|
||||
target !== PropertyLikeParse.CallbackParameter &&
|
||||
(ts.isIdentifier(child.name) || !escapedTextsEqual(name, child.name.left))) {
|
||||
return false;
|
||||
}
|
||||
@@ -6920,12 +6975,12 @@ namespace ts {
|
||||
case "arg":
|
||||
case "argument":
|
||||
case "param":
|
||||
t = PropertyLikeParse.Parameter;
|
||||
t = PropertyLikeParse.Parameter | PropertyLikeParse.CallbackParameter;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (target !== t) {
|
||||
if (!(target & t)) {
|
||||
return false;
|
||||
}
|
||||
const tag = parseParameterOrPropertyTag(atToken, tagName, target, /*indent*/ undefined);
|
||||
|
||||
@@ -413,9 +413,11 @@ namespace ts {
|
||||
JSDocVariadicType,
|
||||
JSDocComment,
|
||||
JSDocTypeLiteral,
|
||||
JSDocSignature,
|
||||
JSDocTag,
|
||||
JSDocAugmentsTag,
|
||||
JSDocClassTag,
|
||||
JSDocCallbackTag,
|
||||
JSDocParameterTag,
|
||||
JSDocReturnTag,
|
||||
JSDocTypeTag,
|
||||
@@ -2053,7 +2055,7 @@ namespace ts {
|
||||
|
||||
export type ObjectTypeDeclaration = ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode;
|
||||
|
||||
export type DeclarationWithTypeParameters = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag;
|
||||
export type DeclarationWithTypeParameters = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag | JSDocTypedefTag | JSDocCallbackTag | JSDocSignature;
|
||||
|
||||
export interface ClassLikeDeclarationBase extends NamedDeclaration, JSDocContainer {
|
||||
kind: SyntaxKind.ClassDeclaration | SyntaxKind.ClassExpression;
|
||||
@@ -2387,6 +2389,21 @@ namespace ts {
|
||||
typeExpression?: JSDocTypeExpression | JSDocTypeLiteral;
|
||||
}
|
||||
|
||||
export interface JSDocCallbackTag extends JSDocTag, NamedDeclaration {
|
||||
parent: JSDoc;
|
||||
kind: SyntaxKind.JSDocCallbackTag;
|
||||
fullName?: JSDocNamespaceDeclaration | Identifier;
|
||||
name?: Identifier;
|
||||
typeExpression: JSDocSignature;
|
||||
}
|
||||
|
||||
export interface JSDocSignature extends JSDocType, Declaration {
|
||||
kind: SyntaxKind.JSDocSignature;
|
||||
typeParameters?: ReadonlyArray<JSDocTemplateTag>;
|
||||
parameters: ReadonlyArray<JSDocParameterTag>;
|
||||
type: JSDocReturnTag | undefined;
|
||||
}
|
||||
|
||||
export interface JSDocPropertyLikeTag extends JSDocTag, Declaration {
|
||||
parent: JSDoc;
|
||||
name: EntityName;
|
||||
@@ -4032,7 +4049,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export interface Signature {
|
||||
declaration?: SignatureDeclaration; // Originating declaration
|
||||
declaration?: SignatureDeclaration | JSDocSignature; // Originating declaration
|
||||
typeParameters?: TypeParameter[]; // Type parameters (undefined if non-generic)
|
||||
parameters: Symbol[]; // Parameters
|
||||
/* @internal */
|
||||
|
||||
@@ -520,6 +520,9 @@ namespace ts {
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.JSDocCallbackTag:
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
case SyntaxKind.JSDocSignature:
|
||||
return true;
|
||||
default:
|
||||
assertTypeIsNever(node);
|
||||
@@ -561,14 +564,7 @@ namespace ts {
|
||||
// Gets the nearest enclosing block scope container that has the provided node
|
||||
// as a descendant, that is not the provided node.
|
||||
export function getEnclosingBlockScopeContainer(node: Node): Node {
|
||||
let current = node.parent;
|
||||
while (current) {
|
||||
if (isBlockScope(current, current.parent)) {
|
||||
return current;
|
||||
}
|
||||
|
||||
current = current.parent;
|
||||
}
|
||||
return findAncestor(node.parent, current => isBlockScope(current, current.parent));
|
||||
}
|
||||
|
||||
// Return display name of an identifier
|
||||
@@ -1803,6 +1799,14 @@ namespace ts {
|
||||
((node as JSDocFunctionType).parameters[0].name as Identifier).escapedText === "new";
|
||||
}
|
||||
|
||||
export function isJSDocTypeAlias(node: Node): node is JSDocTypedefTag | JSDocCallbackTag {
|
||||
return node.kind === SyntaxKind.JSDocTypedefTag || node.kind === SyntaxKind.JSDocCallbackTag;
|
||||
}
|
||||
|
||||
export function isTypeAlias(node: Node): node is JSDocTypedefTag | JSDocCallbackTag | TypeAliasDeclaration {
|
||||
return isJSDocTypeAlias(node) || isTypeAliasDeclaration(node);
|
||||
}
|
||||
|
||||
function getSourceOfAssignment(node: Node): Node {
|
||||
return isExpressionStatement(node) &&
|
||||
node.expression && isBinaryExpression(node.expression) &&
|
||||
@@ -1826,6 +1830,8 @@ namespace ts {
|
||||
return v && v.initializer;
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
return (node as PropertyDeclaration).initializer;
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
return (node as PropertyAssignment).initializer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1907,7 +1913,7 @@ namespace ts {
|
||||
return parameter && parameter.symbol;
|
||||
}
|
||||
|
||||
export function getHostSignatureFromJSDoc(node: JSDocParameterTag): SignatureDeclaration | undefined {
|
||||
export function getHostSignatureFromJSDoc(node: JSDocTag): SignatureDeclaration | undefined {
|
||||
const host = getJSDocHost(node);
|
||||
const decl = getSourceOfDefaultedAssignment(host) ||
|
||||
getSourceOfAssignment(host) ||
|
||||
@@ -1918,18 +1924,12 @@ namespace ts {
|
||||
return decl && isFunctionLike(decl) ? decl : undefined;
|
||||
}
|
||||
|
||||
export function getJSDocHost(node: JSDocTag): HasJSDoc {
|
||||
while (node.parent.kind === SyntaxKind.JSDocTypeLiteral) {
|
||||
if (node.parent.parent.kind === SyntaxKind.JSDocTypedefTag) {
|
||||
node = node.parent.parent as JSDocTypedefTag;
|
||||
}
|
||||
else {
|
||||
// node.parent.parent is a type expression, child of a parameter type
|
||||
node = node.parent.parent.parent as JSDocParameterTag;
|
||||
}
|
||||
export function getJSDocHost(node: Node): HasJSDoc {
|
||||
const comment = findAncestor(node.parent,
|
||||
node => !(isJSDocNode(node) || node.flags & NodeFlags.JSDoc) ? "quit" : node.kind === SyntaxKind.JSDocComment);
|
||||
if (comment) {
|
||||
return (comment as JSDoc).parent;
|
||||
}
|
||||
Debug.assert(node.parent!.kind === SyntaxKind.JSDocComment);
|
||||
return node.parent!.parent!;
|
||||
}
|
||||
|
||||
export function getTypeParameterFromJsDoc(node: TypeParameterDeclaration & { parent: JSDocTemplateTag }): TypeParameterDeclaration | undefined {
|
||||
@@ -1938,13 +1938,14 @@ namespace ts {
|
||||
return find(typeParameters, p => p.name.escapedText === name);
|
||||
}
|
||||
|
||||
export function hasRestParameter(s: SignatureDeclaration): boolean {
|
||||
const last = lastOrUndefined(s.parameters);
|
||||
export function hasRestParameter(s: SignatureDeclaration | JSDocSignature): boolean {
|
||||
const last = lastOrUndefined<ParameterDeclaration | JSDocParameterTag>(s.parameters);
|
||||
return last && isRestParameter(last);
|
||||
}
|
||||
|
||||
export function isRestParameter(node: ParameterDeclaration): boolean {
|
||||
return node.dotDotDotToken !== undefined || node.type && node.type.kind === SyntaxKind.JSDocVariadicType;
|
||||
export function isRestParameter(node: ParameterDeclaration | JSDocParameterTag): boolean {
|
||||
const type = isJSDocParameterTag(node) ? (node.typeExpression && node.typeExpression.type) : node.type;
|
||||
return (node as ParameterDeclaration).dotDotDotToken !== undefined || type && type.kind === SyntaxKind.JSDocVariadicType;
|
||||
}
|
||||
|
||||
export const enum AssignmentKind {
|
||||
@@ -2998,8 +2999,9 @@ namespace ts {
|
||||
return parameter && parameter.type;
|
||||
}
|
||||
|
||||
export function getThisParameter(signature: SignatureDeclaration): ParameterDeclaration | undefined {
|
||||
if (signature.parameters.length) {
|
||||
export function getThisParameter(signature: SignatureDeclaration | JSDocSignature): ParameterDeclaration | undefined {
|
||||
// callback tags do not currently support this parameters
|
||||
if (signature.parameters.length && !isJSDocSignature(signature)) {
|
||||
const thisParameter = signature.parameters[0];
|
||||
if (parameterIsThisKeyword(thisParameter)) {
|
||||
return thisParameter;
|
||||
@@ -3085,7 +3087,10 @@ namespace ts {
|
||||
* Gets the effective return type annotation of a signature. If the node was parsed in a
|
||||
* JavaScript file, gets the return type annotation from JSDoc.
|
||||
*/
|
||||
export function getEffectiveReturnTypeNode(node: SignatureDeclaration): TypeNode | undefined {
|
||||
export function getEffectiveReturnTypeNode(node: SignatureDeclaration | JSDocSignature): TypeNode | undefined {
|
||||
if (isJSDocSignature(node)) {
|
||||
return node.type && node.type.typeExpression && node.type.typeExpression.type;
|
||||
}
|
||||
return node.type || (isInJavaScriptFile(node) ? getJSDocReturnType(node) : undefined);
|
||||
}
|
||||
|
||||
@@ -3093,15 +3098,30 @@ namespace ts {
|
||||
* Gets the effective type parameters. If the node was parsed in a
|
||||
* JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
|
||||
*/
|
||||
export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters | JSDocTypedefTag) {
|
||||
return isJSDocTypedefTag(node)
|
||||
? getJSDocTypeParameterDeclarations(node)
|
||||
: node.typeParameters || (isInJavaScriptFile(node) ? getJSDocTypeParameterDeclarations(node) : undefined);
|
||||
export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters) {
|
||||
if (isJSDocSignature(node)) {
|
||||
return undefined;
|
||||
}
|
||||
if (isJSDocTypeAlias(node)) {
|
||||
Debug.assert(node.parent.kind === SyntaxKind.JSDocComment);
|
||||
const templateTags = flatMap(filter(node.parent.tags, isJSDocTemplateTag), tag => tag.typeParameters) as ReadonlyArray<TypeParameterDeclaration>;
|
||||
const templateTagNodes = templateTags as NodeArray<TypeParameterDeclaration>;
|
||||
templateTagNodes.pos = templateTagNodes.length > 0 ? first(templateTagNodes).pos : node.pos;
|
||||
templateTagNodes.end = templateTagNodes.length > 0 ? last(templateTagNodes).end : node.end;
|
||||
templateTagNodes.hasTrailingComma = false;
|
||||
return templateTagNodes;
|
||||
}
|
||||
return node.typeParameters || (isInJavaScriptFile(node) ? getJSDocTypeParameterDeclarations(node) : undefined);
|
||||
}
|
||||
|
||||
export function getJSDocTypeParameterDeclarations(node: DeclarationWithTypeParameters | JSDocTypedefTag) {
|
||||
const templateTag = getJSDocTemplateTag(node);
|
||||
return templateTag && templateTag.typeParameters;
|
||||
export function getJSDocTypeParameterDeclarations(node: DeclarationWithTypeParameters) {
|
||||
const tags = filter(getJSDocTags(node), isJSDocTemplateTag);
|
||||
for (const tag of tags) {
|
||||
if (!(tag.parent.kind === SyntaxKind.JSDocComment && find(tag.parent.tags, isJSDocTypeAlias))) {
|
||||
// template tags are only available when a typedef isn't already using them
|
||||
return tag.typeParameters;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4638,6 +4658,8 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
case SyntaxKind.JSDocCallbackTag:
|
||||
return (declaration as JSDocCallbackTag).name;
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
return getNameOfJSDocTypedef(declaration as JSDocTypedefTag);
|
||||
case SyntaxKind.ExportAssignment: {
|
||||
@@ -5475,6 +5497,14 @@ namespace ts {
|
||||
export function isJSDocTypeLiteral(node: Node): node is JSDocTypeLiteral {
|
||||
return node.kind === SyntaxKind.JSDocTypeLiteral;
|
||||
}
|
||||
|
||||
export function isJSDocCallbackTag(node: Node): node is JSDocCallbackTag {
|
||||
return node.kind === SyntaxKind.JSDocCallbackTag;
|
||||
}
|
||||
|
||||
export function isJSDocSignature(node: Node): node is JSDocSignature {
|
||||
return node.kind === SyntaxKind.JSDocSignature;
|
||||
}
|
||||
}
|
||||
|
||||
// Node tests
|
||||
@@ -5636,6 +5666,7 @@ namespace ts {
|
||||
switch (kind) {
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.JSDocSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
case SyntaxKind.FunctionType:
|
||||
@@ -6104,6 +6135,7 @@ namespace ts {
|
||||
|| kind === SyntaxKind.TypeParameter
|
||||
|| kind === SyntaxKind.VariableDeclaration
|
||||
|| kind === SyntaxKind.JSDocTypedefTag
|
||||
|| kind === SyntaxKind.JSDocCallbackTag
|
||||
|| kind === SyntaxKind.JSDocPropertyTag;
|
||||
}
|
||||
|
||||
@@ -6254,7 +6286,7 @@ namespace ts {
|
||||
|
||||
/** True if node is of a kind that may contain comment text. */
|
||||
export function isJSDocCommentContainingNode(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.JSDocComment || isJSDocTag(node) || isJSDocTypeLiteral(node);
|
||||
return node.kind === SyntaxKind.JSDocComment || isJSDocTag(node) || isJSDocTypeLiteral(node) || isJSDocSignature(node);
|
||||
}
|
||||
|
||||
// TODO: determine what this does before making it public.
|
||||
|
||||
Reference in New Issue
Block a user