UNPKG

8.29 kBPlain TextView Raw
1import * as tsm from 'ts-morph';
2import {
3 isInterfaceCallSignatureDeclaration,
4 isInterfaceConstructSignatureDeclaration,
5 isInterfaceIndexSignatureDeclaration,
6 isInterfaceMethodDeclaration,
7 isInterfacePropertyDeclaration,
8} from '../types/declaration-type-guards';
9import {
10 DeclarationKinds,
11 InterfaceCallSignatureDeclaration,
12 InterfaceConstructSignatureDeclaration,
13 InterfaceDeclaration,
14 InterfaceIndexSignatureDeclaration,
15 InterfaceMemberDeclarations,
16 InterfaceMethodDeclaration,
17 InterfacePropertyDeclaration,
18} from '../types/module-declarations';
19import { formatInterfaceMember } from './format';
20import { getApparentType } from './get-apparent-type';
21import { getJSDocs } from './get-jsdocs';
22import { getWrapperSignature } from './get-wrapper-signature';
23import { isInternalDeclaration } from './is-internal-declaration';
24import { sortByID } from './sort-by-id';
25import { SourceProvider } from './source-provider';
26import { toID } from './to-id';
27import { TypeChecker } from './type-checker';
28
29export function isInterface(
30 declaration: tsm.Node
31): declaration is tsm.InterfaceDeclaration {
32 return tsm.Node.isInterfaceDeclaration(declaration);
33}
34
35export function newInterface({
36 id,
37 name,
38 declaration,
39 getSource,
40 getType,
41}: {
42 id: string;
43 name: string;
44 declaration: tsm.InterfaceDeclaration;
45 getSource: SourceProvider;
46 getType: TypeChecker;
47}): InterfaceDeclaration {
48 const kind = DeclarationKinds.InterfaceDeclaration;
49 const docs = getJSDocs({ declaration });
50 const source = getSource({ declaration });
51 const signature = getWrapperSignature({ declaration });
52
53 const members = getInterfaceMembers({
54 interfaceID: id,
55 interfaceDeclaration: declaration,
56 getSource,
57 getType,
58 });
59
60 return {
61 kind,
62 id,
63 name,
64 docs,
65 source,
66 signature,
67 members,
68 };
69}
70
71function getInterfaceMembers({
72 interfaceID,
73 interfaceDeclaration,
74 getSource,
75 getType,
76}: {
77 interfaceID: string;
78 interfaceDeclaration: tsm.InterfaceDeclaration;
79 getSource: SourceProvider;
80 getType: TypeChecker;
81}): InterfaceMemberDeclarations {
82 const seenMethods = new Set<string>();
83 const members = interfaceDeclaration
84 .getMembers()
85 .flatMap((declaration, index) => {
86 const name = getMemberName({ declaration });
87 const id = toID(interfaceID, getMemberID({ declaration, index }));
88
89 if (isInternalDeclaration({ declaration, name })) {
90 return [];
91 }
92
93 if (tsm.Node.isPropertySignature(declaration)) {
94 return newProperty({ id, name, declaration, getSource });
95 }
96
97 if (tsm.Node.isMethodSignature(declaration)) {
98 // Skip overloaded methods
99 if (seenMethods.has(id)) {
100 return [];
101 }
102
103 seenMethods.add(id);
104 return newMethod({ id, name, declaration, getSource, getType });
105 }
106
107 if (tsm.Node.isConstructSignatureDeclaration(declaration)) {
108 return newConstructSignature({
109 id,
110 name,
111 declaration,
112 getSource,
113 });
114 }
115
116 if (tsm.Node.isCallSignatureDeclaration(declaration)) {
117 return newCallSignature({ id, name, declaration, getSource });
118 }
119
120 return newIndexSignature({ id, name, declaration, getSource });
121 })
122 .sort(sortByID);
123
124 return {
125 properties: members.filter(isInterfacePropertyDeclaration),
126 methods: members.filter(isInterfaceMethodDeclaration),
127 constructSignatures: members.filter(
128 isInterfaceConstructSignatureDeclaration
129 ),
130 callSignatures: members.filter(isInterfaceCallSignatureDeclaration),
131 indexSignatures: members.filter(isInterfaceIndexSignatureDeclaration),
132 };
133}
134
135function getMemberName({
136 declaration,
137}: {
138 declaration: tsm.TypeElementTypes;
139}): string {
140 if (
141 tsm.Node.isPropertySignature(declaration) ||
142 tsm.Node.isMethodSignature(declaration)
143 ) {
144 return declaration.getName();
145 }
146
147 if (tsm.Node.isConstructSignatureDeclaration(declaration)) {
148 return 'construct signature';
149 }
150
151 if (tsm.Node.isCallSignatureDeclaration(declaration)) {
152 return 'call signature';
153 }
154
155 return 'index signature';
156}
157
158function getMemberID({
159 declaration,
160 index,
161}: {
162 declaration: tsm.TypeElementTypes;
163 index: number;
164}): string {
165 if (
166 tsm.Node.isPropertySignature(declaration) ||
167 tsm.Node.isMethodSignature(declaration)
168 ) {
169 return declaration.getName();
170 }
171
172 if (tsm.Node.isConstructSignatureDeclaration(declaration)) {
173 return `${index}-construct-signature`;
174 }
175
176 if (tsm.Node.isCallSignatureDeclaration(declaration)) {
177 return `${index}-call-signature`;
178 }
179
180 return `${index}-index-signature`;
181}
182
183function newProperty({
184 id,
185 name,
186 declaration,
187 getSource,
188}: {
189 id: string;
190 name: string;
191 declaration: tsm.PropertySignature;
192 getSource: SourceProvider;
193}): InterfacePropertyDeclaration {
194 const kind = DeclarationKinds.InterfacePropertyDeclaration;
195 const docs = getJSDocs({ declaration });
196 const source = getSource({ declaration });
197 const isReadonly = declaration.isReadonly();
198 const isOptional = declaration.hasQuestionToken();
199 const type = getApparentType({ declaration });
200 const signature = formatInterfaceMember(declaration.getText());
201
202 return {
203 kind,
204 id,
205 name,
206 docs,
207 source,
208 signature,
209 isReadonly,
210 isOptional,
211 type,
212 };
213}
214
215function newMethod({
216 id,
217 name,
218 declaration,
219 getSource,
220 getType,
221}: {
222 id: string;
223 name: string;
224 declaration: tsm.MethodSignature;
225 getSource: SourceProvider;
226 getType: TypeChecker;
227}): InterfaceMethodDeclaration {
228 const kind = DeclarationKinds.InterfaceMethodDeclaration;
229 const docs = getJSDocs({ declaration });
230 const source = getSource({ declaration });
231 const type = getType({ declaration });
232 const signature = formatInterfaceMember(`${name}: ${type}`);
233
234 return {
235 kind,
236 id,
237 name,
238 docs,
239 source,
240 signature,
241 type,
242 };
243}
244
245function newConstructSignature({
246 id,
247 name,
248 declaration,
249 getSource,
250}: {
251 id: string;
252 name: string;
253 declaration: tsm.ConstructSignatureDeclaration;
254 getSource: SourceProvider;
255}): InterfaceConstructSignatureDeclaration {
256 const kind = DeclarationKinds.InterfaceConstructSignatureDeclaration;
257 const docs = getJSDocs({ declaration });
258 const source = getSource({ declaration });
259 const signature = formatInterfaceMember(declaration.getText());
260
261 return {
262 kind,
263 id,
264 name,
265 docs,
266 source,
267 signature,
268 };
269}
270
271function newCallSignature({
272 id,
273 name,
274 declaration,
275 getSource,
276}: {
277 id: string;
278 name: string;
279 declaration: tsm.CallSignatureDeclaration;
280 getSource: SourceProvider;
281}): InterfaceCallSignatureDeclaration {
282 const kind = DeclarationKinds.InterfaceCallSignatureDeclaration;
283 const docs = getJSDocs({ declaration });
284 const source = getSource({ declaration });
285 const signature = formatInterfaceMember(declaration.getText());
286
287 return {
288 kind,
289 id,
290 name,
291 docs,
292 source,
293 signature,
294 };
295}
296
297function newIndexSignature({
298 id,
299 name,
300 declaration,
301 getSource,
302}: {
303 id: string;
304 name: string;
305 declaration: tsm.IndexSignatureDeclaration;
306 getSource: SourceProvider;
307}): InterfaceIndexSignatureDeclaration {
308 const kind = DeclarationKinds.InterfaceIndexSignatureDeclaration;
309 const docs = getJSDocs({ declaration });
310 const source = getSource({ declaration });
311 const signature = formatInterfaceMember(declaration.getText());
312
313 return {
314 kind,
315 id,
316 name,
317 docs,
318 source,
319 signature,
320 };
321}