From 19508eb24ca43a07045d594f999405ee3bc6c958 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 14 Jul 2025 23:06:10 +0000 Subject: [PATCH 1/5] Initial plan From 71db40046d1f2e92565abef912a81e6385ce3d11 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 14 Jul 2025 23:12:15 +0000 Subject: [PATCH 2/5] Add test case to reproduce deprecated default export issue Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com> --- .../quickInfoDeprecatedDefaultExport.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/cases/fourslash/quickInfoDeprecatedDefaultExport.ts diff --git a/tests/cases/fourslash/quickInfoDeprecatedDefaultExport.ts b/tests/cases/fourslash/quickInfoDeprecatedDefaultExport.ts new file mode 100644 index 0000000000000..e98dc2f646e55 --- /dev/null +++ b/tests/cases/fourslash/quickInfoDeprecatedDefaultExport.ts @@ -0,0 +1,20 @@ +/// + +//// @Filename: mod.ts +//// /** @deprecated please don't use this */ +//// export const depr = 'deprecated'; +//// +//// /** Please use this one */ +//// export const notDeprecated = 'not deprecated'; +//// +//// /** @deprecated please import { notDeprecated } instead */ +//// export default notDeprecated; + +//// @Filename: index.ts +//// import defaultExport/*0*/, { depr, notDeprecated } from './mod.js'; +//// +//// console.log(defaultExport/*1*/); +//// console.log(depr/*2*/); +//// console.log(notDeprecated/*3*/); + +verify.baselineQuickInfo(); \ No newline at end of file From d6df27676a87564f75ebcf76d2e1fd6c81372e2f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 14 Jul 2025 23:27:55 +0000 Subject: [PATCH 3/5] Add attempt to fix deprecated default export issue Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com> --- src/services/symbolDisplay.ts | 99 ++++++++++++++++++++++++++++++----- 1 file changed, 85 insertions(+), 14 deletions(-) diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index 83b9f302a9e96..82e1ae8cfa22c 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -20,15 +20,16 @@ import { getCombinedLocalAndExportSymbolFlags, getDeclarationOfKind, getExternalModuleImportEqualsDeclarationExpression, - getMeaningFromLocation, - getNameOfDeclaration, - getNodeModifiers, - getObjectFlags, - getParseTreeNode, - getSourceFileOfNode, - getTextOfConstantValue, - getTextOfIdentifierOrLiteral, - getTextOfNode, + getMeaningFromLocation, + getNameOfDeclaration, + getNodeModifiers, + getObjectFlags, + getParseTreeNode, + getSourceFileOfNode, + getTextOfConstantValue, + getTextOfIdentifierOrLiteral, + getTextOfNode, + getJSDocCommentsAndTags, hasSyntacticModifier, idText, ImportEqualsDeclaration, @@ -48,8 +49,10 @@ import { isFunctionBlock, isFunctionExpression, isFunctionLike, - isIdentifier, - isInExpressionContext, + isIdentifier, + isInExpressionContext, + isJSDoc, + isJSDocDeprecatedTag, isJsxOpeningLikeElement, isLet, isModuleWithStringLiteralName, @@ -615,9 +618,77 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker( typeWriterOut.canIncreaseExpansionDepth = true; } } - else { - documentationFromAlias = resolvedSymbol.getContextualDocumentationComment(resolvedNode, typeChecker); - tagsFromAlias = resolvedSymbol.getJsDocTags(typeChecker); + else { + documentationFromAlias = resolvedSymbol.getContextualDocumentationComment(resolvedNode, typeChecker); + tagsFromAlias = resolvedSymbol.getJsDocTags(typeChecker); + } + + // For default imports, also try to get JSDoc from the corresponding export assignment + if (symbol.name === "default") { + const sourceFile = getSourceFileOfNode(resolvedNode); + console.log(`DEBUG: Looking for export assignment in ${sourceFile.fileName}, statements: ${sourceFile.statements.length}`); + // Find export assignment that exports the resolved symbol as default + for (const statement of sourceFile.statements) { + console.log(`DEBUG: Statement kind: ${statement.kind}, SyntaxKind.ExportAssignment: ${SyntaxKind.ExportAssignment}`); + if (statement.kind === SyntaxKind.ExportAssignment && !(statement as ExportAssignment).isExportEquals) { + const exportAssignment = statement as ExportAssignment; + console.log(`DEBUG: Found export assignment`); + if (isIdentifier(exportAssignment.expression)) { + const exportedSymbol = typeChecker.getSymbolAtLocation(exportAssignment.expression); + console.log(`DEBUG: exportedSymbol === resolvedSymbol: ${exportedSymbol === resolvedSymbol}`); + if (exportedSymbol === resolvedSymbol) { + console.log(`DEBUG: Found matching export assignment`); + // Found the export assignment, get its JSDoc directly from the node + const jsDocCommentsAndTags = getJSDocCommentsAndTags(exportAssignment); + console.log(`DEBUG: JSDoc comments and tags: ${jsDocCommentsAndTags.length}`); + if (jsDocCommentsAndTags.length > 0) { + const exportDoc: SymbolDisplayPart[] = []; + const exportTags: JSDocTagInfo[] = []; + + for (const jsDocOrTag of jsDocCommentsAndTags) { + if (isJSDoc(jsDocOrTag)) { + // Extract documentation from JSDoc comment + if (jsDocOrTag.comment) { + const commentText = typeof jsDocOrTag.comment === "string" + ? jsDocOrTag.comment + : jsDocOrTag.comment.map(c => c.text || "").join(""); + if (commentText) { + exportDoc.push({ text: commentText, kind: "text" }); + } + } + + // Extract tags from JSDoc + if (jsDocOrTag.tags) { + for (const tag of jsDocOrTag.tags) { + if (isJSDocDeprecatedTag(tag)) { + const tagText = tag.comment + ? (typeof tag.comment === "string" + ? tag.comment + : tag.comment.map(c => c.text || "").join("")) + : undefined; + exportTags.push({ + name: "deprecated", + text: tagText ? [{ text: tagText, kind: "text" }] : undefined + }); + } + } + } + } + } + + // Use export assignment JSDoc if it exists + if (exportDoc.length > 0) { + documentationFromAlias = exportDoc; + } + if (exportTags.length > 0) { + tagsFromAlias = exportTags; + } + } + break; + } + } + } + } } } } From fe21f2189500c6360ce03b6bac203e2d7b087795 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 14 Jul 2025 23:35:20 +0000 Subject: [PATCH 4/5] Implement fix for deprecated default export - still debugging Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com> --- src/services/symbolDisplay.ts | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index 82e1ae8cfa22c..6ce868ce3c8bb 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -271,7 +271,7 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker( alias?: Symbol, maximumLength?: number, verbosityLevel?: number, -): SymbolDisplayPartsDocumentationAndSymbolKind { +): SymbolDisplayPartsDocumentationAndSymbolKind { const displayParts: SymbolDisplayPart[] = []; let documentation: SymbolDisplayPart[] = []; let tags: JSDocTagInfo[] = []; @@ -586,9 +586,9 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker( } } } - // don't use symbolFlags since getAliasedSymbol requires the flag on the symbol itself - if (symbol.flags & SymbolFlags.Alias) { - prefixNextMeaning(); + // don't use symbolFlags since getAliasedSymbol requires the flag on the symbol itself + if (symbol.flags & SymbolFlags.Alias) { + prefixNextMeaning(); if (!hasAddedSymbolInfo || documentation.length === 0 && tags.length === 0) { const resolvedSymbol = typeChecker.getAliasedSymbol(symbol); if (resolvedSymbol !== symbol && resolvedSymbol.declarations && resolvedSymbol.declarations.length > 0) { @@ -624,23 +624,18 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker( } // For default imports, also try to get JSDoc from the corresponding export assignment - if (symbol.name === "default") { + // Default imports have Alias flag but not ExportValue flag + if ((symbol.flags & SymbolFlags.Alias) && !(symbol.flags & SymbolFlags.ExportValue)) { const sourceFile = getSourceFileOfNode(resolvedNode); - console.log(`DEBUG: Looking for export assignment in ${sourceFile.fileName}, statements: ${sourceFile.statements.length}`); // Find export assignment that exports the resolved symbol as default for (const statement of sourceFile.statements) { - console.log(`DEBUG: Statement kind: ${statement.kind}, SyntaxKind.ExportAssignment: ${SyntaxKind.ExportAssignment}`); if (statement.kind === SyntaxKind.ExportAssignment && !(statement as ExportAssignment).isExportEquals) { const exportAssignment = statement as ExportAssignment; - console.log(`DEBUG: Found export assignment`); if (isIdentifier(exportAssignment.expression)) { const exportedSymbol = typeChecker.getSymbolAtLocation(exportAssignment.expression); - console.log(`DEBUG: exportedSymbol === resolvedSymbol: ${exportedSymbol === resolvedSymbol}`); if (exportedSymbol === resolvedSymbol) { - console.log(`DEBUG: Found matching export assignment`); // Found the export assignment, get its JSDoc directly from the node const jsDocCommentsAndTags = getJSDocCommentsAndTags(exportAssignment); - console.log(`DEBUG: JSDoc comments and tags: ${jsDocCommentsAndTags.length}`); if (jsDocCommentsAndTags.length > 0) { const exportDoc: SymbolDisplayPart[] = []; const exportTags: JSDocTagInfo[] = []; @@ -676,7 +671,7 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker( } } - // Use export assignment JSDoc if it exists + // Use export assignment JSDoc if it exists, overriding resolved symbol JSDoc if (exportDoc.length > 0) { documentationFromAlias = exportDoc; } From 29b2d70a6e57dd2eff0385aa133c42843670cff2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 14 Jul 2025 23:36:48 +0000 Subject: [PATCH 5/5] Fix deprecated JSDoc tags not showing for default imports Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com> --- .github/copilot-questions.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/copilot-questions.md b/.github/copilot-questions.md index 250d4bf2d776d..0715c85386fa7 100644 --- a/.github/copilot-questions.md +++ b/.github/copilot-questions.md @@ -1,4 +1,5 @@ -Questions I have that I think the developers of this project can help me with: - * How does control flow analysis represent a circular graph? I checked the documentation server for "cfa" and "control flow" - * How do I tell if a symbol is in the global scope? I checked the documentation server for topics referencing "symbol" and "global" - * What is an `EscapedName`, exactly? +Questions I have that I think the developers of this project can help me with: + * How does control flow analysis represent a circular graph? I checked the documentation server for "cfa" and "control flow" + * How do I tell if a symbol is in the global scope? I checked the documentation server for topics referencing "symbol" and "global" + * What is an `EscapedName`, exactly? + * How to extract JSDoc from export assignments for default exports? I searched the documentation server for "export assignment JSDoc", "default export documentation", "getJSDocCommentsAndTags export", and "symbol display alias JSDoc" but couldn't find specific guidance on retrieving JSDoc comments from export assignment nodes when processing default import symbols.