@iviva/react-tsdoc 0.1.7 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +217 -26
  2. package/bin/react-tsdoc.js +1 -1
  3. package/dist/cli/index.d.ts +1 -0
  4. package/dist/cli/index.js +38 -0
  5. package/dist/cli/index.js.map +1 -0
  6. package/dist/core/analyzer.d.ts +18 -0
  7. package/dist/core/analyzer.js +574 -0
  8. package/dist/core/analyzer.js.map +1 -0
  9. package/dist/core/parser.d.ts +4 -0
  10. package/dist/core/parser.js +73 -0
  11. package/dist/core/parser.js.map +1 -0
  12. package/dist/core/types.d.ts +134 -0
  13. package/dist/core/types.js +10 -0
  14. package/dist/core/types.js.map +1 -0
  15. package/dist/generators/docs/component.d.ts +7 -0
  16. package/dist/generators/docs/component.js +87 -0
  17. package/dist/generators/docs/component.js.map +1 -0
  18. package/dist/generators/docs/function.d.ts +2 -0
  19. package/dist/generators/docs/function.js +38 -0
  20. package/dist/generators/docs/function.js.map +1 -0
  21. package/dist/generators/docs/hook.d.ts +2 -0
  22. package/dist/generators/docs/hook.js +36 -0
  23. package/dist/generators/docs/hook.js.map +1 -0
  24. package/dist/generators/docs/type.d.ts +2 -0
  25. package/dist/generators/docs/type.js +61 -0
  26. package/dist/generators/docs/type.js.map +1 -0
  27. package/dist/generators/markdown.d.ts +8 -0
  28. package/dist/generators/markdown.js +44 -0
  29. package/dist/generators/markdown.js.map +1 -0
  30. package/dist/generators/types/module.d.ts +4 -0
  31. package/dist/generators/types/module.js +242 -0
  32. package/dist/generators/types/module.js.map +1 -0
  33. package/dist/index.d.ts +4 -1
  34. package/dist/index.js +116 -603
  35. package/dist/index.js.map +1 -1
  36. package/dist/utils/file.d.ts +3 -0
  37. package/dist/utils/file.js +45 -0
  38. package/dist/utils/file.js.map +1 -0
  39. package/dist/utils/logger.d.ts +5 -0
  40. package/dist/utils/logger.js +28 -0
  41. package/dist/utils/logger.js.map +1 -0
  42. package/dist/utils/type-helpers.d.ts +13 -0
  43. package/dist/utils/type-helpers.js +160 -0
  44. package/dist/utils/type-helpers.js.map +1 -0
  45. package/package.json +28 -18
  46. package/.github/workflows/npm-publish.yml +0 -37
  47. package/clap.d.ts +0 -1
  48. package/package-lock.json +0 -104
  49. package/src/index.ts +0 -812
  50. package/tsconfig.json +0 -15
