@refrakt-md/cli 0.9.0 → 0.9.1
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.
- package/dist/bin.js +3 -94
- package/dist/bin.js.map +1 -1
- package/dist/commands/inspect.js +4 -4
- package/dist/commands/inspect.js.map +1 -1
- package/dist/lib/format.d.ts.map +1 -1
- package/dist/lib/format.js +28 -2
- package/dist/lib/format.js.map +1 -1
- package/package.json +6 -9
- package/dist/commands/extract.d.ts +0 -10
- package/dist/commands/extract.d.ts.map +0 -1
- package/dist/commands/extract.js +0 -161
- package/dist/commands/extract.js.map +0 -1
- package/dist/extractors/index.d.ts +0 -3
- package/dist/extractors/index.d.ts.map +0 -1
- package/dist/extractors/index.js +0 -17
- package/dist/extractors/index.js.map +0 -1
- package/dist/extractors/python-docstring.d.ts +0 -26
- package/dist/extractors/python-docstring.d.ts.map +0 -1
- package/dist/extractors/python-docstring.js +0 -396
- package/dist/extractors/python-docstring.js.map +0 -1
- package/dist/extractors/python.d.ts +0 -21
- package/dist/extractors/python.d.ts.map +0 -1
- package/dist/extractors/python.js +0 -560
- package/dist/extractors/python.js.map +0 -1
- package/dist/extractors/types.d.ts +0 -55
- package/dist/extractors/types.d.ts.map +0 -1
- package/dist/extractors/types.js +0 -2
- package/dist/extractors/types.js.map +0 -1
- package/dist/extractors/typescript.d.ts +0 -28
- package/dist/extractors/typescript.d.ts.map +0 -1
- package/dist/extractors/typescript.js +0 -566
- package/dist/extractors/typescript.js.map +0 -1
- package/dist/lib/layout-generator.d.ts +0 -8
- package/dist/lib/layout-generator.d.ts.map +0 -1
- package/dist/lib/layout-generator.js +0 -22
- package/dist/lib/layout-generator.js.map +0 -1
- package/dist/lib/symbol-generator.d.ts +0 -14
- package/dist/lib/symbol-generator.d.ts.map +0 -1
- package/dist/lib/symbol-generator.js +0 -201
- package/dist/lib/symbol-generator.js.map +0 -1
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
export type SymbolKind = 'function' | 'class' | 'interface' | 'enum' | 'type' | 'module' | 'hook' | 'component';
|
|
2
|
-
export interface SymbolParameter {
|
|
3
|
-
name: string;
|
|
4
|
-
type: string;
|
|
5
|
-
description: string;
|
|
6
|
-
optional: boolean;
|
|
7
|
-
defaultValue?: string;
|
|
8
|
-
children?: SymbolParameter[];
|
|
9
|
-
}
|
|
10
|
-
export interface SymbolReturn {
|
|
11
|
-
type: string;
|
|
12
|
-
description: string;
|
|
13
|
-
}
|
|
14
|
-
export interface SymbolThrows {
|
|
15
|
-
type: string;
|
|
16
|
-
description: string;
|
|
17
|
-
}
|
|
18
|
-
export interface SymbolMemberDoc {
|
|
19
|
-
name: string;
|
|
20
|
-
kind: 'property' | 'method' | 'constructor' | 'accessor' | 'index-signature';
|
|
21
|
-
signature: string;
|
|
22
|
-
description: string;
|
|
23
|
-
parameters?: SymbolParameter[];
|
|
24
|
-
returns?: SymbolReturn;
|
|
25
|
-
throws?: SymbolThrows[];
|
|
26
|
-
since?: string;
|
|
27
|
-
deprecated?: string;
|
|
28
|
-
}
|
|
29
|
-
export interface SymbolGroupDoc {
|
|
30
|
-
label: string;
|
|
31
|
-
members: SymbolMemberDoc[];
|
|
32
|
-
}
|
|
33
|
-
export interface SymbolDoc {
|
|
34
|
-
name: string;
|
|
35
|
-
kind: SymbolKind;
|
|
36
|
-
signature: string;
|
|
37
|
-
description: string;
|
|
38
|
-
parameters?: SymbolParameter[];
|
|
39
|
-
returns?: SymbolReturn;
|
|
40
|
-
throws?: SymbolThrows[];
|
|
41
|
-
since?: string;
|
|
42
|
-
deprecated?: string;
|
|
43
|
-
source?: string;
|
|
44
|
-
groups?: SymbolGroupDoc[];
|
|
45
|
-
filePath: string;
|
|
46
|
-
line: number;
|
|
47
|
-
}
|
|
48
|
-
export interface ExtractorResult {
|
|
49
|
-
symbols: SymbolDoc[];
|
|
50
|
-
filePath: string;
|
|
51
|
-
}
|
|
52
|
-
export interface SymbolExtractor {
|
|
53
|
-
extractFile(filePath: string): ExtractorResult;
|
|
54
|
-
}
|
|
55
|
-
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/extractors/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,OAAO,GAAG,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAEhH,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,aAAa,GAAG,UAAU,GAAG,iBAAiB,CAAC;IAC7E,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC/B,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,CAAC;CAC/C"}
|
package/dist/extractors/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/extractors/types.ts"],"names":[],"mappings":""}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { SymbolExtractor, ExtractorResult } from './types.js';
|
|
2
|
-
export declare class TypeScriptExtractor implements SymbolExtractor {
|
|
3
|
-
private program;
|
|
4
|
-
private checker;
|
|
5
|
-
private rootDir;
|
|
6
|
-
private sourceUrl?;
|
|
7
|
-
constructor(rootDir: string, sourceUrl?: string);
|
|
8
|
-
extractFile(filePath: string): ExtractorResult;
|
|
9
|
-
private extractExport;
|
|
10
|
-
private extractFunction;
|
|
11
|
-
private extractVariable;
|
|
12
|
-
private extractClass;
|
|
13
|
-
private extractClassMembers;
|
|
14
|
-
private extractInterface;
|
|
15
|
-
private extractInterfaceMembers;
|
|
16
|
-
private extractEnum;
|
|
17
|
-
private extractTypeAlias;
|
|
18
|
-
private extractMemberDoc;
|
|
19
|
-
private extractParameters;
|
|
20
|
-
private extractReturn;
|
|
21
|
-
private extractThrows;
|
|
22
|
-
private isPrivateOrProtected;
|
|
23
|
-
private hasModifier;
|
|
24
|
-
private buildSourceUrl;
|
|
25
|
-
}
|
|
26
|
-
/** Find all TypeScript source files in a directory */
|
|
27
|
-
export declare function findSourceFiles(dir: string): string[];
|
|
28
|
-
//# sourceMappingURL=typescript.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"typescript.d.ts","sourceRoot":"","sources":["../../src/extractors/typescript.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEsB,eAAe,EAAE,eAAe,EACjE,MAAM,YAAY,CAAC;AAkFpB,qBAAa,mBAAoB,YAAW,eAAe;IAC1D,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAC,CAAS;gBAEf,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;IAoB/C,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe;IAmB9C,OAAO,CAAC,aAAa;IAuCrB,OAAO,CAAC,eAAe;IAyBvB,OAAO,CAAC,eAAe;IAiDvB,OAAO,CAAC,YAAY;IA0BpB,OAAO,CAAC,mBAAmB;IAuC3B,OAAO,CAAC,gBAAgB;IA4BxB,OAAO,CAAC,uBAAuB;IAuB/B,OAAO,CAAC,WAAW;IAyCnB,OAAO,CAAC,gBAAgB;IAqBxB,OAAO,CAAC,gBAAgB;IAkFxB,OAAO,CAAC,iBAAiB;IA8CzB,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,oBAAoB;IAK5B,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,cAAc;CAKtB;AAED,sDAAsD;AACtD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAQrD"}
|
|
@@ -1,566 +0,0 @@
|
|
|
1
|
-
import ts from 'typescript';
|
|
2
|
-
import { resolve, relative, dirname } from 'node:path';
|
|
3
|
-
import { readdirSync, statSync, existsSync } from 'node:fs';
|
|
4
|
-
function getJSDocDescription(node) {
|
|
5
|
-
const jsDocs = node.jsDoc;
|
|
6
|
-
if (!jsDocs || jsDocs.length === 0)
|
|
7
|
-
return '';
|
|
8
|
-
const doc = jsDocs[jsDocs.length - 1];
|
|
9
|
-
if (!doc.comment)
|
|
10
|
-
return '';
|
|
11
|
-
if (typeof doc.comment === 'string')
|
|
12
|
-
return doc.comment;
|
|
13
|
-
return doc.comment.map((c) => c.text ?? '').join('');
|
|
14
|
-
}
|
|
15
|
-
function extractJSDoc(node) {
|
|
16
|
-
const description = getJSDocDescription(node);
|
|
17
|
-
const params = new Map();
|
|
18
|
-
let returns;
|
|
19
|
-
let since;
|
|
20
|
-
let deprecated;
|
|
21
|
-
const throws = [];
|
|
22
|
-
const tags = ts.getJSDocTags(node);
|
|
23
|
-
for (const tag of tags) {
|
|
24
|
-
const tagName = tag.tagName.text;
|
|
25
|
-
const comment = typeof tag.comment === 'string'
|
|
26
|
-
? tag.comment
|
|
27
|
-
: tag.comment?.map((c) => c.text ?? '').join('') ?? '';
|
|
28
|
-
switch (tagName) {
|
|
29
|
-
case 'param': {
|
|
30
|
-
const paramTag = tag;
|
|
31
|
-
const name = paramTag.name?.getText() ?? '';
|
|
32
|
-
if (name)
|
|
33
|
-
params.set(name, comment);
|
|
34
|
-
break;
|
|
35
|
-
}
|
|
36
|
-
case 'returns':
|
|
37
|
-
case 'return':
|
|
38
|
-
returns = comment;
|
|
39
|
-
break;
|
|
40
|
-
case 'since':
|
|
41
|
-
since = comment.trim();
|
|
42
|
-
break;
|
|
43
|
-
case 'deprecated':
|
|
44
|
-
deprecated = comment.trim() || 'true';
|
|
45
|
-
break;
|
|
46
|
-
case 'throws':
|
|
47
|
-
case 'throw':
|
|
48
|
-
throws.push(comment);
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return { description, params, returns, since, deprecated, throws };
|
|
53
|
-
}
|
|
54
|
-
function getLineNumber(node, sourceFile) {
|
|
55
|
-
return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;
|
|
56
|
-
}
|
|
57
|
-
function findTsFiles(dir) {
|
|
58
|
-
const files = [];
|
|
59
|
-
const entries = readdirSync(dir);
|
|
60
|
-
for (const entry of entries) {
|
|
61
|
-
if (entry === 'node_modules' || entry.startsWith('.'))
|
|
62
|
-
continue;
|
|
63
|
-
const fullPath = resolve(dir, entry);
|
|
64
|
-
const stat = statSync(fullPath);
|
|
65
|
-
if (stat.isDirectory()) {
|
|
66
|
-
files.push(...findTsFiles(fullPath));
|
|
67
|
-
}
|
|
68
|
-
else if (/\.tsx?$/.test(entry) && !entry.endsWith('.d.ts') && !entry.endsWith('.test.ts') && !entry.endsWith('.spec.ts')) {
|
|
69
|
-
files.push(fullPath);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return files;
|
|
73
|
-
}
|
|
74
|
-
export class TypeScriptExtractor {
|
|
75
|
-
program;
|
|
76
|
-
checker;
|
|
77
|
-
rootDir;
|
|
78
|
-
sourceUrl;
|
|
79
|
-
constructor(rootDir, sourceUrl) {
|
|
80
|
-
this.rootDir = resolve(rootDir);
|
|
81
|
-
this.sourceUrl = sourceUrl;
|
|
82
|
-
const configPath = ts.findConfigFile(this.rootDir, ts.sys.fileExists, 'tsconfig.json');
|
|
83
|
-
if (configPath) {
|
|
84
|
-
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
85
|
-
const parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, dirname(configPath));
|
|
86
|
-
this.program = ts.createProgram(parsed.fileNames, parsed.options);
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
const files = findTsFiles(this.rootDir);
|
|
90
|
-
this.program = ts.createProgram(files, {
|
|
91
|
-
target: ts.ScriptTarget.ESNext,
|
|
92
|
-
module: ts.ModuleKind.NodeNext,
|
|
93
|
-
moduleResolution: ts.ModuleResolutionKind.NodeNext,
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
this.checker = this.program.getTypeChecker();
|
|
97
|
-
}
|
|
98
|
-
extractFile(filePath) {
|
|
99
|
-
const absPath = resolve(filePath);
|
|
100
|
-
const sourceFile = this.program.getSourceFile(absPath);
|
|
101
|
-
if (!sourceFile)
|
|
102
|
-
return { symbols: [], filePath: absPath };
|
|
103
|
-
const fileSymbol = this.checker.getSymbolAtLocation(sourceFile);
|
|
104
|
-
if (!fileSymbol)
|
|
105
|
-
return { symbols: [], filePath: absPath };
|
|
106
|
-
const exports = this.checker.getExportsOfModule(fileSymbol);
|
|
107
|
-
const symbols = [];
|
|
108
|
-
for (const exp of exports) {
|
|
109
|
-
const doc = this.extractExport(exp, sourceFile);
|
|
110
|
-
if (doc)
|
|
111
|
-
symbols.push(doc);
|
|
112
|
-
}
|
|
113
|
-
return { symbols, filePath: absPath };
|
|
114
|
-
}
|
|
115
|
-
extractExport(symbol, sourceFile) {
|
|
116
|
-
// Resolve aliases (re-exports)
|
|
117
|
-
let resolved = symbol;
|
|
118
|
-
if (resolved.flags & ts.SymbolFlags.Alias) {
|
|
119
|
-
resolved = this.checker.getAliasedSymbol(resolved);
|
|
120
|
-
}
|
|
121
|
-
const declarations = resolved.getDeclarations();
|
|
122
|
-
if (!declarations || declarations.length === 0)
|
|
123
|
-
return null;
|
|
124
|
-
const decl = declarations[0];
|
|
125
|
-
// Skip re-exports from other files
|
|
126
|
-
if (decl.getSourceFile() !== sourceFile)
|
|
127
|
-
return null;
|
|
128
|
-
const name = symbol.getName();
|
|
129
|
-
if (ts.isFunctionDeclaration(decl)) {
|
|
130
|
-
return this.extractFunction(name, resolved, decl, sourceFile);
|
|
131
|
-
}
|
|
132
|
-
if (ts.isClassDeclaration(decl)) {
|
|
133
|
-
return this.extractClass(name, resolved, decl, sourceFile);
|
|
134
|
-
}
|
|
135
|
-
if (ts.isInterfaceDeclaration(decl)) {
|
|
136
|
-
return this.extractInterface(name, resolved, decl, sourceFile);
|
|
137
|
-
}
|
|
138
|
-
if (ts.isEnumDeclaration(decl)) {
|
|
139
|
-
return this.extractEnum(name, resolved, decl, sourceFile);
|
|
140
|
-
}
|
|
141
|
-
if (ts.isTypeAliasDeclaration(decl)) {
|
|
142
|
-
return this.extractTypeAlias(name, resolved, decl, sourceFile);
|
|
143
|
-
}
|
|
144
|
-
if (ts.isVariableDeclaration(decl)) {
|
|
145
|
-
return this.extractVariable(name, resolved, decl, sourceFile);
|
|
146
|
-
}
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
extractFunction(name, symbol, decl, sourceFile) {
|
|
150
|
-
const jsDoc = extractJSDoc(decl);
|
|
151
|
-
const kind = name.startsWith('use') && /^use[A-Z]/.test(name) ? 'hook' : 'function';
|
|
152
|
-
const type = this.checker.getTypeOfSymbolAtLocation(symbol, decl);
|
|
153
|
-
const signatures = type.getCallSignatures();
|
|
154
|
-
const signature = signatures.length > 0
|
|
155
|
-
? this.checker.signatureToString(signatures[0], decl, ts.TypeFormatFlags.WriteArrowStyleSignature | ts.TypeFormatFlags.NoTruncation)
|
|
156
|
-
: this.checker.typeToString(type, decl, ts.TypeFormatFlags.NoTruncation);
|
|
157
|
-
const parameters = this.extractParameters(decl.parameters, jsDoc);
|
|
158
|
-
const returns = this.extractReturn(signatures[0], jsDoc);
|
|
159
|
-
const throws = this.extractThrows(jsDoc);
|
|
160
|
-
return {
|
|
161
|
-
name, kind, signature,
|
|
162
|
-
description: jsDoc.description,
|
|
163
|
-
parameters: parameters.length > 0 ? parameters : undefined,
|
|
164
|
-
returns, throws: throws.length > 0 ? throws : undefined,
|
|
165
|
-
since: jsDoc.since, deprecated: jsDoc.deprecated,
|
|
166
|
-
source: this.buildSourceUrl(sourceFile.fileName, getLineNumber(decl, sourceFile)),
|
|
167
|
-
filePath: sourceFile.fileName,
|
|
168
|
-
line: getLineNumber(decl, sourceFile),
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
extractVariable(name, symbol, decl, sourceFile) {
|
|
172
|
-
const type = this.checker.getTypeOfSymbolAtLocation(symbol, decl);
|
|
173
|
-
const callSigs = type.getCallSignatures();
|
|
174
|
-
// If the variable is a function (arrow function or function expression)
|
|
175
|
-
if (callSigs.length > 0) {
|
|
176
|
-
// Get JSDoc from the variable statement, not the declaration
|
|
177
|
-
const varStatement = decl.parent?.parent;
|
|
178
|
-
const jsDoc = varStatement ? extractJSDoc(varStatement) : extractJSDoc(decl);
|
|
179
|
-
const kind = name.startsWith('use') && /^use[A-Z]/.test(name) ? 'hook' : 'function';
|
|
180
|
-
const signature = this.checker.signatureToString(callSigs[0], decl, ts.TypeFormatFlags.WriteArrowStyleSignature | ts.TypeFormatFlags.NoTruncation);
|
|
181
|
-
// Try to get parameters from the initializer if it's an arrow function
|
|
182
|
-
let parameters = [];
|
|
183
|
-
if (decl.initializer && (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))) {
|
|
184
|
-
parameters = this.extractParameters(decl.initializer.parameters, jsDoc);
|
|
185
|
-
}
|
|
186
|
-
const returns = this.extractReturn(callSigs[0], jsDoc);
|
|
187
|
-
const throws = this.extractThrows(jsDoc);
|
|
188
|
-
return {
|
|
189
|
-
name, kind, signature,
|
|
190
|
-
description: jsDoc.description,
|
|
191
|
-
parameters: parameters.length > 0 ? parameters : undefined,
|
|
192
|
-
returns, throws: throws.length > 0 ? throws : undefined,
|
|
193
|
-
since: jsDoc.since, deprecated: jsDoc.deprecated,
|
|
194
|
-
source: this.buildSourceUrl(sourceFile.fileName, getLineNumber(decl, sourceFile)),
|
|
195
|
-
filePath: sourceFile.fileName,
|
|
196
|
-
line: getLineNumber(decl, sourceFile),
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
// Non-function variable — treat as a constant/value
|
|
200
|
-
const varStatement = decl.parent?.parent;
|
|
201
|
-
const jsDoc = varStatement ? extractJSDoc(varStatement) : extractJSDoc(decl);
|
|
202
|
-
const typeStr = this.checker.typeToString(type, decl, ts.TypeFormatFlags.NoTruncation);
|
|
203
|
-
return {
|
|
204
|
-
name, kind: 'function', // use 'function' kind for exported constants since there's no 'const' kind
|
|
205
|
-
signature: `const ${name}: ${typeStr}`,
|
|
206
|
-
description: jsDoc.description,
|
|
207
|
-
since: jsDoc.since, deprecated: jsDoc.deprecated,
|
|
208
|
-
source: this.buildSourceUrl(sourceFile.fileName, getLineNumber(decl, sourceFile)),
|
|
209
|
-
filePath: sourceFile.fileName,
|
|
210
|
-
line: getLineNumber(decl, sourceFile),
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
extractClass(name, _symbol, decl, sourceFile) {
|
|
214
|
-
const jsDoc = extractJSDoc(decl);
|
|
215
|
-
// Build class signature
|
|
216
|
-
let signature = `class ${name}`;
|
|
217
|
-
if (decl.heritageClauses) {
|
|
218
|
-
for (const clause of decl.heritageClauses) {
|
|
219
|
-
const keyword = clause.token === ts.SyntaxKind.ExtendsKeyword ? 'extends' : 'implements';
|
|
220
|
-
const types = clause.types.map(t => t.getText(sourceFile)).join(', ');
|
|
221
|
-
signature += ` ${keyword} ${types}`;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
const groups = this.extractClassMembers(decl, sourceFile);
|
|
225
|
-
return {
|
|
226
|
-
name, kind: 'class', signature,
|
|
227
|
-
description: jsDoc.description,
|
|
228
|
-
groups: groups.length > 0 ? groups : undefined,
|
|
229
|
-
since: jsDoc.since, deprecated: jsDoc.deprecated,
|
|
230
|
-
source: this.buildSourceUrl(sourceFile.fileName, getLineNumber(decl, sourceFile)),
|
|
231
|
-
filePath: sourceFile.fileName,
|
|
232
|
-
line: getLineNumber(decl, sourceFile),
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
extractClassMembers(decl, sourceFile) {
|
|
236
|
-
const constructors = [];
|
|
237
|
-
const properties = [];
|
|
238
|
-
const methods = [];
|
|
239
|
-
const staticProperties = [];
|
|
240
|
-
const staticMethods = [];
|
|
241
|
-
const accessors = [];
|
|
242
|
-
for (const member of decl.members) {
|
|
243
|
-
if (this.isPrivateOrProtected(member))
|
|
244
|
-
continue;
|
|
245
|
-
const isStatic = this.hasModifier(member, ts.SyntaxKind.StaticKeyword);
|
|
246
|
-
if (ts.isConstructorDeclaration(member)) {
|
|
247
|
-
constructors.push(this.extractMemberDoc(member, 'constructor', sourceFile));
|
|
248
|
-
}
|
|
249
|
-
else if (ts.isPropertyDeclaration(member)) {
|
|
250
|
-
const doc = this.extractMemberDoc(member, 'property', sourceFile);
|
|
251
|
-
if (isStatic)
|
|
252
|
-
staticProperties.push(doc);
|
|
253
|
-
else
|
|
254
|
-
properties.push(doc);
|
|
255
|
-
}
|
|
256
|
-
else if (ts.isMethodDeclaration(member)) {
|
|
257
|
-
const doc = this.extractMemberDoc(member, 'method', sourceFile);
|
|
258
|
-
if (isStatic)
|
|
259
|
-
staticMethods.push(doc);
|
|
260
|
-
else
|
|
261
|
-
methods.push(doc);
|
|
262
|
-
}
|
|
263
|
-
else if (ts.isGetAccessorDeclaration(member) || ts.isSetAccessorDeclaration(member)) {
|
|
264
|
-
accessors.push(this.extractMemberDoc(member, 'accessor', sourceFile));
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
const groups = [];
|
|
268
|
-
if (constructors.length > 0)
|
|
269
|
-
groups.push({ label: 'Constructor', members: constructors });
|
|
270
|
-
if (properties.length > 0)
|
|
271
|
-
groups.push({ label: 'Properties', members: properties });
|
|
272
|
-
if (methods.length > 0)
|
|
273
|
-
groups.push({ label: 'Methods', members: methods });
|
|
274
|
-
if (staticProperties.length > 0)
|
|
275
|
-
groups.push({ label: 'Static Properties', members: staticProperties });
|
|
276
|
-
if (staticMethods.length > 0)
|
|
277
|
-
groups.push({ label: 'Static Methods', members: staticMethods });
|
|
278
|
-
if (accessors.length > 0)
|
|
279
|
-
groups.push({ label: 'Accessors', members: accessors });
|
|
280
|
-
return groups;
|
|
281
|
-
}
|
|
282
|
-
extractInterface(name, _symbol, decl, sourceFile) {
|
|
283
|
-
const jsDoc = extractJSDoc(decl);
|
|
284
|
-
let signature = `interface ${name}`;
|
|
285
|
-
if (decl.heritageClauses) {
|
|
286
|
-
for (const clause of decl.heritageClauses) {
|
|
287
|
-
const types = clause.types.map(t => t.getText(sourceFile)).join(', ');
|
|
288
|
-
signature += ` extends ${types}`;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
if (decl.typeParameters && decl.typeParameters.length > 0) {
|
|
292
|
-
const params = decl.typeParameters.map(tp => tp.getText(sourceFile)).join(', ');
|
|
293
|
-
signature = `interface ${name}<${params}>` + signature.slice(`interface ${name}`.length);
|
|
294
|
-
}
|
|
295
|
-
const groups = this.extractInterfaceMembers(decl, sourceFile);
|
|
296
|
-
return {
|
|
297
|
-
name, kind: 'interface', signature,
|
|
298
|
-
description: jsDoc.description,
|
|
299
|
-
groups: groups.length > 0 ? groups : undefined,
|
|
300
|
-
since: jsDoc.since, deprecated: jsDoc.deprecated,
|
|
301
|
-
source: this.buildSourceUrl(sourceFile.fileName, getLineNumber(decl, sourceFile)),
|
|
302
|
-
filePath: sourceFile.fileName,
|
|
303
|
-
line: getLineNumber(decl, sourceFile),
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
extractInterfaceMembers(decl, sourceFile) {
|
|
307
|
-
const properties = [];
|
|
308
|
-
const methods = [];
|
|
309
|
-
const indexSignatures = [];
|
|
310
|
-
for (const member of decl.members) {
|
|
311
|
-
if (ts.isPropertySignature(member)) {
|
|
312
|
-
properties.push(this.extractMemberDoc(member, 'property', sourceFile));
|
|
313
|
-
}
|
|
314
|
-
else if (ts.isMethodSignature(member)) {
|
|
315
|
-
methods.push(this.extractMemberDoc(member, 'method', sourceFile));
|
|
316
|
-
}
|
|
317
|
-
else if (ts.isIndexSignatureDeclaration(member)) {
|
|
318
|
-
indexSignatures.push(this.extractMemberDoc(member, 'index-signature', sourceFile));
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
const groups = [];
|
|
322
|
-
if (properties.length > 0)
|
|
323
|
-
groups.push({ label: 'Properties', members: properties });
|
|
324
|
-
if (methods.length > 0)
|
|
325
|
-
groups.push({ label: 'Methods', members: methods });
|
|
326
|
-
if (indexSignatures.length > 0)
|
|
327
|
-
groups.push({ label: 'Index Signatures', members: indexSignatures });
|
|
328
|
-
return groups;
|
|
329
|
-
}
|
|
330
|
-
extractEnum(name, _symbol, decl, sourceFile) {
|
|
331
|
-
const jsDoc = extractJSDoc(decl);
|
|
332
|
-
const parameters = [];
|
|
333
|
-
for (const member of decl.members) {
|
|
334
|
-
const memberName = member.name.getText(sourceFile);
|
|
335
|
-
const memberJsDoc = extractJSDoc(member);
|
|
336
|
-
let value = '';
|
|
337
|
-
if (member.initializer) {
|
|
338
|
-
value = member.initializer.getText(sourceFile);
|
|
339
|
-
}
|
|
340
|
-
else {
|
|
341
|
-
// Computed enum value
|
|
342
|
-
const memberSymbol = this.checker.getSymbolAtLocation(member.name);
|
|
343
|
-
if (memberSymbol) {
|
|
344
|
-
const constantValue = this.checker.getConstantValue(member);
|
|
345
|
-
if (constantValue !== undefined) {
|
|
346
|
-
value = typeof constantValue === 'string' ? `"${constantValue}"` : String(constantValue);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
parameters.push({
|
|
351
|
-
name: memberName,
|
|
352
|
-
type: value,
|
|
353
|
-
description: memberJsDoc.description,
|
|
354
|
-
optional: false,
|
|
355
|
-
});
|
|
356
|
-
}
|
|
357
|
-
return {
|
|
358
|
-
name, kind: 'enum',
|
|
359
|
-
signature: `enum ${name}`,
|
|
360
|
-
description: jsDoc.description,
|
|
361
|
-
parameters: parameters.length > 0 ? parameters : undefined,
|
|
362
|
-
since: jsDoc.since, deprecated: jsDoc.deprecated,
|
|
363
|
-
source: this.buildSourceUrl(sourceFile.fileName, getLineNumber(decl, sourceFile)),
|
|
364
|
-
filePath: sourceFile.fileName,
|
|
365
|
-
line: getLineNumber(decl, sourceFile),
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
|
-
extractTypeAlias(name, _symbol, decl, sourceFile) {
|
|
369
|
-
const jsDoc = extractJSDoc(decl);
|
|
370
|
-
const typeNode = decl.type;
|
|
371
|
-
const typeText = typeNode.getText(sourceFile);
|
|
372
|
-
let signature = `type ${name}`;
|
|
373
|
-
if (decl.typeParameters && decl.typeParameters.length > 0) {
|
|
374
|
-
const params = decl.typeParameters.map(tp => tp.getText(sourceFile)).join(', ');
|
|
375
|
-
signature += `<${params}>`;
|
|
376
|
-
}
|
|
377
|
-
signature += ` = ${typeText}`;
|
|
378
|
-
return {
|
|
379
|
-
name, kind: 'type', signature,
|
|
380
|
-
description: jsDoc.description,
|
|
381
|
-
since: jsDoc.since, deprecated: jsDoc.deprecated,
|
|
382
|
-
source: this.buildSourceUrl(sourceFile.fileName, getLineNumber(decl, sourceFile)),
|
|
383
|
-
filePath: sourceFile.fileName,
|
|
384
|
-
line: getLineNumber(decl, sourceFile),
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
extractMemberDoc(member, kind, sourceFile) {
|
|
388
|
-
const jsDoc = extractJSDoc(member);
|
|
389
|
-
let name = '';
|
|
390
|
-
let signature = '';
|
|
391
|
-
let parameters;
|
|
392
|
-
let returns;
|
|
393
|
-
let throws;
|
|
394
|
-
if (ts.isConstructorDeclaration(member)) {
|
|
395
|
-
name = 'constructor';
|
|
396
|
-
const paramTexts = member.parameters.map(p => p.getText(sourceFile)).join(', ');
|
|
397
|
-
signature = `new (${paramTexts})`;
|
|
398
|
-
parameters = this.extractParameters(member.parameters, jsDoc);
|
|
399
|
-
}
|
|
400
|
-
else if (ts.isMethodDeclaration(member) || ts.isMethodSignature(member)) {
|
|
401
|
-
name = member.name?.getText(sourceFile) ?? '';
|
|
402
|
-
const memberSymbol = member.name ? this.checker.getSymbolAtLocation(member.name) : undefined;
|
|
403
|
-
if (memberSymbol) {
|
|
404
|
-
const type = this.checker.getTypeOfSymbolAtLocation(memberSymbol, member);
|
|
405
|
-
const callSigs = type.getCallSignatures();
|
|
406
|
-
if (callSigs.length > 0) {
|
|
407
|
-
signature = `${name}${this.checker.signatureToString(callSigs[0], member, ts.TypeFormatFlags.NoTruncation)}`;
|
|
408
|
-
}
|
|
409
|
-
else {
|
|
410
|
-
signature = member.getText(sourceFile);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
else {
|
|
414
|
-
signature = member.getText(sourceFile);
|
|
415
|
-
}
|
|
416
|
-
if ('parameters' in member) {
|
|
417
|
-
parameters = this.extractParameters(member.parameters, jsDoc);
|
|
418
|
-
}
|
|
419
|
-
const memberSymbol2 = member.name ? this.checker.getSymbolAtLocation(member.name) : undefined;
|
|
420
|
-
if (memberSymbol2) {
|
|
421
|
-
const type = this.checker.getTypeOfSymbolAtLocation(memberSymbol2, member);
|
|
422
|
-
const callSigs = type.getCallSignatures();
|
|
423
|
-
if (callSigs.length > 0) {
|
|
424
|
-
returns = this.extractReturn(callSigs[0], jsDoc);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
const throwsDocs = this.extractThrows(jsDoc);
|
|
428
|
-
if (throwsDocs.length > 0)
|
|
429
|
-
throws = throwsDocs;
|
|
430
|
-
}
|
|
431
|
-
else if (ts.isPropertyDeclaration(member) || ts.isPropertySignature(member)) {
|
|
432
|
-
name = member.name?.getText(sourceFile) ?? '';
|
|
433
|
-
const memberSymbol = member.name ? this.checker.getSymbolAtLocation(member.name) : undefined;
|
|
434
|
-
if (memberSymbol) {
|
|
435
|
-
const type = this.checker.getTypeOfSymbolAtLocation(memberSymbol, member);
|
|
436
|
-
const typeStr = this.checker.typeToString(type, member, ts.TypeFormatFlags.NoTruncation);
|
|
437
|
-
const optional = member.questionToken ? '?' : '';
|
|
438
|
-
signature = `${name}${optional}: ${typeStr}`;
|
|
439
|
-
}
|
|
440
|
-
else {
|
|
441
|
-
signature = member.getText(sourceFile);
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
else if (ts.isGetAccessorDeclaration(member)) {
|
|
445
|
-
name = member.name?.getText(sourceFile) ?? '';
|
|
446
|
-
const memberSymbol = member.name ? this.checker.getSymbolAtLocation(member.name) : undefined;
|
|
447
|
-
if (memberSymbol) {
|
|
448
|
-
const type = this.checker.getTypeOfSymbolAtLocation(memberSymbol, member);
|
|
449
|
-
const typeStr = this.checker.typeToString(type, member, ts.TypeFormatFlags.NoTruncation);
|
|
450
|
-
signature = `get ${name}(): ${typeStr}`;
|
|
451
|
-
}
|
|
452
|
-
else {
|
|
453
|
-
signature = member.getText(sourceFile);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
else if (ts.isSetAccessorDeclaration(member)) {
|
|
457
|
-
name = member.name?.getText(sourceFile) ?? '';
|
|
458
|
-
signature = member.getText(sourceFile);
|
|
459
|
-
}
|
|
460
|
-
else if (ts.isIndexSignatureDeclaration(member)) {
|
|
461
|
-
name = '[index]';
|
|
462
|
-
signature = member.getText(sourceFile);
|
|
463
|
-
}
|
|
464
|
-
return {
|
|
465
|
-
name, kind, signature,
|
|
466
|
-
description: jsDoc.description,
|
|
467
|
-
parameters: parameters && parameters.length > 0 ? parameters : undefined,
|
|
468
|
-
returns, throws,
|
|
469
|
-
since: jsDoc.since, deprecated: jsDoc.deprecated,
|
|
470
|
-
};
|
|
471
|
-
}
|
|
472
|
-
extractParameters(params, jsDoc) {
|
|
473
|
-
return params.map(param => {
|
|
474
|
-
const name = param.name.getText();
|
|
475
|
-
const paramSymbol = this.checker.getSymbolAtLocation(param.name);
|
|
476
|
-
let type = 'unknown';
|
|
477
|
-
if (paramSymbol) {
|
|
478
|
-
const paramType = this.checker.getTypeOfSymbolAtLocation(paramSymbol, param);
|
|
479
|
-
type = this.checker.typeToString(paramType, param, ts.TypeFormatFlags.NoTruncation);
|
|
480
|
-
}
|
|
481
|
-
else if (param.type) {
|
|
482
|
-
type = param.type.getText();
|
|
483
|
-
}
|
|
484
|
-
const optional = !!param.questionToken || !!param.initializer;
|
|
485
|
-
let defaultValue;
|
|
486
|
-
if (param.initializer) {
|
|
487
|
-
defaultValue = param.initializer.getText();
|
|
488
|
-
}
|
|
489
|
-
const description = jsDoc.params.get(name) ?? '';
|
|
490
|
-
// Check for destructured object parameters with documented children
|
|
491
|
-
let children;
|
|
492
|
-
if (ts.isObjectBindingPattern(param.name)) {
|
|
493
|
-
children = param.name.elements.map(element => {
|
|
494
|
-
const childName = element.name.getText();
|
|
495
|
-
const childDesc = jsDoc.params.get(`${name}.${childName}`) ?? jsDoc.params.get(childName) ?? '';
|
|
496
|
-
const childSymbol = this.checker.getSymbolAtLocation(element.name);
|
|
497
|
-
let childType = 'unknown';
|
|
498
|
-
if (childSymbol) {
|
|
499
|
-
const ct = this.checker.getTypeOfSymbolAtLocation(childSymbol, element);
|
|
500
|
-
childType = this.checker.typeToString(ct, element, ts.TypeFormatFlags.NoTruncation);
|
|
501
|
-
}
|
|
502
|
-
return {
|
|
503
|
-
name: childName,
|
|
504
|
-
type: childType,
|
|
505
|
-
description: childDesc,
|
|
506
|
-
optional: !!element.dotDotDotToken || !!element.initializer,
|
|
507
|
-
defaultValue: element.initializer?.getText(),
|
|
508
|
-
};
|
|
509
|
-
});
|
|
510
|
-
}
|
|
511
|
-
return { name, type, description, optional, defaultValue, children };
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
extractReturn(signature, jsDoc) {
|
|
515
|
-
if (!signature)
|
|
516
|
-
return undefined;
|
|
517
|
-
const returnType = this.checker.getReturnTypeOfSignature(signature);
|
|
518
|
-
const typeStr = this.checker.typeToString(returnType, undefined, ts.TypeFormatFlags.NoTruncation);
|
|
519
|
-
if (typeStr === 'void' && !jsDoc.returns)
|
|
520
|
-
return undefined;
|
|
521
|
-
return {
|
|
522
|
-
type: typeStr,
|
|
523
|
-
description: jsDoc.returns ?? '',
|
|
524
|
-
};
|
|
525
|
-
}
|
|
526
|
-
extractThrows(jsDoc) {
|
|
527
|
-
return jsDoc.throws.map(text => {
|
|
528
|
-
// Parse "ErrorType description" or just "description"
|
|
529
|
-
const match = text.match(/^(\w+)\s+(.*)/);
|
|
530
|
-
if (match) {
|
|
531
|
-
return { type: match[1], description: match[2] };
|
|
532
|
-
}
|
|
533
|
-
return { type: 'Error', description: text };
|
|
534
|
-
});
|
|
535
|
-
}
|
|
536
|
-
isPrivateOrProtected(member) {
|
|
537
|
-
const flags = ts.getCombinedModifierFlags(member);
|
|
538
|
-
return !!(flags & (ts.ModifierFlags.Private | ts.ModifierFlags.Protected));
|
|
539
|
-
}
|
|
540
|
-
hasModifier(member, kind) {
|
|
541
|
-
// Use canHaveModifiers + getModifiers for TS 5.x compatibility
|
|
542
|
-
const node = member;
|
|
543
|
-
if (!ts.canHaveModifiers(node))
|
|
544
|
-
return false;
|
|
545
|
-
const modifiers = ts.getModifiers(node);
|
|
546
|
-
return modifiers?.some((m) => m.kind === kind) ?? false;
|
|
547
|
-
}
|
|
548
|
-
buildSourceUrl(filePath, line) {
|
|
549
|
-
if (!this.sourceUrl)
|
|
550
|
-
return undefined;
|
|
551
|
-
const rel = relative(this.rootDir, filePath).replace(/\\/g, '/');
|
|
552
|
-
return `${this.sourceUrl.replace(/\/$/, '')}/${rel}#L${line}`;
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
/** Find all TypeScript source files in a directory */
|
|
556
|
-
export function findSourceFiles(dir) {
|
|
557
|
-
const absDir = resolve(dir);
|
|
558
|
-
if (!existsSync(absDir))
|
|
559
|
-
return [];
|
|
560
|
-
const stat = statSync(absDir);
|
|
561
|
-
if (!stat.isDirectory()) {
|
|
562
|
-
return /\.tsx?$/.test(absDir) ? [absDir] : [];
|
|
563
|
-
}
|
|
564
|
-
return findTsFiles(absDir);
|
|
565
|
-
}
|
|
566
|
-
//# sourceMappingURL=typescript.js.map
|