Skip to content
Source
Sign inSign up

jsdoc.ts

65 lines2.3 KB

1import type { TSTypeKind } from "ast-types/gen/kinds"
2import type * as cs from "jscodeshift"
3​
4//
5// this is needed to resolve a bug in jscodeshift that
6// forgets to traverse type parameters in call expressions
7//
8declare module "ast-types/gen/namedTypes.js" {
9 namespace namedTypes {
10 interface CallExpression extends TSHasOptionalTypeParameterInstantiation {}
11 }
13​
14export default function transformer(file: cs.FileInfo, api: cs.API) {
15 const j = api.jscodeshift
16​
17 const root = j(file.source)
18​
19 root.find(j.ExportNamedDeclaration).forEach((path) => {
20 const declaration = path.node.declaration
21 if (!j.VariableDeclaration.check(declaration)) return
22​
23 const comments = path.node.comments ?? []
24 declaration.declarations.forEach((declarator) => {
25 if (!j.VariableDeclarator.check(declarator) || !j.Identifier.check(declarator.id)) return
26​
27 const annotation = declarator.id.typeAnnotation
28 if (annotation) {
29 // An explicit annotation is the public type; leave the initializer alone.
30 if (!j.TSTypeAnnotation.check(annotation) || !j.TSTypeLiteral.check(annotation.typeAnnotation)) return
31 annotation.typeAnnotation.members.forEach((member) => {
32 if (!j.TSCallSignatureDeclaration.check(member) || hasComments(member)) return
33 member.comments = comments
34 })
35 return
36 }
37​
38 const init = declarator.init
39 if (!j.CallExpression.check(init)) return
40 const callee = init.callee
41 const isDual = j.Identifier.check(callee) && callee.name === "dual"
42 || j.MemberExpression.check(callee) && !callee.computed
43 && j.Identifier.check(callee.object) && callee.object.name === "Dual"
44 && j.Identifier.check(callee.property) && callee.property.name === "dual"
45 if (!isDual) return
46​
47 // Only the dual call's own type arguments describe the public overloads.
48 init.typeParameters?.params.forEach((param) => {
49 // Don't override comments if they already exist
50 if (hasLeadingCommentRanges(param) || hasComments(param)) return
51 param.comments = comments
52 })
53 })
54 })
55​
56 return root.toSource()
58​
59function hasComments(node: cs.Node) {
60 return Array.isArray(node.comments)
62​
63function hasLeadingCommentRanges(node: TSTypeKind) {
64 return "leadingComments" in node && Array.isArray(node.leadingComments) && node.leadingComments.length > 0