UNPKG

2.65 kBPlain TextView Raw
1import * as tsdoc from '@microsoft/tsdoc';
2import * as tsm from 'ts-morph';
3
4export function getJSDocs({
5 declaration,
6}: {
7 declaration: tsm.Node;
8}): string[] {
9 const declarations = getDeclarationsWithDocs({ declaration });
10 const allDocs = declarations.flatMap((declaration) => {
11 const doc = getLastJSDoc({ declaration });
12 return doc ? doc : [];
13 });
14
15 return Array.from(new Set(allDocs));
16}
17
18function getDeclarationsWithDocs({
19 declaration,
20}: {
21 declaration: tsm.Node;
22}): tsm.Node[] {
23 if (tsm.Node.isVariableDeclaration(declaration)) {
24 return [declaration.getVariableStatementOrThrow()];
25 }
26
27 if (tsm.Node.isExpression(declaration)) {
28 return [declaration.getParent()!];
29 }
30
31 // Make functions and class methods share the same docs,
32 // that is one declaration with multiple (overload) docs,
33 // since they have their signature built from the typechecker.
34 // Exclude constructors since their signatures are built manually and
35 // thus each constructor needs its own doc.
36 if (
37 tsm.Node.isOverloadable(declaration) &&
38 !tsm.Node.isConstructorDeclaration(declaration)
39 ) {
40 const overloads = declaration.getOverloads();
41 const implementation = declaration.getImplementation();
42
43 return [...overloads, ...(implementation ? [implementation] : [])];
44 }
45
46 // Make interface methods share the same docs as for overloadable nodes
47 if (
48 tsm.Node.isMethodSignature(declaration) &&
49 declaration.getParent().getKind() ===
50 tsm.SyntaxKind.InterfaceDeclaration
51 ) {
52 const methodName = declaration.getName();
53 const overloads = declaration
54 .getParentIfKindOrThrow(tsm.SyntaxKind.InterfaceDeclaration)
55 .getMethods()
56 .filter((method) => method.getName() === methodName);
57
58 return overloads;
59 }
60
61 return [declaration];
62}
63
64function getLastJSDoc({
65 declaration,
66}: {
67 declaration: tsm.Node;
68}): string | undefined {
69 // Get the doc closest to the declaration signature
70 const doc = declaration
71 .getLastChildByKind(tsm.SyntaxKind.JSDocComment)
72 ?.getText();
73 if (!doc) {
74 return undefined;
75 }
76
77 // The first declaration after package documentation
78 // should not inherit that jsdoc if it has none.
79 // See `export-named-declaration-without-jsdoc.test.ts`.
80 const isPackageDocumentation = new tsdoc.TSDocParser()
81 .parseString(doc)
82 .docComment.modifierTagSet.isPackageDocumentation();
83 if (isPackageDocumentation) {
84 return undefined;
85 }
86
87 return doc;
88}