Fix name resolution in typedef and allow defaults for template tags (#45483)

* Fix name resolution in typedef and allow defaults for template tags

* Inline parseBracketNameInTemplateTag

* Update baselines

* Add js declaration emit tests
This commit is contained in:
Ron Buckton
2021-09-08 17:05:07 -07:00
committed by GitHub
parent 8610ff5ebe
commit cf787e9bcf
14 changed files with 649 additions and 5 deletions

View File

@@ -3388,7 +3388,7 @@ namespace ts {
function bindTypeParameter(node: TypeParameterDeclaration) {
if (isJSDocTemplateTag(node.parent)) {
const container = find((node.parent.parent as JSDoc).tags!, isJSDocTypeAlias) || getHostSignatureFromJSDoc(node.parent); // TODO: GH#18217
const container = getEffectiveContainerForJSDocTemplateTag(node.parent);
if (container) {
if (!container.locals) {
container.locals = createSymbolTable();

View File

@@ -2052,7 +2052,9 @@ namespace ts {
lastSelfReferenceLocation = location;
}
lastLocation = location;
location = location.parent;
location = isJSDocTemplateTag(location) ?
getEffectiveContainerForJSDocTemplateTag(location) || location.parent :
location.parent;
}
// We just climbed up parents looking for the name, meaning that we started in a descendant node of `lastLocation`.
@@ -12901,7 +12903,7 @@ namespace ts {
function getParentSymbolOfTypeParameter(typeParameter: TypeParameter): Symbol | undefined {
const tp = getDeclarationOfKind<TypeParameterDeclaration>(typeParameter.symbol, SyntaxKind.TypeParameter)!;
const host = isJSDocTemplateTag(tp.parent) ? getHostSignatureFromJSDoc(tp.parent) : tp.parent;
const host = isJSDocTemplateTag(tp.parent) ? getEffectiveContainerForJSDocTemplateTag(tp.parent) : tp.parent;
return host && getSymbolOfNode(host);
}
@@ -33673,7 +33675,7 @@ namespace ts {
}
}
checkTypeParameters(node.typeParameters);
checkTypeParameters(getEffectiveTypeParameterDeclarations(node));
forEach(node.parameters, checkParameter);
@@ -35306,6 +35308,7 @@ namespace ts {
checkTypeNameIsReserved(node.name, Diagnostics.Type_alias_name_cannot_be_0);
}
checkSourceElement(node.typeExpression);
checkTypeParameters(getEffectiveTypeParameterDeclarations(node));
}
function checkJSDocTemplateTag(node: JSDocTemplateTag): void {

View File

@@ -8441,11 +8441,24 @@ namespace ts {
function parseTemplateTagTypeParameter() {
const typeParameterPos = getNodePos();
const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken);
if (isBracketed) {
skipWhitespace();
}
const name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces);
let defaultType: TypeNode | undefined;
if (isBracketed) {
skipWhitespace();
parseExpected(SyntaxKind.EqualsToken);
defaultType = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType);
parseExpected(SyntaxKind.CloseBracketToken);
}
if (nodeIsMissing(name)) {
return undefined;
}
return finishNode(factory.createTypeParameterDeclaration(name, /*constraint*/ undefined, /*defaultType*/ undefined), typeParameterPos);
return finishNode(factory.createTypeParameterDeclaration(name, /*constraint*/ undefined, defaultType), typeParameterPos);
}
function parseTemplateTagTypeParameters() {

View File

@@ -2723,6 +2723,18 @@ namespace ts {
return parameter && parameter.symbol;
}
export function getEffectiveContainerForJSDocTemplateTag(node: JSDocTemplateTag) {
if (isJSDoc(node.parent) && node.parent.tags) {
// A @template tag belongs to any @typedef, @callback, or @enum tags in the same comment block, if they exist.
const typeAlias = find(node.parent.tags, isJSDocTypeAlias);
if (typeAlias) {
return typeAlias;
}
}
// otherwise it belongs to the host it annotates
return getHostSignatureFromJSDoc(node);
}
export function getHostSignatureFromJSDoc(node: Node): SignatureDeclaration | undefined {
const host = getEffectiveJSDocHost(node);
return host && isFunctionLike(host) ? host : undefined;