-
Notifications
You must be signed in to change notification settings - Fork 653
[api-extractor] Apply @module comments to module namespace objects #5449
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
base: main
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. | ||
| // See LICENSE in the project root for license information. | ||
|
|
||
| import * as ts from 'typescript'; | ||
|
|
||
| import type { Collector } from '../collector/Collector'; | ||
| import { ExtractorMessageId } from '../api/ExtractorMessageId'; | ||
|
|
||
| export class ModuleDocComment { | ||
|
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. DRY - this is essentially a copy+paste of the code+comments from PackageDocComment.ts, introducing a second full scan of the AST. And it does not conider a comment block containing both |
||
| /** | ||
| * For the given source file, see if it starts with a TSDoc comment containing the `@module` tag. | ||
| */ | ||
| public static tryFindInSourceFile( | ||
| sourceFile: ts.SourceFile, | ||
| collector: Collector | ||
| ): ts.TextRange | undefined { | ||
| // The @module comment is special because it is not attached to an AST | ||
| // definition. Instead, it is part of the "trivia" tokens that the compiler treats | ||
| // as irrelevant white space. | ||
| // | ||
| // This implementation assumes that the "@module" will be in the first TSDoc comment | ||
| // that appears in the source file. | ||
| let moduleCommentRange: ts.TextRange | undefined = undefined; | ||
| let foundFirstJSDocComment: boolean = false; | ||
|
|
||
| for (const commentRange of ts.getLeadingCommentRanges(sourceFile.text, sourceFile.getFullStart()) || []) { | ||
| if (commentRange.kind === ts.SyntaxKind.MultiLineCommentTrivia) { | ||
| const commentBody: string = sourceFile.text.substring(commentRange.pos, commentRange.end); | ||
|
|
||
| // Choose the first JSDoc-style comment | ||
| if (/^\s*\/\*\*/.test(commentBody)) { | ||
| if (!foundFirstJSDocComment) { | ||
| foundFirstJSDocComment = true; | ||
| // But only if it looks like it's trying to be @module | ||
| // (The TSDoc parser will validate this more rigorously) | ||
| if (/\@module/i.test(commentBody)) { | ||
| moduleCommentRange = commentRange; | ||
| } | ||
| } else { | ||
| // If we find another JSDoc comment with @module, report an error | ||
| if (/\@module/i.test(commentBody)) { | ||
| collector.messageRouter.addAnalyzerIssueForPosition( | ||
| ExtractorMessageId.MisplacedModuleTag, | ||
| 'The @module comment should only appear once at the top of the source file', | ||
| sourceFile, | ||
| commentRange.pos | ||
| ); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return moduleCommentRange; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,7 @@ import { AstNamespaceImport } from '../analyzer/AstNamespaceImport'; | |
| import type { IAstModuleExportInfo } from '../analyzer/AstModule'; | ||
| import { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter'; | ||
| import type { AstEntity } from '../analyzer/AstEntity'; | ||
| import { ModuleDocComment } from '../aedoc/ModuleDocComment'; | ||
|
|
||
| /** | ||
| * Used with DtsRollupGenerator.writeTypingsFile() | ||
|
|
@@ -180,6 +181,21 @@ export class DtsRollupGenerator { | |
| // signatures may reference them directly (without using the namespace qualifier). | ||
|
|
||
| writer.ensureSkippedLine(); | ||
|
|
||
| // Check if the source file has a @module comment and emit it before the namespace declaration | ||
| const sourceFile: ts.SourceFile = astEntity.astModule.sourceFile; | ||
| const moduleCommentRange: ts.TextRange | undefined = ModuleDocComment.tryFindInSourceFile( | ||
|
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. The API Extractor architecture generally does not perform this kind of analysis in the generator layer. It should happen earlier (e.g. in the collector), and the comment needs to be parsed as TSDoc, not literally copy+pasted into the output without any analysis. 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. These comments also need to be emitted into the .api.json model file. If you implement the ApiModelGenerator part, then you will realize why parsing needs to happen upstream from the generators. |
||
| sourceFile, | ||
| collector | ||
| ); | ||
| if (moduleCommentRange) { | ||
| const moduleComment: string = sourceFile.text.substring( | ||
| moduleCommentRange.pos, | ||
| moduleCommentRange.end | ||
| ); | ||
| writer.writeLine(moduleComment); | ||
| } | ||
|
|
||
| if (entity.shouldInlineExport) { | ||
| writer.write('export '); | ||
| } | ||
|
|
@@ -265,6 +281,12 @@ export class DtsRollupGenerator { | |
| span.modification.skipAll(); | ||
| } | ||
|
|
||
| // If the @module comment seems to be attached to one of the regular API items, | ||
| // omit it. It gets emitted with the namespace declaration. | ||
| if (span.node.getText().match(/(?:\s|\*)@module(?:\s|\*)/gi)) { | ||
| span.modification.skipAll(); | ||
| } | ||
|
Comment on lines
+284
to
+288
Member
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. @copilot - This should be an error case, shouldn't it? The
Contributor
Author
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. Currently, Should we report an error if a file contains |
||
|
|
||
| // For now, we don't transform JSDoc comment nodes at all | ||
| recurseChildren = false; | ||
| break; | ||
|
|
||
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.
Since
@moduleis already defined by JSDoc, we should probably make it a standard TSDoc tag rather than an AEDoc custom tag. If the JSDoc syntax is inconsistent or has different semantics, then maybe TSDoc should consider a different name like@moduleDocumentation.