package/src/index.ts DELETED
@@ -1,812 +0,0 @@
1
- import * as tsdoc from '@microsoft/tsdoc';
2
- import * as fs from 'fs';
3
- import * as ts from 'typescript';
4
- import chalk from 'chalk';
5
- import { DocNode } from '@microsoft/tsdoc';
6
- import clap from 'clap';
7
- import mkdirp from 'mkdirp';
8
-
9
- enum ComponentFlags {
10
- None = 0,
11
- Export = 1 << 0,
12
- Hook = 1 << 1,
13
- }
14
-
15
- function logCompilerMessage(message: string) {
16
- console.error(chalk.gray(`[TypeScript] ${message}`));
17
- }
18
- function logDebug(...objects: any[]) {
19
- console.log(chalk.gray(...objects));
20
- }
21
- function logInfo(...objects: any[]) {
22
- console.log(chalk.green(...objects));
23
- }
24
- function logWarning(...objects: any[]) {
25
- console.log(chalk.redBright(...objects));
26
- }
27
- function logError(...objects: any[]) {
28
- console.log(chalk.redBright(...objects));
29
- }
30
- function indentCode(code: string, chars: string) {
31
- let lines = code.split('\n').map(line => line.trimRight());
32
- return lines.map(line => chars + line).join('\n');
33
- }
34
- class MarkdownBuilder {
35
- private code = "";
36
- public addTitle(title: string, level: 1 | 2 | 3 | 4) {
37
- let headerChar = '#';
38
- let prefix = '';
39
- for (let i = 0; i < level; i++) {
40
- prefix += headerChar;
41
- }
42
- this.code += prefix + ' ' + title + '\n\n';
43
- }
44
- public addParagraph(p: string) {
45
-
46
- this.code += '\n\n' + p + '\n\n';
47
- }
48
-
49
- public addCode(code: string) {
50
- code = code.trim();
51
- if (code.startsWith('```')) {
52
- code = code.substring(3);
53
- }
54
- if (code.endsWith('```')) {
55
- code = code.substring(0, code.length - 3);
56
- }
57
- this.code += '\n\n```tsx\n' + code.trim() + '\n```\n\n'
58
- }
59
- public addTable(table: any[]) {
60
- const tableFormat = (s: string) => {
61
- return s.replace(/\s+/g, ' ').replace(/\|/g, '\\|');
62
- }
63
- if (table.length == 0) {
64
- this.code += '\n\n';
65
- return
66
- }
67
- let headers = Object.keys(table[0]);
68
- this.code += '|' + (headers.map(tableFormat)).join('|') + '|\n';
69
- this.code += '|' + (headers.map(h => '-')).join('|') + '|\n';
70
- for (let i in table) {
71
- let row = table[i];
72
- this.code += '|' + (headers.map(h => tableFormat(row[h]))).join('|') + '|\n';
73
- }
74
-
75
- this.code += '\n\n'
76
-
77
- }
78
- public toString() {
79
- return this.code;
80
- }
81
- }
82
- interface IExportModuleOptions {
83
- moduleName: string;
84
- }
85
-
86
- interface ITypeDefinition {
87
- comment: string;
88
- }
89
-
90
- interface IFunctionParam {
91
- name: string;
92
- type: string;
93
- }
94
- interface IFunctionSignature extends ITypeDefinition {
95
- parameters: IFunctionParam[];
96
- return: string;
97
- code: string;
98
- }
99
- interface IUnion extends ITypeDefinition {
100
- items: string[];
101
- code: string;
102
- }
103
- interface IInterfaceMember {
104
- name: string;
105
- type: string;
106
- comment: string;
107
- }
108
- interface IInterfaceDeclaration extends ITypeDefinition {
109
- name: string;
110
- comment: string;
111
- members: IInterfaceMember[];
112
- code: string;
113
- }
114
- interface IReactComponent {
115
- name: string;
116
- propType: string;
117
- stateType?: string
118
- refType?: string
119
- comment: string;
120
- type?: 'class' | 'functional' | 'forwardRef'
121
- }
122
- interface IReactHookParam {
123
- name: string;
124
- type: string;
125
- }
126
- interface IReactHook {
127
- name: string;
128
- type: string;
129
- parameters: IReactHookParam[];
130
- comment: string;
131
- }
132
- interface IDocInfo {
133
- interfaces: { [key: string]: IInterfaceDeclaration };
134
- components: { [key: string]: IReactComponent };
135
- hooks: { [key: string]: IReactHook };
136
- functions: { [key: string]: IFunctionSignature };
137
- unions: { [key: string]: IUnion };
138
-
139
- }
140
- interface IExample {
141
- summary: string;
142
-
143
- }
144
- interface ITypeDocumentation {
145
- name: string;
146
- type: 'interface' | 'function' | 'union';
147
- summary: string;
148
- examples: IExample[];
149
- code: string;
150
- flags: ComponentFlags;
151
-
152
- }
153
-
154
- interface IHookDocumentation {
155
- name: string;
156
- summary: string;
157
- examples: IExample[];
158
- flags: ComponentFlags;
159
- }
160
- interface IComponentDocumentation {
161
- /**
162
- * The name of the component
163
- */
164
- name: string;
165
-
166
- /**
167
- * Summary
168
- */
169
- summary: string;
170
-
171
- /**
172
- * Examples
173
- */
174
- examples: IExample[];
175
-
176
- /**
177
- * Docs for individual properties
178
- */
179
- props: IComponentPropDocumentation[];
180
-
181
- /**
182
- * Any custom @-attribute flags set on the component
183
- */
184
- flags: ComponentFlags;
185
-
186
- }
187
- interface IDocObject {
188
- components: IComponentDocumentation[];
189
- hooks: IHookDocumentation[];
190
- types: ITypeDocumentation[];
191
- }
192
-
193
- /**
194
- * Individual property documentation
195
- */
196
- interface IComponentPropDocumentation {
197
- name: string;
198
- type: string;
199
- summary: string;
200
- examples: IExample[];
201
- }
202
- function extractActualContentFromDocMess(node: tsdoc.DocNode): string {
203
- if (!node) {
204
- return "";
205
- }
206
- let result = "";
207
- if (node instanceof tsdoc.DocExcerpt) {
208
- result += node.content.toString();
209
- }
210
- for (const childNode of node.getChildNodes()) {
211
- result += extractActualContentFromDocMess(childNode);
212
- }
213
- return result;
214
- }
215
- function parseTSDocComment(comment: string): [string, IExample[], ComponentFlags] {
216
- let config = new tsdoc.TSDocConfiguration();
217
-
218
- config.addTagDefinition(
219
- new tsdoc.TSDocTagDefinition({
220
- tagName: '@export',
221
- syntaxKind: tsdoc.TSDocTagSyntaxKind.ModifierTag,
222
- allowMultiple: false
223
- })
224
- );
225
-
226
- config.addTagDefinition(
227
- new tsdoc.TSDocTagDefinition({
228
- tagName: '@hook',
229
- syntaxKind: tsdoc.TSDocTagSyntaxKind.ModifierTag,
230
- allowMultiple: false
231
- })
232
- );
233
-
234
- let parser = new tsdoc.TSDocParser(config);
235
-
236
- let ctx = parser.parseString(comment);
237
- let summary = extractActualContentFromDocMess(ctx.docComment.summarySection);
238
- let examples: IExample[] = [];
239
- let props: ComponentFlags = ComponentFlags.None;
240
- for (const block of ctx.docComment.customBlocks) {
241
- if (block.blockTag.tagName == '@example') {
242
- let example = { summary: extractActualContentFromDocMess(block.content) };
243
- examples.push(example);
244
-
245
- }
246
- }
247
- let flags: ComponentFlags = ComponentFlags.None;
248
-
249
- if (ctx.docComment.modifierTagSet.hasTagName('@export')) {
250
- flags = flags | ComponentFlags.Export;
251
- }
252
-
253
- if (ctx.docComment.modifierTagSet.hasTagName('@hook')) {
254
- flags = flags | ComponentFlags.Hook;
255
- }
256
-
257
- return [summary, examples, flags];
258
- }
259
- function generatePropDocs(inf: IInterfaceDeclaration) {
260
- let results: IComponentPropDocumentation[] = [];
261
- for (let i in inf.members) {
262
- let prop = inf.members[i];
263
- let propDoc: IComponentPropDocumentation = { examples: [], name: prop.name, summary: '', type: prop.type };
264
- [propDoc.summary, propDoc.examples] = parseTSDocComment(prop.comment);
265
- results.push(propDoc);
266
- }
267
- return results;
268
- }
269
- function generateHookTypeDefinition(hook: IReactHook) {
270
- return `export const ${hook.name}:${hook.type};`;
271
- }
272
- function generateComponentTypeDefinition(c: IReactComponent, interfaces: { [key: string]: IInterfaceDeclaration }) {
273
- let code = "";
274
- let type = c.type || 'functional'
275
- let inf = interfaces[c.propType];
276
- if (inf) {
277
- code += inf.comment + '\n';
278
- code += inf.code + '\n';
279
- }
280
- if (c.stateType) {
281
- let stateInf = interfaces[c.stateType];
282
- if (stateInf) {
283
- code += stateInf.comment + '\n';
284
- code += stateInf.code + '\n';
285
- }
286
- }
287
- if (c.refType) {
288
- let refInf = interfaces[c.refType];
289
- if (refInf) {
290
- code += refInf.comment + '\n';
291
- code += refInf.code + '\n';
292
- }
293
- }
294
- code += c.comment + '\n';
295
-
296
- switch (type) {
297
- case 'functional':
298
- code += `export const ${c.name} : React.FunctionComponent<${c.propType}>;\n`
299
- break
300
- case 'class':
301
- code += `export class ${c.name} extends React.Component<${c.propType}, ${c.stateType || 'any'}> {}\n`
302
- break
303
- case 'forwardRef':
304
- code += `export const ${c.name}:React.ForwardRefExoticComponent<${c.propType} & React.RefAttributes<${c.refType || 'any'}>>;\n`
305
- break
306
- }
307
-
308
- return code;
309
- }
310
- function fillRelatedTypes(t: string, types: any, docInfo: IDocInfo) {
311
- if (docInfo.interfaces[t]) {
312
- types[t] = 1;
313
- let inf = docInfo.interfaces[t];
314
- for (let m of inf.members) {
315
- fillRelatedTypes(m.comment, types, docInfo);
316
- }
317
- return;
318
- }
319
- if (docInfo.unions[t]) {
320
- types[t] = 1;
321
- return;
322
- }
323
- if (docInfo.functions[t]) {
324
- let f = docInfo.functions[t];
325
- types[t] = 1;
326
- fillRelatedTypes(f.return, types, docInfo);
327
- for (let p of f.parameters) {
328
- let pt = p.type;
329
- fillRelatedTypes(pt, types, docInfo);
330
- }
331
- }
332
-
333
- }
334
- function generateDocObject(docInfo: IDocInfo): IDocObject {
335
- let components: IComponentDocumentation[] = [];
336
- //let typesToExport:any = {};
337
- for (let cn in docInfo.components) {
338
- let componentDoc: IComponentDocumentation = { examples: [], name: cn, props: [], summary: '', flags: ComponentFlags.None };
339
- let componentInfo = docInfo.components[cn];
340
- [componentDoc.summary, componentDoc.examples, componentDoc.flags] = parseTSDocComment(componentInfo.comment);
341
-
342
- let propType = docInfo.interfaces[componentInfo.propType];
343
- if (!!propType) {
344
- componentDoc.props = generatePropDocs(propType)
345
- }
346
- //typesToExport[componentInfo.propType] = 1;
347
-
348
- components.push(componentDoc);
349
-
350
- }
351
- let hooks: IHookDocumentation[] = [];
352
- for (let hi in docInfo.hooks) {
353
- let hook = docInfo.hooks[hi];
354
- let hookDoc: IHookDocumentation = { name: hook.name, flags: ComponentFlags.None, summary: '', examples: [] };
355
- [hookDoc.summary, hookDoc.examples, hookDoc.flags] = parseTSDocComment(hook.comment);
356
- let propType = docInfo.functions[hook.type];
357
- // if (!!propType) {
358
- // typesToExport[hook.type] = 1;
359
- // }
360
- hooks.push(hookDoc);
361
- }
362
- //console.log(typesToExport);
363
- // for(let k of Object.keys(typesToExport)) {
364
- // fillRelatedTypes(k,typesToExport,docInfo);
365
- // }
366
- let types: ITypeDocumentation[] = [];
367
- for (let k of Object.keys(docInfo.interfaces)) {
368
- let inf = docInfo.interfaces[k];
369
- let typeDoc: ITypeDocumentation = { examples: [], name: inf.name, summary: '', type: 'interface', code: '', flags: ComponentFlags.None };
370
- typeDoc.code = inf.code;
371
- [typeDoc.summary, typeDoc.examples, typeDoc.flags] = parseTSDocComment(inf.comment);
372
- types.push(typeDoc);
373
- }
374
- for (let k of Object.keys(docInfo.functions)) {
375
- let inf = docInfo.functions[k];
376
- let typeDoc: ITypeDocumentation = { examples: [], name: k, summary: '', type: 'function', code: '', flags: ComponentFlags.None };
377
- typeDoc.code = inf.code;
378
- [typeDoc.summary, typeDoc.examples, typeDoc.flags] = parseTSDocComment(inf.comment);
379
- types.push(typeDoc);
380
- }
381
- for (let k of Object.keys(docInfo.unions)) {
382
- let inf = docInfo.unions[k];
383
- let typeDoc: ITypeDocumentation = { examples: [], name: k, summary: '', type: 'union', code: '', flags: ComponentFlags.None };
384
- typeDoc.code = inf.code;
385
- [typeDoc.summary, typeDoc.examples, typeDoc.flags] = parseTSDocComment(inf.comment);
386
- types.push(typeDoc);
387
- }
388
-
389
-
390
- return { components, hooks, types };
391
- }
392
-
393
- function extractComment(node: ts.Node) {
394
- let fullText = node.getSourceFile().getFullText();
395
- let comments = ts.getLeadingCommentRanges(fullText, node.pos);
396
- if (!comments) return '';
397
- return comments!.map(c => fullText.slice(c.pos, c.end)).join('\n');
398
- }
399
- function getCode(node: ts.Node) {
400
- return node.getSourceFile().getFullText().substring(node.getStart(), node.getEnd());
401
- }
402
- function parseFunctionSignature(node: ts.Node, docInfo: IDocInfo) {
403
-
404
- }
405
- function parseInterfaceDeclaration(node: ts.Node, docInfo: IDocInfo) {
406
-
407
- let name = (node as any).name.getText();
408
- let members = (node as any).members;
409
- if (members.length == 1 && members[0].kind == ts.SyntaxKind.CallSignature) {
410
- return parseFunctionSignature(members[0], docInfo);
411
- }
412
-
413
- let docs = extractComment(node);
414
- let inf: IInterfaceDeclaration = { comment: docs, members: [], name: name, code: getCode(node) };
415
- for (let i = 0; i < members.length; i++) {
416
- let member = members[i];
417
- let name = member.name.getText();
418
- let type = member.type.getText();
419
- let mdoc = extractComment(member);
420
- inf.members.push({ comment: mdoc, name: name, type: type });
421
- }
422
- docInfo.interfaces[name] = inf;
423
-
424
- }
425
- function parseVariableDeclaration(node: ts.Node, docInfo: IDocInfo) {
426
-
427
- let type = (node as any).type?.typeName?.getText();
428
- if ((node as any)?.type?.kind == ts.SyntaxKind.CallSignature ||
429
- (node as any)?.type?.kind == ts.SyntaxKind.FunctionType
430
- ) {
431
- console.log('dug');
432
- }
433
- if (!type) {
434
- return;
435
- }
436
- let name = (node as any).name.getText() as string;
437
- if (type == 'React.FunctionComponent') {
438
- let propType = (node as any).type.typeArguments[0].getText();
439
- let comment = extractComment(node.parent);
440
- docInfo.components[name] = { comment, propType, name, type: 'functional' };
441
- return;
442
- }
443
- if (type == 'React.ForwardRefExoticComponent') {
444
- let cType = (node as any).type.typeArguments[0].getText();
445
- // get prop type and ref type
446
- // assume
447
- // - props defined as following format <PropType & RefType>
448
- // - RefType always starts with `React.RefAttributes`
449
- let parts = (cType as string).split("&", 2).map(p => p.trim())
450
- let propType = parts[0]
451
- let refType = parts[1]
452
- if (parts[0].startsWith('React.RefAttributes')) {
453
- propType = parts[1]
454
- refType = parts[0]
455
- }
456
-
457
- refType = refType
458
- .replace('React.RefAttributes<', '')
459
- .replace(">", '')
460
- .trim()
461
-
462
-
463
- let comment = extractComment(node.parent);
464
- docInfo.components[name] = { comment, propType, refType, name, type: 'forwardRef' };
465
- return;
466
- }
467
- if (name.startsWith('use')) {
468
- let comment = extractComment(node.parent);
469
- let parameters: IReactHookParam[] = [];
470
-
471
- docInfo.hooks[name] = { name, type, parameters, comment };
472
- }
473
- }
474
- function parseClassDeclaration(node: ts.Node, docInfo: IDocInfo) {
475
- let className = (node as any)?.heritageClauses[0]?.types[0].expression.getText();
476
- if (className == 'React.Component') {
477
- let propType = (node as any).heritageClauses[0].types[0].typeArguments[0].getText();
478
- let stateType = (node as any).heritageClauses[0].types[0].typeArguments[1].getText();
479
- let comment = extractComment(node);
480
- let name = (node as any).name.getText();
481
- docInfo.components[name] = { comment, propType, name, stateType, type: 'class' };
482
-
483
- }
484
- }
485
- function parseTypeAlias(node: ts.Node, docInfo: IDocInfo) {
486
- let name = (node as any).name.getText();
487
- let type = (node as any).type;
488
- if (type.kind == ts.SyntaxKind.FunctionType) {
489
- let returnType = type.getText();
490
- let parameters = type.parameters;
491
- let comment = extractComment(node);
492
- let code = getCode(node);
493
- let f: IFunctionSignature = { parameters: [], return: returnType, comment, code };
494
- for (let p = 0; p < parameters.length; p++) {
495
- let parameter = parameters[p];
496
- let fp: IFunctionParam = { name: parameter.name.getText(), type: parameter.type.getText() };
497
- f.parameters.push(fp);
498
-
499
- }
500
- docInfo.functions[name] = f;
501
- return;
502
- }
503
- if (type.kind == ts.SyntaxKind.UnionType) {
504
- let types = type.types;
505
- let comment = extractComment(node);
506
- let code = getCode(node);
507
- let u: IUnion = { items: [], comment, code };
508
-
509
- for (let p = 0; p < types.length; p++) {
510
- let txt = types[p].getText();
511
- u.items.push(txt);
512
- }
513
- docInfo.unions[name] = u;
514
- }
515
- }
516
-
517
- function walkTree(node: ts.Node, docInfo: IDocInfo) {
518
- switch (node.kind) {
519
- case ts.SyntaxKind.TypeAliasDeclaration:
520
- parseTypeAlias(node, docInfo);
521
- break;
522
- case ts.SyntaxKind.InterfaceDeclaration:
523
- parseInterfaceDeclaration(node, docInfo);
524
- break;
525
- case ts.SyntaxKind.VariableDeclaration:
526
- parseVariableDeclaration(node, docInfo);
527
- break;
528
- case ts.SyntaxKind.ClassDeclaration:
529
- parseClassDeclaration(node, docInfo);
530
- break;
531
- case ts.SyntaxKind.FunctionDeclaration:
532
- case 242:
533
- parseVariableDeclaration(node, docInfo);
534
- break;
535
-
536
- }
537
- node.forEachChild((child: any) => walkTree(child, docInfo));
538
-
539
- }
540
- function validateProgram(program: ts.Program) {
541
- const compilerDiagnostics: ReadonlyArray<ts.Diagnostic> = program.getSemanticDiagnostics();
542
- if (compilerDiagnostics.length > 0) {
543
- for (const diagnostic of compilerDiagnostics) {
544
-
545
- const message: string = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
546
- if (diagnostic.file) {
547
- const location: ts.LineAndCharacter = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!);
548
- const formattedMessage: string = `${diagnostic.file.fileName}(${location.line + 1},${location.character + 1}):`
549
- + `${message}`;
550
- logCompilerMessage(formattedMessage);
551
- } else {
552
- logCompilerMessage(message);
553
- }
554
- }
555
- } else {
556
- logCompilerMessage('No compiler errors or warnings.');
557
- }
558
- }
559
-
560
- function getSources(program: ts.Program) {
561
- return program.getSourceFiles().filter(f => {
562
- return f.fileName.indexOf('node_modules') < 0
563
- }).map(f => f.fileName);
564
- }
565
-
566
- function generateExportModule(docs: IDocObject, docInfo: IDocInfo, options: IExportModuleOptions) {
567
- let code = '';
568
- if (options?.moduleName) {
569
- code += `declare module "${options.moduleName}" {\n`;
570
- }
571
- for (let i in docs.types) {
572
- let obj = docs.types[i];
573
- let comment = '';
574
- if (docInfo.interfaces[obj.name]) {
575
- comment = docInfo.interfaces[obj.name].comment;
576
- }
577
- if (docInfo.functions[obj.name]) {
578
- comment = docInfo.functions[obj.name].comment;
579
- }
580
- if (docInfo.unions[obj.name]) {
581
- comment = docInfo.unions[obj.name].comment;
582
- }
583
- if (ComponentFlags.Export === (obj.flags & ComponentFlags.Export)) {
584
- code += indentCode('\n' + comment + '\n' + 'export ' + obj.code + '\n', ' ');
585
- }
586
- }
587
- for (let i in docs.components) {
588
- let doc = docs.components[i];
589
-
590
- if (ComponentFlags.Export === (doc.flags & ComponentFlags.Export)) {
591
- let component = docInfo.components[doc.name];
592
- let componentCode = generateComponentTypeDefinition(component, docInfo.interfaces);
593
- code += indentCode(componentCode, ' ');
594
- }
595
- }
596
- for (let i in docs.hooks) {
597
- let doc = docs.hooks[i];
598
- if (ComponentFlags.Export === (doc.flags & ComponentFlags.Export)) {
599
- let hook = docInfo.hooks[doc.name];
600
- let hookCode = generateHookTypeDefinition(hook);
601
- code += indentCode(hookCode, ' ');
602
- }
603
-
604
- }
605
- code += "\n}\n";
606
- return code;
607
- }
608
-
609
- function load(root: string): [IDocInfo, IDocObject] {
610
- let options: ts.CompilerOptions = {
611
- jsx: ts.JsxEmit.React,
612
- };
613
- logDebug('Loading', root);
614
- logDebug('Loading', root);
615
- let program = ts.createProgram([root], options);
616
- logDebug('Compiled');
617
- validateProgram(program);
618
- logDebug('Validated');
619
- let sources = getSources(program);
620
- let docInfo: IDocInfo = { interfaces: {}, components: {}, hooks: {}, functions: {}, unions: {} };
621
- for (var i = 0; i < sources.length; i++) {
622
- let source = sources[i];
623
- logDebug('Loading', source);
624
- let sourceNode = program.getSourceFile(source);
625
- if (!sourceNode) {
626
- continue;
627
- }
628
-
629
- try {
630
- walkTree(sourceNode, docInfo);
631
- } catch (error) {
632
- logError(`Error in ${source}: ${error}`)
633
- }
634
- }
635
- let docs = generateDocObject(docInfo);
636
- return [docInfo, docs];
637
-
638
-
639
-
640
- /*
641
- for(let i in docInfo.components) {
642
- let c = docInfo.components[i];
643
- let inf = docInfo.interfaces[c.propType];
644
- if (!!inf) {
645
- console.log(inf.comment);
646
- console.log(inf.code);
647
- }
648
- console.log(c.comment);
649
- console.log(`export const ${c.name} : React.FunctionComponent<${c.propType}>;`)
650
- }*/
651
-
652
- }
653
-
654
-
655
- function generateHookDoc(cdoc: IHookDocumentation, docs: IDocObject) {
656
- let md = new MarkdownBuilder();
657
- md.addTitle(cdoc.name, 1)
658
- md.addParagraph(cdoc.summary);
659
- md.addTitle('Installation', 2);
660
- md.addCode(`import {${cdoc.name}} from 'uxp/components';`);
661
- if (cdoc.examples.length > 0) {
662
- md.addTitle('Examples', 2);
663
- for (let i in cdoc.examples) {
664
- md.addCode(cdoc.examples[i].summary)
665
- }
666
- }
667
-
668
- return md.toString();
669
- }
670
-
671
- function generateTypeDoc(cdoc: ITypeDocumentation, docs: IDocObject) {
672
- let md = new MarkdownBuilder();
673
- md.addTitle(cdoc.name, 1)
674
- md.addParagraph(cdoc.summary);
675
- md.addCode(cdoc.code);
676
- md.addTitle('Usage', 2);
677
- md.addCode(`import {${cdoc.name}} from 'uxp/components';`);
678
- if (cdoc.examples.length > 0) {
679
- md.addTitle('Examples', 2);
680
- for (let i in cdoc.examples) {
681
- md.addCode(cdoc.examples[i].summary)
682
- }
683
- }
684
-
685
-
686
- return md.toString();
687
- }
688
- function linkedType(t: string, docs: IDocObject) {
689
- if (docs.types.find(x => x.name.toUpperCase() == t.toUpperCase())) {
690
- return `../[${t}](types/${t}.md)`;
691
- }
692
- return t;
693
- }
694
- function generateComponentDoc(cdoc: IComponentDocumentation, docs: IDocObject) {
695
- let md = new MarkdownBuilder();
696
- md.addTitle(cdoc.name, 1)
697
- md.addParagraph(cdoc.summary);
698
- md.addTitle('Installation', 2);
699
- md.addCode(`import {${cdoc.name}} from 'uxp/components';`);
700
- if (cdoc.examples.length > 0) {
701
- md.addTitle('Examples', 2);
702
- for (let i in cdoc.examples) {
703
- md.addCode(cdoc.examples[i].summary)
704
- }
705
- }
706
- if (cdoc.props.length > 0) {
707
-
708
- md.addTitle('Properties', 2);
709
- md.addTable(cdoc.props.map(p => ({ Name: p.name, Type: linkedType(p.type, docs), Description: p.summary })));
710
- for (let i in cdoc.props) {
711
- let prop = cdoc.props[i];
712
- md.addTitle(prop.name, 3);
713
- md.addParagraph('---');
714
- md.addParagraph(prop.summary);
715
- md.addTable([{ 'type': linkedType(prop.type, docs) }]);
716
-
717
- for (let j in prop.examples) {
718
- md.addCode(prop.examples[j].summary);
719
- }
720
- }
721
-
722
- }
723
- return md.toString();
724
- }
725
- function generateDocs(root: string, outputPath: string) {
726
- let [docInfo, docs] = load(root);
727
- let components = docs.components;
728
- if (outputPath.endsWith('/')) outputPath = outputPath.substring(0, outputPath.length - 1);
729
-
730
- mkdirp.sync(outputPath + '/components/');
731
- mkdirp.sync(outputPath + '/types/');
732
- mkdirp.sync(outputPath + '/hooks/');
733
-
734
- for (let i in components) {
735
- let component = components[i];
736
- if (ComponentFlags.Export === (component.flags & ComponentFlags.Export)) {
737
- let md = generateComponentDoc(component, docs);
738
- let path = outputPath + '/components/' + component.name + '.md';
739
-
740
- console.log(chalk.gray('Writing component', component.name, 'to', path));
741
- fs.writeFileSync(path, md.toString());
742
- }
743
- }
744
- for (let i in docs.types) {
745
- let type = docs.types[i];
746
- if (ComponentFlags.Export === (type.flags & ComponentFlags.Export)) {
747
- let md = generateTypeDoc(type, docs);
748
- let path = outputPath + '/types/' + type.name + '.md';
749
- console.log(chalk.gray('Writing type', type.name, 'to', path));
750
- fs.writeFileSync(path, md.toString());
751
- }
752
- }
753
-
754
- for (let i in docs.hooks) {
755
- let hook = docs.hooks[i];
756
- if (ComponentFlags.Export === (hook.flags & ComponentFlags.Export)) {
757
- let md = generateHookDoc(hook, docs);
758
- let path = outputPath + '/hooks/' + hook.name + '.md';
759
- console.log(chalk.gray('Writing hook', hook.name, 'to', path));
760
- fs.writeFileSync(path, md.toString());
761
- }
762
- }
763
- }
764
- function generateTypeDefinition(root: string, outputPath: string, moduleName: string) {
765
-
766
-
767
- let [docInfo, docs] = load(root);
768
- let moduleCode = generateExportModule(docs, docInfo, { moduleName: moduleName || 'module' });
769
- fs.writeFileSync(outputPath, moduleCode);
770
- }
771
-
772
- export function main() {
773
- try {
774
- let cmd = clap
775
- .command('react-tsdoc')
776
- .description('Generate docs for React components')
777
- .version('0.0.1')
778
- ;
779
- cmd.command('types [input.ts] [output.t.ds]')
780
- .option('--module-name <name>')
781
-
782
-
783
- .action((actionArgs: { args: string[], options: any }) => {
784
- let args = actionArgs.args || [];
785
- let options = actionArgs.options || {};
786
-
787
- generateTypeDefinition(
788
- args[0],
789
- args[1],
790
- options.moduleName
791
- );
792
- })
793
-
794
- ;
795
-
796
- cmd.command('docs [input.ts] [output-folder]')
797
- .action((actionArgs: { args: string[], options: any }) => {
798
- let { args, options } = actionArgs;
799
- generateDocs(args[0], args[1]);
800
- })
801
- ;
802
-
803
- cmd.run();
804
- } catch (e) {
805
- console.error(chalk.red(e));
806
-
807
- }
808
-
809
-
810
- }
811
-
812
-