@deplens/mcp 0.1.6 → 0.1.8
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/bin/deplens-mcp.js +0 -0
- package/package.json +6 -3
- package/src/core/changelog-parser.mjs +313 -0
- package/src/core/diff-analyzer.mjs +590 -0
- package/src/core/diff.mjs +145 -0
- package/src/core/inspect.mjs +950 -482
- package/src/core/parse-dts.mjs +198 -172
- package/src/core/parse-source.mjs +524 -0
- package/src/core/version-resolver.mjs +317 -0
- package/src/server.mjs +579 -40
package/src/core/parse-dts.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// parse-dts.mjs - TypeScript Compiler API based .d.ts parser
|
|
2
|
-
import ts from "typescript"
|
|
3
|
-
import fs from "fs"
|
|
4
|
-
import path from "path"
|
|
2
|
+
import ts from "typescript";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import path from "path";
|
|
5
5
|
|
|
6
6
|
function getScriptKind(filePath) {
|
|
7
7
|
if (typeof ts.getScriptKindFromFileName === "function") {
|
|
8
|
-
const kind = ts.getScriptKindFromFileName(filePath)
|
|
9
|
-
return kind === ts.ScriptKind.Unknown ? ts.ScriptKind.TS : kind
|
|
8
|
+
const kind = ts.getScriptKindFromFileName(filePath);
|
|
9
|
+
return kind === ts.ScriptKind.Unknown ? ts.ScriptKind.TS : kind;
|
|
10
10
|
}
|
|
11
|
-
return ts.ScriptKind.TS
|
|
11
|
+
return ts.ScriptKind.TS;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -18,71 +18,77 @@ function getScriptKind(filePath) {
|
|
|
18
18
|
* @returns {Map<string, string>} Map of symbol name -> source file path
|
|
19
19
|
*/
|
|
20
20
|
function findReExports(dtsPath, filterList) {
|
|
21
|
-
const content = fs.readFileSync(dtsPath, "utf-8")
|
|
21
|
+
const content = fs.readFileSync(dtsPath, "utf-8");
|
|
22
22
|
const sourceFile = ts.createSourceFile(
|
|
23
23
|
dtsPath,
|
|
24
24
|
content,
|
|
25
25
|
ts.ScriptTarget.Latest,
|
|
26
26
|
true,
|
|
27
27
|
getScriptKind(dtsPath),
|
|
28
|
-
)
|
|
28
|
+
);
|
|
29
29
|
|
|
30
|
-
const dtsDir = path.dirname(dtsPath)
|
|
31
|
-
const reExports = new Map()
|
|
32
|
-
const wildcardSources = []
|
|
33
|
-
const filterSet = filterList
|
|
30
|
+
const dtsDir = path.dirname(dtsPath);
|
|
31
|
+
const reExports = new Map();
|
|
32
|
+
const wildcardSources = [];
|
|
33
|
+
const filterSet = filterList
|
|
34
|
+
? new Set(filterList.map((n) => n.toLowerCase()))
|
|
35
|
+
: null;
|
|
34
36
|
|
|
35
37
|
function resolveDtsPath(moduleSpec) {
|
|
36
38
|
// Handle .cjs/.mjs/.js -> .d.cts/.d.mts/.d.ts
|
|
37
39
|
let sourceFile = moduleSpec
|
|
38
40
|
.replace(/\.cjs$/, ".d.cts")
|
|
39
41
|
.replace(/\.mjs$/, ".d.mts")
|
|
40
|
-
.replace(/\.js$/, ".d.ts")
|
|
41
|
-
if (
|
|
42
|
+
.replace(/\.js$/, ".d.ts");
|
|
43
|
+
if (
|
|
44
|
+
!sourceFile.endsWith(".d.ts") &&
|
|
45
|
+
!sourceFile.endsWith(".d.cts") &&
|
|
46
|
+
!sourceFile.endsWith(".d.mts")
|
|
47
|
+
) {
|
|
42
48
|
// Try all extensions
|
|
43
|
-
const dtsCandidate = path.resolve(dtsDir, sourceFile + ".d.ts")
|
|
44
|
-
const ctsCandidate = path.resolve(dtsDir, sourceFile + ".d.cts")
|
|
45
|
-
const mtsCandidate = path.resolve(dtsDir, sourceFile + ".d.mts")
|
|
46
|
-
if (fs.existsSync(dtsCandidate)) return dtsCandidate
|
|
47
|
-
if (fs.existsSync(ctsCandidate)) return ctsCandidate
|
|
48
|
-
if (fs.existsSync(mtsCandidate)) return mtsCandidate
|
|
49
|
-
return null
|
|
49
|
+
const dtsCandidate = path.resolve(dtsDir, sourceFile + ".d.ts");
|
|
50
|
+
const ctsCandidate = path.resolve(dtsDir, sourceFile + ".d.cts");
|
|
51
|
+
const mtsCandidate = path.resolve(dtsDir, sourceFile + ".d.mts");
|
|
52
|
+
if (fs.existsSync(dtsCandidate)) return dtsCandidate;
|
|
53
|
+
if (fs.existsSync(ctsCandidate)) return ctsCandidate;
|
|
54
|
+
if (fs.existsSync(mtsCandidate)) return mtsCandidate;
|
|
55
|
+
return null;
|
|
50
56
|
}
|
|
51
|
-
const fullPath = path.resolve(dtsDir, sourceFile)
|
|
52
|
-
return fs.existsSync(fullPath) ? fullPath : null
|
|
57
|
+
const fullPath = path.resolve(dtsDir, sourceFile);
|
|
58
|
+
return fs.existsSync(fullPath) ? fullPath : null;
|
|
53
59
|
}
|
|
54
60
|
|
|
55
61
|
function visit(node) {
|
|
56
62
|
// Handle: export { foo } from './foo.js'
|
|
57
63
|
if (ts.isExportDeclaration(node) && node.moduleSpecifier) {
|
|
58
|
-
const moduleSpec = node.moduleSpecifier.text
|
|
64
|
+
const moduleSpec = node.moduleSpecifier.text;
|
|
59
65
|
|
|
60
66
|
if (node.exportClause && ts.isNamedExports(node.exportClause)) {
|
|
61
67
|
// Named exports
|
|
62
68
|
for (const elem of node.exportClause.elements) {
|
|
63
|
-
const exportedName = elem.name.text
|
|
69
|
+
const exportedName = elem.name.text;
|
|
64
70
|
if (!filterSet || filterSet.has(exportedName.toLowerCase())) {
|
|
65
|
-
const fullPath = resolveDtsPath(moduleSpec)
|
|
71
|
+
const fullPath = resolveDtsPath(moduleSpec);
|
|
66
72
|
if (fullPath) {
|
|
67
|
-
reExports.set(exportedName, fullPath)
|
|
73
|
+
reExports.set(exportedName, fullPath);
|
|
68
74
|
}
|
|
69
75
|
}
|
|
70
76
|
}
|
|
71
77
|
} else if (!node.exportClause) {
|
|
72
78
|
// Wildcard: export * from './module'
|
|
73
|
-
const fullPath = resolveDtsPath(moduleSpec)
|
|
79
|
+
const fullPath = resolveDtsPath(moduleSpec);
|
|
74
80
|
if (fullPath) {
|
|
75
|
-
wildcardSources.push(fullPath)
|
|
81
|
+
wildcardSources.push(fullPath);
|
|
76
82
|
}
|
|
77
83
|
}
|
|
78
84
|
}
|
|
79
|
-
ts.forEachChild(node, visit)
|
|
85
|
+
ts.forEachChild(node, visit);
|
|
80
86
|
}
|
|
81
87
|
|
|
82
|
-
visit(sourceFile)
|
|
88
|
+
visit(sourceFile);
|
|
83
89
|
|
|
84
90
|
// For wildcard exports, we return them all as potential sources
|
|
85
|
-
return { named: reExports, wildcards: wildcardSources }
|
|
91
|
+
return { named: reExports, wildcards: wildcardSources };
|
|
86
92
|
}
|
|
87
93
|
|
|
88
94
|
/**
|
|
@@ -93,21 +99,21 @@ function findReExports(dtsPath, filterList) {
|
|
|
93
99
|
*/
|
|
94
100
|
export function parseDtsFile(dtsPath, filterList, visited = new Set()) {
|
|
95
101
|
if (!fs.existsSync(dtsPath)) {
|
|
96
|
-
return null
|
|
102
|
+
return null;
|
|
97
103
|
}
|
|
98
104
|
if (visited.has(dtsPath)) {
|
|
99
|
-
return null
|
|
105
|
+
return null;
|
|
100
106
|
}
|
|
101
|
-
visited.add(dtsPath)
|
|
107
|
+
visited.add(dtsPath);
|
|
102
108
|
|
|
103
|
-
const content = fs.readFileSync(dtsPath, "utf-8")
|
|
109
|
+
const content = fs.readFileSync(dtsPath, "utf-8");
|
|
104
110
|
const sourceFile = ts.createSourceFile(
|
|
105
111
|
dtsPath,
|
|
106
112
|
content,
|
|
107
113
|
ts.ScriptTarget.Latest,
|
|
108
114
|
true,
|
|
109
115
|
getScriptKind(dtsPath),
|
|
110
|
-
)
|
|
116
|
+
);
|
|
111
117
|
|
|
112
118
|
const typeInfo = {
|
|
113
119
|
functions: {},
|
|
@@ -118,205 +124,225 @@ export function parseDtsFile(dtsPath, filterList, visited = new Set()) {
|
|
|
118
124
|
namespaces: {},
|
|
119
125
|
defaults: [],
|
|
120
126
|
jsdoc: {},
|
|
121
|
-
}
|
|
127
|
+
};
|
|
122
128
|
|
|
123
|
-
const filterSet = filterList
|
|
129
|
+
const filterSet = filterList
|
|
130
|
+
? new Set(filterList.map((n) => n.toLowerCase()))
|
|
131
|
+
: null;
|
|
124
132
|
|
|
125
133
|
function shouldInclude(name) {
|
|
126
|
-
if (!filterSet) return true
|
|
127
|
-
return filterSet.has(name.toLowerCase())
|
|
134
|
+
if (!filterSet) return true;
|
|
135
|
+
return filterSet.has(name.toLowerCase());
|
|
128
136
|
}
|
|
129
137
|
|
|
130
138
|
function getNodeText(node) {
|
|
131
|
-
return node.getText(sourceFile)
|
|
139
|
+
return node.getText(sourceFile);
|
|
132
140
|
}
|
|
133
141
|
|
|
134
142
|
function formatType(typeNode, maxLen = 80) {
|
|
135
|
-
if (!typeNode) return "any"
|
|
136
|
-
const text = getNodeText(typeNode).replace(/\s+/g, " ").trim()
|
|
137
|
-
return text.length > maxLen ? text.substring(0, maxLen) + "..." : text
|
|
143
|
+
if (!typeNode) return "any";
|
|
144
|
+
const text = getNodeText(typeNode).replace(/\s+/g, " ").trim();
|
|
145
|
+
return text.length > maxLen ? text.substring(0, maxLen) + "..." : text;
|
|
138
146
|
}
|
|
139
147
|
|
|
140
148
|
function formatParams(params) {
|
|
141
|
-
if (!params || params.length === 0) return ""
|
|
149
|
+
if (!params || params.length === 0) return "";
|
|
142
150
|
|
|
143
151
|
// For complex destructuring, simplify
|
|
144
152
|
const paramStrs = params.map((p) => {
|
|
145
|
-
const name = p.name ? getNodeText(p.name) : "arg"
|
|
153
|
+
const name = p.name ? getNodeText(p.name) : "arg";
|
|
146
154
|
|
|
147
155
|
// Handle destructuring pattern - just show "options"
|
|
148
156
|
if (name.startsWith("{")) {
|
|
149
|
-
return "options: object"
|
|
157
|
+
return "options: object";
|
|
150
158
|
}
|
|
151
159
|
|
|
152
|
-
const optional = p.questionToken ? "?" : ""
|
|
153
|
-
const type = p.type ? formatType(p.type, 40) : "any"
|
|
160
|
+
const optional = p.questionToken ? "?" : "";
|
|
161
|
+
const type = p.type ? formatType(p.type, 40) : "any";
|
|
154
162
|
|
|
155
163
|
// Simplify long type names
|
|
156
|
-
const shortType = type.length > 40 ? type.split("<")[0] + "<...>" : type
|
|
157
|
-
return `${name}${optional}: ${shortType}
|
|
158
|
-
})
|
|
164
|
+
const shortType = type.length > 40 ? type.split("<")[0] + "<...>" : type;
|
|
165
|
+
return `${name}${optional}: ${shortType}`;
|
|
166
|
+
});
|
|
159
167
|
|
|
160
168
|
// If total length too long, just show count
|
|
161
|
-
const joined = paramStrs.join(", ")
|
|
169
|
+
const joined = paramStrs.join(", ");
|
|
162
170
|
if (joined.length > 100) {
|
|
163
|
-
return `${params.length} param${params.length > 1 ? "s" : ""}
|
|
171
|
+
return `${params.length} param${params.length > 1 ? "s" : ""}`;
|
|
164
172
|
}
|
|
165
|
-
return joined
|
|
173
|
+
return joined;
|
|
166
174
|
}
|
|
167
175
|
|
|
168
176
|
function jsDocText(comment) {
|
|
169
|
-
if (!comment) return ""
|
|
170
|
-
if (typeof comment === "string") return comment.trim()
|
|
177
|
+
if (!comment) return "";
|
|
178
|
+
if (typeof comment === "string") return comment.trim();
|
|
171
179
|
if (Array.isArray(comment)) {
|
|
172
|
-
return comment
|
|
180
|
+
return comment
|
|
181
|
+
.map((part) => part.text || "")
|
|
182
|
+
.join("")
|
|
183
|
+
.trim();
|
|
173
184
|
}
|
|
174
|
-
return ""
|
|
185
|
+
return "";
|
|
175
186
|
}
|
|
176
187
|
|
|
177
188
|
function collectJSDocTags(tagNodes) {
|
|
178
|
-
const tags = {}
|
|
179
|
-
if (!tagNodes || tagNodes.length === 0) return tags
|
|
189
|
+
const tags = {};
|
|
190
|
+
if (!tagNodes || tagNodes.length === 0) return tags;
|
|
180
191
|
for (const tag of tagNodes) {
|
|
181
|
-
if (!tag?.tagName?.text) continue
|
|
182
|
-
const tagName = tag.tagName.text
|
|
183
|
-
const comment = jsDocText(tag.comment)
|
|
184
|
-
if (!tags[tagName]) tags[tagName] = []
|
|
185
|
-
tags[tagName].push(comment || "")
|
|
192
|
+
if (!tag?.tagName?.text) continue;
|
|
193
|
+
const tagName = tag.tagName.text;
|
|
194
|
+
const comment = jsDocText(tag.comment);
|
|
195
|
+
if (!tags[tagName]) tags[tagName] = [];
|
|
196
|
+
tags[tagName].push(comment || "");
|
|
186
197
|
}
|
|
187
|
-
return tags
|
|
198
|
+
return tags;
|
|
188
199
|
}
|
|
189
200
|
|
|
190
201
|
function extractJSDoc(node) {
|
|
191
|
-
const entries = ts.getJSDocCommentsAndTags(node)
|
|
192
|
-
if (!entries || entries.length === 0) return null
|
|
193
|
-
let summary = ""
|
|
194
|
-
const tags = {}
|
|
202
|
+
const entries = ts.getJSDocCommentsAndTags(node);
|
|
203
|
+
if (!entries || entries.length === 0) return null;
|
|
204
|
+
let summary = "";
|
|
205
|
+
const tags = {};
|
|
195
206
|
for (const entry of entries) {
|
|
196
207
|
if (ts.isJSDoc(entry)) {
|
|
197
|
-
if (!summary) summary = jsDocText(entry.comment)
|
|
198
|
-
const entryTags = collectJSDocTags(entry.tags)
|
|
208
|
+
if (!summary) summary = jsDocText(entry.comment);
|
|
209
|
+
const entryTags = collectJSDocTags(entry.tags);
|
|
199
210
|
for (const [name, values] of Object.entries(entryTags)) {
|
|
200
|
-
if (!tags[name]) tags[name] = []
|
|
201
|
-
tags[name].push(...values)
|
|
211
|
+
if (!tags[name]) tags[name] = [];
|
|
212
|
+
tags[name].push(...values);
|
|
202
213
|
}
|
|
203
214
|
} else if (ts.isJSDocTag(entry)) {
|
|
204
|
-
const tagName = entry.tagName?.text
|
|
215
|
+
const tagName = entry.tagName?.text;
|
|
205
216
|
if (tagName) {
|
|
206
|
-
const comment = jsDocText(entry.comment)
|
|
207
|
-
if (!tags[tagName]) tags[tagName] = []
|
|
208
|
-
tags[tagName].push(comment || "")
|
|
217
|
+
const comment = jsDocText(entry.comment);
|
|
218
|
+
if (!tags[tagName]) tags[tagName] = [];
|
|
219
|
+
tags[tagName].push(comment || "");
|
|
209
220
|
}
|
|
210
221
|
}
|
|
211
222
|
}
|
|
212
|
-
if (!summary && Object.keys(tags).length === 0) return null
|
|
213
|
-
return { summary, tags }
|
|
223
|
+
if (!summary && Object.keys(tags).length === 0) return null;
|
|
224
|
+
return { summary, tags };
|
|
214
225
|
}
|
|
215
226
|
|
|
216
227
|
function attachJSDoc(name, node) {
|
|
217
|
-
if (!name || !node) return
|
|
218
|
-
const doc = extractJSDoc(node)
|
|
219
|
-
if (!doc) return
|
|
220
|
-
typeInfo.jsdoc[name] = doc
|
|
228
|
+
if (!name || !node) return;
|
|
229
|
+
const doc = extractJSDoc(node);
|
|
230
|
+
if (!doc) return;
|
|
231
|
+
typeInfo.jsdoc[name] = doc;
|
|
221
232
|
}
|
|
222
233
|
|
|
223
234
|
function visit(node) {
|
|
224
235
|
// Function declarations
|
|
225
236
|
if (ts.isFunctionDeclaration(node)) {
|
|
226
|
-
const isDefault = node.modifiers?.some(
|
|
227
|
-
|
|
237
|
+
const isDefault = node.modifiers?.some(
|
|
238
|
+
(m) => m.kind === ts.SyntaxKind.DefaultKeyword,
|
|
239
|
+
);
|
|
240
|
+
const name = node.name?.text || (isDefault ? "default" : null);
|
|
228
241
|
if (name && shouldInclude(name)) {
|
|
229
|
-
const params = formatParams(node.parameters)
|
|
230
|
-
const returnType = formatType(node.type, 60)
|
|
231
|
-
typeInfo.functions[name] = { params, returnType }
|
|
232
|
-
attachJSDoc(name, node)
|
|
242
|
+
const params = formatParams(node.parameters);
|
|
243
|
+
const returnType = formatType(node.type, 60);
|
|
244
|
+
typeInfo.functions[name] = { params, returnType };
|
|
245
|
+
attachJSDoc(name, node);
|
|
233
246
|
}
|
|
234
247
|
}
|
|
235
248
|
|
|
236
249
|
// Interface declarations
|
|
237
250
|
if (ts.isInterfaceDeclaration(node)) {
|
|
238
|
-
const name = node.name.text
|
|
239
|
-
const isDefault = node.modifiers?.some(
|
|
240
|
-
|
|
251
|
+
const name = node.name.text;
|
|
252
|
+
const isDefault = node.modifiers?.some(
|
|
253
|
+
(m) => m.kind === ts.SyntaxKind.DefaultKeyword,
|
|
254
|
+
);
|
|
255
|
+
const exportName = isDefault ? "default" : name;
|
|
241
256
|
if (shouldInclude(exportName)) {
|
|
242
|
-
const props = []
|
|
257
|
+
const props = [];
|
|
243
258
|
node.members.slice(0, 5).forEach((member) => {
|
|
244
259
|
if (ts.isPropertySignature(member) && member.name) {
|
|
245
|
-
const propName = getNodeText(member.name)
|
|
246
|
-
const optional = member.questionToken ? "?" : ""
|
|
247
|
-
const propType = formatType(member.type, 30)
|
|
248
|
-
props.push(`${propName}${optional}: ${propType}`)
|
|
260
|
+
const propName = getNodeText(member.name);
|
|
261
|
+
const optional = member.questionToken ? "?" : "";
|
|
262
|
+
const propType = formatType(member.type, 30);
|
|
263
|
+
props.push(`${propName}${optional}: ${propType}`);
|
|
249
264
|
}
|
|
250
|
-
})
|
|
265
|
+
});
|
|
251
266
|
if (props.length > 0) {
|
|
252
|
-
typeInfo.interfaces[exportName] = props
|
|
253
|
-
attachJSDoc(exportName, node)
|
|
267
|
+
typeInfo.interfaces[exportName] = props;
|
|
268
|
+
attachJSDoc(exportName, node);
|
|
254
269
|
}
|
|
255
270
|
}
|
|
256
271
|
}
|
|
257
272
|
|
|
258
273
|
// Type aliases
|
|
259
274
|
if (ts.isTypeAliasDeclaration(node)) {
|
|
260
|
-
const name = node.name.text
|
|
261
|
-
const isDefault = node.modifiers?.some(
|
|
262
|
-
|
|
275
|
+
const name = node.name.text;
|
|
276
|
+
const isDefault = node.modifiers?.some(
|
|
277
|
+
(m) => m.kind === ts.SyntaxKind.DefaultKeyword,
|
|
278
|
+
);
|
|
279
|
+
const exportName = isDefault ? "default" : name;
|
|
263
280
|
if (shouldInclude(exportName)) {
|
|
264
|
-
typeInfo.types[exportName] = formatType(node.type, 80)
|
|
265
|
-
attachJSDoc(exportName, node)
|
|
281
|
+
typeInfo.types[exportName] = formatType(node.type, 80);
|
|
282
|
+
attachJSDoc(exportName, node);
|
|
266
283
|
}
|
|
267
284
|
}
|
|
268
285
|
|
|
269
286
|
// Class declarations
|
|
270
287
|
if (ts.isClassDeclaration(node)) {
|
|
271
|
-
const isDefault = node.modifiers?.some(
|
|
272
|
-
|
|
288
|
+
const isDefault = node.modifiers?.some(
|
|
289
|
+
(m) => m.kind === ts.SyntaxKind.DefaultKeyword,
|
|
290
|
+
);
|
|
291
|
+
const name = node.name?.text || (isDefault ? "default" : null);
|
|
273
292
|
if (name && shouldInclude(name)) {
|
|
274
|
-
let extendsClause = null
|
|
293
|
+
let extendsClause = null;
|
|
275
294
|
if (node.heritageClauses) {
|
|
276
295
|
for (const clause of node.heritageClauses) {
|
|
277
|
-
if (
|
|
278
|
-
|
|
296
|
+
if (
|
|
297
|
+
clause.token === ts.SyntaxKind.ExtendsKeyword &&
|
|
298
|
+
clause.types.length > 0
|
|
299
|
+
) {
|
|
300
|
+
extendsClause = getNodeText(clause.types[0].expression);
|
|
279
301
|
}
|
|
280
302
|
}
|
|
281
303
|
}
|
|
282
|
-
typeInfo.classes[name] = extendsClause
|
|
283
|
-
attachJSDoc(name, node)
|
|
304
|
+
typeInfo.classes[name] = extendsClause;
|
|
305
|
+
attachJSDoc(name, node);
|
|
284
306
|
}
|
|
285
307
|
}
|
|
286
308
|
|
|
287
309
|
// Enum declarations
|
|
288
310
|
if (ts.isEnumDeclaration(node)) {
|
|
289
|
-
const name = node.name.text
|
|
311
|
+
const name = node.name.text;
|
|
290
312
|
if (shouldInclude(name)) {
|
|
291
|
-
const members = node.members
|
|
292
|
-
|
|
293
|
-
|
|
313
|
+
const members = node.members
|
|
314
|
+
.slice(0, 5)
|
|
315
|
+
.map((member) => getNodeText(member.name));
|
|
316
|
+
typeInfo.enums[name] = members;
|
|
317
|
+
attachJSDoc(name, node);
|
|
294
318
|
}
|
|
295
319
|
}
|
|
296
320
|
|
|
297
321
|
// Namespace/module declarations
|
|
298
322
|
if (ts.isModuleDeclaration(node) && node.name) {
|
|
299
|
-
const name = getNodeText(node.name)
|
|
323
|
+
const name = getNodeText(node.name);
|
|
300
324
|
if (shouldInclude(name)) {
|
|
301
|
-
typeInfo.namespaces[name] = true
|
|
302
|
-
attachJSDoc(name, node)
|
|
325
|
+
typeInfo.namespaces[name] = true;
|
|
326
|
+
attachJSDoc(name, node);
|
|
303
327
|
}
|
|
304
328
|
}
|
|
305
329
|
|
|
306
330
|
// Variable statements (export const foo: Type)
|
|
307
331
|
if (ts.isVariableStatement(node)) {
|
|
308
|
-
const isExported = node.modifiers?.some(
|
|
332
|
+
const isExported = node.modifiers?.some(
|
|
333
|
+
(m) => m.kind === ts.SyntaxKind.ExportKeyword,
|
|
334
|
+
);
|
|
309
335
|
if (isExported && node.declarationList.declarations) {
|
|
310
336
|
for (const decl of node.declarationList.declarations) {
|
|
311
337
|
if (ts.isIdentifier(decl.name)) {
|
|
312
|
-
const name = decl.name.text
|
|
338
|
+
const name = decl.name.text;
|
|
313
339
|
if (shouldInclude(name) && decl.type) {
|
|
314
340
|
// Check if it's a function type
|
|
315
341
|
if (ts.isFunctionTypeNode(decl.type)) {
|
|
316
|
-
const params = formatParams(decl.type.parameters)
|
|
317
|
-
const returnType = formatType(decl.type.type, 60)
|
|
318
|
-
typeInfo.functions[name] = { params, returnType }
|
|
319
|
-
attachJSDoc(name, node)
|
|
342
|
+
const params = formatParams(decl.type.parameters);
|
|
343
|
+
const returnType = formatType(decl.type.type, 60);
|
|
344
|
+
typeInfo.functions[name] = { params, returnType };
|
|
345
|
+
attachJSDoc(name, node);
|
|
320
346
|
}
|
|
321
347
|
}
|
|
322
348
|
}
|
|
@@ -326,16 +352,30 @@ export function parseDtsFile(dtsPath, filterList, visited = new Set()) {
|
|
|
326
352
|
|
|
327
353
|
// export = Foo or export default Foo
|
|
328
354
|
if (ts.isExportAssignment(node)) {
|
|
329
|
-
const assignment = getNodeText(node.expression)
|
|
355
|
+
const assignment = getNodeText(node.expression);
|
|
330
356
|
if (assignment) {
|
|
331
|
-
typeInfo.defaults.push(assignment)
|
|
357
|
+
typeInfo.defaults.push(assignment);
|
|
332
358
|
}
|
|
333
359
|
}
|
|
334
360
|
|
|
335
|
-
ts.forEachChild(node, visit)
|
|
361
|
+
ts.forEachChild(node, visit);
|
|
336
362
|
}
|
|
337
363
|
|
|
338
|
-
visit(sourceFile)
|
|
364
|
+
visit(sourceFile);
|
|
365
|
+
|
|
366
|
+
const mergeTypeInfo = (source) => {
|
|
367
|
+
if (!source) return;
|
|
368
|
+
Object.assign(typeInfo.functions, source.functions);
|
|
369
|
+
Object.assign(typeInfo.interfaces, source.interfaces);
|
|
370
|
+
Object.assign(typeInfo.types, source.types);
|
|
371
|
+
Object.assign(typeInfo.classes, source.classes);
|
|
372
|
+
Object.assign(typeInfo.enums, source.enums);
|
|
373
|
+
Object.assign(typeInfo.namespaces, source.namespaces);
|
|
374
|
+
Object.assign(typeInfo.jsdoc, source.jsdoc);
|
|
375
|
+
if (Array.isArray(source.defaults)) {
|
|
376
|
+
typeInfo.defaults.push(...source.defaults);
|
|
377
|
+
}
|
|
378
|
+
};
|
|
339
379
|
|
|
340
380
|
// If we have a filter, try to follow re-exports for missing symbols
|
|
341
381
|
if (filterList && filterList.length > 0) {
|
|
@@ -346,71 +386,57 @@ export function parseDtsFile(dtsPath, filterList, visited = new Set()) {
|
|
|
346
386
|
...Object.keys(typeInfo.classes),
|
|
347
387
|
...Object.keys(typeInfo.enums),
|
|
348
388
|
...Object.keys(typeInfo.namespaces),
|
|
349
|
-
])
|
|
350
|
-
const missing = filterList.filter((name) => !found.has(name))
|
|
389
|
+
]);
|
|
390
|
+
const missing = filterList.filter((name) => !found.has(name));
|
|
351
391
|
|
|
352
392
|
if (missing.length > 0) {
|
|
353
|
-
const { named, wildcards } = findReExports(dtsPath, missing)
|
|
393
|
+
const { named, wildcards } = findReExports(dtsPath, missing);
|
|
354
394
|
|
|
355
395
|
// Try named exports first
|
|
356
|
-
for (const [
|
|
357
|
-
|
|
358
|
-
if (subResult) {
|
|
359
|
-
Object.assign(typeInfo.functions, subResult.functions)
|
|
360
|
-
Object.assign(typeInfo.interfaces, subResult.interfaces)
|
|
361
|
-
Object.assign(typeInfo.types, subResult.types)
|
|
362
|
-
Object.assign(typeInfo.classes, subResult.classes)
|
|
363
|
-
Object.assign(typeInfo.enums, subResult.enums)
|
|
364
|
-
Object.assign(typeInfo.namespaces, subResult.namespaces)
|
|
365
|
-
Object.assign(typeInfo.jsdoc, subResult.jsdoc)
|
|
366
|
-
typeInfo.defaults.push(...subResult.defaults)
|
|
367
|
-
}
|
|
396
|
+
for (const [, sourcePath] of named) {
|
|
397
|
+
mergeTypeInfo(parseDtsFile(sourcePath, missing, visited));
|
|
368
398
|
}
|
|
369
399
|
|
|
370
400
|
// If still missing, try wildcard sources
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
const subResult = parseDtsFile(wildcardPath, missing, visited)
|
|
374
|
-
if (subResult) {
|
|
375
|
-
Object.assign(typeInfo.functions, subResult.functions)
|
|
376
|
-
Object.assign(typeInfo.interfaces, subResult.interfaces)
|
|
377
|
-
Object.assign(typeInfo.types, subResult.types)
|
|
378
|
-
Object.assign(typeInfo.classes, subResult.classes)
|
|
379
|
-
Object.assign(typeInfo.enums, subResult.enums)
|
|
380
|
-
Object.assign(typeInfo.namespaces, subResult.namespaces)
|
|
381
|
-
Object.assign(typeInfo.jsdoc, subResult.jsdoc)
|
|
382
|
-
typeInfo.defaults.push(...subResult.defaults)
|
|
383
|
-
}
|
|
401
|
+
for (const wildcardPath of wildcards) {
|
|
402
|
+
mergeTypeInfo(parseDtsFile(wildcardPath, missing, visited));
|
|
384
403
|
}
|
|
385
404
|
}
|
|
386
|
-
}
|
|
405
|
+
} else if (!filterList) {
|
|
406
|
+
const { named, wildcards } = findReExports(dtsPath, null);
|
|
407
|
+
for (const [, sourcePath] of named) {
|
|
408
|
+
mergeTypeInfo(parseDtsFile(sourcePath, null, visited));
|
|
409
|
+
}
|
|
410
|
+
for (const wildcardPath of wildcards) {
|
|
411
|
+
mergeTypeInfo(parseDtsFile(wildcardPath, null, visited));
|
|
412
|
+
}
|
|
387
413
|
}
|
|
388
414
|
|
|
389
|
-
return typeInfo
|
|
415
|
+
return typeInfo;
|
|
390
416
|
}
|
|
391
417
|
|
|
392
418
|
const isMain =
|
|
393
419
|
typeof import.meta.main === "boolean"
|
|
394
420
|
? import.meta.main
|
|
395
|
-
: Boolean(process.argv?.[1] && process.argv[1].endsWith("parse-dts.mjs"))
|
|
421
|
+
: Boolean(process.argv?.[1] && process.argv[1].endsWith("parse-dts.mjs"));
|
|
396
422
|
|
|
397
423
|
// CLI mode
|
|
398
424
|
if (isMain) {
|
|
399
|
-
const dtsPath = process.argv[2]
|
|
400
|
-
const filter = process.argv[3]
|
|
425
|
+
const dtsPath = process.argv[2];
|
|
426
|
+
const filter = process.argv[3];
|
|
401
427
|
|
|
402
428
|
if (!dtsPath) {
|
|
403
|
-
console.error("Usage: node parse-dts.mjs <path-to-dts> [filter]")
|
|
404
|
-
process.exit(1)
|
|
429
|
+
console.error("Usage: node parse-dts.mjs <path-to-dts> [filter]");
|
|
430
|
+
process.exit(1);
|
|
405
431
|
}
|
|
406
432
|
|
|
407
|
-
const filterList = filter ? filter.split(",") : null
|
|
408
|
-
const result = parseDtsFile(dtsPath, filterList)
|
|
433
|
+
const filterList = filter ? filter.split(",") : null;
|
|
434
|
+
const result = parseDtsFile(dtsPath, filterList);
|
|
409
435
|
|
|
410
436
|
if (result) {
|
|
411
|
-
console.log(JSON.stringify(result, null, 2))
|
|
437
|
+
console.log(JSON.stringify(result, null, 2));
|
|
412
438
|
} else {
|
|
413
|
-
console.error("Failed to parse:", dtsPath)
|
|
414
|
-
process.exit(1)
|
|
439
|
+
console.error("Failed to parse:", dtsPath);
|
|
440
|
+
process.exit(1);
|
|
415
441
|
}
|
|
416
442
|
}
|