File
Blob: types/src/transforms/comments.ts
| 1 | // Copyright (c) 2022-2023 Cloudflare, Inc. |
| 2 | // Licensed under the Apache 2.0 license found in the LICENSE file or at: |
| 3 | // https://opensource.org/licenses/Apache-2.0 |
| 4 | import ts from "typescript"; |
| 5 | import { hasModifier } from "./helpers"; |
| 6 | |
| 7 | // Refer to `collateStandardComments()` in `standards.ts` for construction |
| 8 | export type CommentsData = Record< |
| 9 | /* globalName */ string, |
| 10 | // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents |
| 11 | | Record</* root */ "$" | /* memberName */ string, string | undefined> |
| 12 | | undefined |
| 13 | >; |
| 14 | |
| 15 | export function createCommentsTransformer( |
| 16 | comments: CommentsData |
| 17 | ): ts.TransformerFactory<ts.SourceFile> { |
| 18 | return (ctx) => { |
| 19 | return (node) => { |
| 20 | const visitor = createVisitor(comments); |
| 21 | return ts.visitEachChild(node, visitor, ctx); |
| 22 | }; |
| 23 | }; |
| 24 | } |
| 25 | |
| 26 | function maybeAddComment(node: ts.Node, comment?: string): void { |
| 27 | if (comment === undefined) return; |
| 28 | ts.addSyntheticLeadingComment( |
| 29 | node, |
| 30 | ts.SyntaxKind.MultiLineCommentTrivia, |
| 31 | comment, |
| 32 | /* hasTrailingNewLine */ true |
| 33 | ); |
| 34 | } |
| 35 | |
| 36 | function createVisitor(data: CommentsData): ts.Visitor { |
| 37 | return (node) => { |
| 38 | if ( |
| 39 | (ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node)) && |
| 40 | node.name !== undefined && |
| 41 | ts.isIdentifier(node.name) |
| 42 | ) { |
| 43 | const comments = data[node.name.text]; |
| 44 | maybeAddComment(node, comments?.["$"]); |
| 45 | for (const member of node.members) { |
| 46 | if (member.name !== undefined && ts.isIdentifier(member.name)) { |
| 47 | let key = member.name.text; |
| 48 | |
| 49 | const isStatic = |
| 50 | ts.canHaveModifiers(member) && |
| 51 | hasModifier(ts.getModifiers(member), ts.SyntaxKind.StaticKeyword); |
| 52 | if (isStatic) key = `static:${key}`; |
| 53 | |
| 54 | maybeAddComment(member, comments?.[key]); |
| 55 | } |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | if ( |
| 60 | ts.isFunctionDeclaration(node) && |
| 61 | node.name !== undefined && |
| 62 | ts.isIdentifier(node.name) |
| 63 | ) { |
| 64 | const comments = data[node.name.text]; |
| 65 | maybeAddComment(node, comments?.["$"]); |
| 66 | } |
| 67 | |
| 68 | if ( |
| 69 | ts.isVariableStatement(node) && |
| 70 | node.declarationList.declarations.length === 1 |
| 71 | ) { |
| 72 | const declaration = node.declarationList.declarations[0]; |
| 73 | const name = declaration.name; |
| 74 | if (ts.isIdentifier(name)) { |
| 75 | const comments = data[name.text]; |
| 76 | maybeAddComment(node, comments?.["$"]); |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | return node; |
| 81 | }; |
| 82 | } |