tidewave 0.1.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.
- package/CHANGELOG.md +55 -0
- package/LICENSE +201 -0
- package/README.md +96 -0
- package/dist/cli/index.js +1202 -0
- package/dist/index.js +1020 -0
- package/dist/mcp.js +1151 -0
- package/dist/resolution/formatters.js +153 -0
- package/dist/resolution/index.js +1030 -0
- package/dist/resolution/module-resolver.js +369 -0
- package/dist/resolution/symbol-finder.js +634 -0
- package/dist/resolution/utils.js +318 -0
- package/package.json +72 -0
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,1151 @@
|
|
|
1
|
+
// src/resolution/index.ts
|
|
2
|
+
import ts5 from "typescript";
|
|
3
|
+
|
|
4
|
+
// node:path
|
|
5
|
+
var L = Object.create;
|
|
6
|
+
var h = Object.defineProperty;
|
|
7
|
+
var D = Object.getOwnPropertyDescriptor;
|
|
8
|
+
var T = Object.getOwnPropertyNames;
|
|
9
|
+
var _ = Object.getPrototypeOf;
|
|
10
|
+
var E = Object.prototype.hasOwnProperty;
|
|
11
|
+
var R = (s, e) => () => (e || s((e = { exports: {} }).exports, e), e.exports);
|
|
12
|
+
var N = (s, e, r, t) => {
|
|
13
|
+
if (e && typeof e == "object" || typeof e == "function")
|
|
14
|
+
for (let i of T(e))
|
|
15
|
+
!E.call(s, i) && i !== r && h(s, i, { get: () => e[i], enumerable: !(t = D(e, i)) || t.enumerable });
|
|
16
|
+
return s;
|
|
17
|
+
};
|
|
18
|
+
var j = (s, e, r) => (r = s != null ? L(_(s)) : {}, N(e || !s || !s.__esModule ? h(r, "default", { value: s, enumerable: true }) : r, s));
|
|
19
|
+
var k = R((W, w) => {
|
|
20
|
+
function v(s) {
|
|
21
|
+
if (typeof s != "string")
|
|
22
|
+
throw new TypeError("Path must be a string. Received " + JSON.stringify(s));
|
|
23
|
+
}
|
|
24
|
+
function C(s, e) {
|
|
25
|
+
for (var r = "", t = 0, i = -1, a = 0, n, l = 0;l <= s.length; ++l) {
|
|
26
|
+
if (l < s.length)
|
|
27
|
+
n = s.charCodeAt(l);
|
|
28
|
+
else {
|
|
29
|
+
if (n === 47)
|
|
30
|
+
break;
|
|
31
|
+
n = 47;
|
|
32
|
+
}
|
|
33
|
+
if (n === 47) {
|
|
34
|
+
if (!(i === l - 1 || a === 1))
|
|
35
|
+
if (i !== l - 1 && a === 2) {
|
|
36
|
+
if (r.length < 2 || t !== 2 || r.charCodeAt(r.length - 1) !== 46 || r.charCodeAt(r.length - 2) !== 46) {
|
|
37
|
+
if (r.length > 2) {
|
|
38
|
+
var f = r.lastIndexOf("/");
|
|
39
|
+
if (f !== r.length - 1) {
|
|
40
|
+
f === -1 ? (r = "", t = 0) : (r = r.slice(0, f), t = r.length - 1 - r.lastIndexOf("/")), i = l, a = 0;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
} else if (r.length === 2 || r.length === 1) {
|
|
44
|
+
r = "", t = 0, i = l, a = 0;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
e && (r.length > 0 ? r += "/.." : r = "..", t = 2);
|
|
49
|
+
} else
|
|
50
|
+
r.length > 0 ? r += "/" + s.slice(i + 1, l) : r = s.slice(i + 1, l), t = l - i - 1;
|
|
51
|
+
i = l, a = 0;
|
|
52
|
+
} else
|
|
53
|
+
n === 46 && a !== -1 ? ++a : a = -1;
|
|
54
|
+
}
|
|
55
|
+
return r;
|
|
56
|
+
}
|
|
57
|
+
function F(s, e) {
|
|
58
|
+
var r = e.dir || e.root, t = e.base || (e.name || "") + (e.ext || "");
|
|
59
|
+
return r ? r === e.root ? r + t : r + s + t : t;
|
|
60
|
+
}
|
|
61
|
+
var m = { resolve: function() {
|
|
62
|
+
for (var e = "", r = false, t, i = arguments.length - 1;i >= -1 && !r; i--) {
|
|
63
|
+
var a;
|
|
64
|
+
i >= 0 ? a = arguments[i] : (t === undefined && (t = process.cwd()), a = t), v(a), a.length !== 0 && (e = a + "/" + e, r = a.charCodeAt(0) === 47);
|
|
65
|
+
}
|
|
66
|
+
return e = C(e, !r), r ? e.length > 0 ? "/" + e : "/" : e.length > 0 ? e : ".";
|
|
67
|
+
}, normalize: function(e) {
|
|
68
|
+
if (v(e), e.length === 0)
|
|
69
|
+
return ".";
|
|
70
|
+
var r = e.charCodeAt(0) === 47, t = e.charCodeAt(e.length - 1) === 47;
|
|
71
|
+
return e = C(e, !r), e.length === 0 && !r && (e = "."), e.length > 0 && t && (e += "/"), r ? "/" + e : e;
|
|
72
|
+
}, isAbsolute: function(e) {
|
|
73
|
+
return v(e), e.length > 0 && e.charCodeAt(0) === 47;
|
|
74
|
+
}, join: function() {
|
|
75
|
+
if (arguments.length === 0)
|
|
76
|
+
return ".";
|
|
77
|
+
for (var e, r = 0;r < arguments.length; ++r) {
|
|
78
|
+
var t = arguments[r];
|
|
79
|
+
v(t), t.length > 0 && (e === undefined ? e = t : e += "/" + t);
|
|
80
|
+
}
|
|
81
|
+
return e === undefined ? "." : m.normalize(e);
|
|
82
|
+
}, relative: function(e, r) {
|
|
83
|
+
if (v(e), v(r), e === r || (e = m.resolve(e), r = m.resolve(r), e === r))
|
|
84
|
+
return "";
|
|
85
|
+
for (var t = 1;t < e.length && e.charCodeAt(t) === 47; ++t)
|
|
86
|
+
;
|
|
87
|
+
for (var i = e.length, a = i - t, n = 1;n < r.length && r.charCodeAt(n) === 47; ++n)
|
|
88
|
+
;
|
|
89
|
+
for (var l = r.length, f = l - n, c = a < f ? a : f, d = -1, o = 0;o <= c; ++o) {
|
|
90
|
+
if (o === c) {
|
|
91
|
+
if (f > c) {
|
|
92
|
+
if (r.charCodeAt(n + o) === 47)
|
|
93
|
+
return r.slice(n + o + 1);
|
|
94
|
+
if (o === 0)
|
|
95
|
+
return r.slice(n + o);
|
|
96
|
+
} else
|
|
97
|
+
a > c && (e.charCodeAt(t + o) === 47 ? d = o : o === 0 && (d = 0));
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
var A = e.charCodeAt(t + o), z = r.charCodeAt(n + o);
|
|
101
|
+
if (A !== z)
|
|
102
|
+
break;
|
|
103
|
+
A === 47 && (d = o);
|
|
104
|
+
}
|
|
105
|
+
var b = "";
|
|
106
|
+
for (o = t + d + 1;o <= i; ++o)
|
|
107
|
+
(o === i || e.charCodeAt(o) === 47) && (b.length === 0 ? b += ".." : b += "/..");
|
|
108
|
+
return b.length > 0 ? b + r.slice(n + d) : (n += d, r.charCodeAt(n) === 47 && ++n, r.slice(n));
|
|
109
|
+
}, _makeLong: function(e) {
|
|
110
|
+
return e;
|
|
111
|
+
}, dirname: function(e) {
|
|
112
|
+
if (v(e), e.length === 0)
|
|
113
|
+
return ".";
|
|
114
|
+
for (var r = e.charCodeAt(0), t = r === 47, i = -1, a = true, n = e.length - 1;n >= 1; --n)
|
|
115
|
+
if (r = e.charCodeAt(n), r === 47) {
|
|
116
|
+
if (!a) {
|
|
117
|
+
i = n;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
} else
|
|
121
|
+
a = false;
|
|
122
|
+
return i === -1 ? t ? "/" : "." : t && i === 1 ? "//" : e.slice(0, i);
|
|
123
|
+
}, basename: function(e, r) {
|
|
124
|
+
if (r !== undefined && typeof r != "string")
|
|
125
|
+
throw new TypeError('"ext" argument must be a string');
|
|
126
|
+
v(e);
|
|
127
|
+
var t = 0, i = -1, a = true, n;
|
|
128
|
+
if (r !== undefined && r.length > 0 && r.length <= e.length) {
|
|
129
|
+
if (r.length === e.length && r === e)
|
|
130
|
+
return "";
|
|
131
|
+
var l = r.length - 1, f = -1;
|
|
132
|
+
for (n = e.length - 1;n >= 0; --n) {
|
|
133
|
+
var c = e.charCodeAt(n);
|
|
134
|
+
if (c === 47) {
|
|
135
|
+
if (!a) {
|
|
136
|
+
t = n + 1;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
} else
|
|
140
|
+
f === -1 && (a = false, f = n + 1), l >= 0 && (c === r.charCodeAt(l) ? --l === -1 && (i = n) : (l = -1, i = f));
|
|
141
|
+
}
|
|
142
|
+
return t === i ? i = f : i === -1 && (i = e.length), e.slice(t, i);
|
|
143
|
+
} else {
|
|
144
|
+
for (n = e.length - 1;n >= 0; --n)
|
|
145
|
+
if (e.charCodeAt(n) === 47) {
|
|
146
|
+
if (!a) {
|
|
147
|
+
t = n + 1;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
} else
|
|
151
|
+
i === -1 && (a = false, i = n + 1);
|
|
152
|
+
return i === -1 ? "" : e.slice(t, i);
|
|
153
|
+
}
|
|
154
|
+
}, extname: function(e) {
|
|
155
|
+
v(e);
|
|
156
|
+
for (var r = -1, t = 0, i = -1, a = true, n = 0, l = e.length - 1;l >= 0; --l) {
|
|
157
|
+
var f = e.charCodeAt(l);
|
|
158
|
+
if (f === 47) {
|
|
159
|
+
if (!a) {
|
|
160
|
+
t = l + 1;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
i === -1 && (a = false, i = l + 1), f === 46 ? r === -1 ? r = l : n !== 1 && (n = 1) : r !== -1 && (n = -1);
|
|
166
|
+
}
|
|
167
|
+
return r === -1 || i === -1 || n === 0 || n === 1 && r === i - 1 && r === t + 1 ? "" : e.slice(r, i);
|
|
168
|
+
}, format: function(e) {
|
|
169
|
+
if (e === null || typeof e != "object")
|
|
170
|
+
throw new TypeError('The "pathObject" argument must be of type Object. Received type ' + typeof e);
|
|
171
|
+
return F("/", e);
|
|
172
|
+
}, parse: function(e) {
|
|
173
|
+
v(e);
|
|
174
|
+
var r = { root: "", dir: "", base: "", ext: "", name: "" };
|
|
175
|
+
if (e.length === 0)
|
|
176
|
+
return r;
|
|
177
|
+
var t = e.charCodeAt(0), i = t === 47, a;
|
|
178
|
+
i ? (r.root = "/", a = 1) : a = 0;
|
|
179
|
+
for (var n = -1, l = 0, f = -1, c = true, d = e.length - 1, o = 0;d >= a; --d) {
|
|
180
|
+
if (t = e.charCodeAt(d), t === 47) {
|
|
181
|
+
if (!c) {
|
|
182
|
+
l = d + 1;
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
f === -1 && (c = false, f = d + 1), t === 46 ? n === -1 ? n = d : o !== 1 && (o = 1) : n !== -1 && (o = -1);
|
|
188
|
+
}
|
|
189
|
+
return n === -1 || f === -1 || o === 0 || o === 1 && n === f - 1 && n === l + 1 ? f !== -1 && (l === 0 && i ? r.base = r.name = e.slice(1, f) : r.base = r.name = e.slice(l, f)) : (l === 0 && i ? (r.name = e.slice(1, n), r.base = e.slice(1, f)) : (r.name = e.slice(l, n), r.base = e.slice(l, f)), r.ext = e.slice(n, f)), l > 0 ? r.dir = e.slice(0, l - 1) : i && (r.dir = "/"), r;
|
|
190
|
+
}, sep: "/", delimiter: ":", win32: null, posix: null };
|
|
191
|
+
m.posix = m;
|
|
192
|
+
w.exports = m;
|
|
193
|
+
});
|
|
194
|
+
var x = j(k());
|
|
195
|
+
var u = x;
|
|
196
|
+
var J = x;
|
|
197
|
+
var P = function(s) {
|
|
198
|
+
return s;
|
|
199
|
+
};
|
|
200
|
+
var S = function() {
|
|
201
|
+
throw new Error("Not implemented");
|
|
202
|
+
};
|
|
203
|
+
u.parse ??= S;
|
|
204
|
+
J.parse ??= S;
|
|
205
|
+
var g = { resolve: u.resolve.bind(u), normalize: u.normalize.bind(u), isAbsolute: u.isAbsolute.bind(u), join: u.join.bind(u), relative: u.relative.bind(u), toNamespacedPath: P, dirname: u.dirname.bind(u), basename: u.basename.bind(u), extname: u.extname.bind(u), format: u.format.bind(u), parse: u.parse.bind(u), sep: "/", delimiter: ":", win32: undefined, posix: undefined, _makeLong: P };
|
|
206
|
+
var y = { sep: "\\", delimiter: ";", win32: undefined, ...g, posix: g };
|
|
207
|
+
g.win32 = y.win32 = y;
|
|
208
|
+
g.posix = g;
|
|
209
|
+
var q = g;
|
|
210
|
+
|
|
211
|
+
// src/core.ts
|
|
212
|
+
function isError(result) {
|
|
213
|
+
return result != null && "success" in result && result.success === false;
|
|
214
|
+
}
|
|
215
|
+
function isResolveError(result) {
|
|
216
|
+
return result != null && "success" in result && result.success === false;
|
|
217
|
+
}
|
|
218
|
+
function isExtractError(result) {
|
|
219
|
+
return result != null && "error" in result;
|
|
220
|
+
}
|
|
221
|
+
function resolveError(specifier, source) {
|
|
222
|
+
return {
|
|
223
|
+
success: false,
|
|
224
|
+
error: {
|
|
225
|
+
code: "MODULE_NOT_FOUND",
|
|
226
|
+
message: `Cannot resolve module '${specifier}' from '${source}'`
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function createExtractError(code, message, details) {
|
|
231
|
+
return {
|
|
232
|
+
error: {
|
|
233
|
+
code,
|
|
234
|
+
message,
|
|
235
|
+
details
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// src/resolution/module-resolver.ts
|
|
241
|
+
import ts from "typescript";
|
|
242
|
+
function loadTsConfig(prefix) {
|
|
243
|
+
const projectPath = prefix || process.cwd();
|
|
244
|
+
const configPath = ts.findConfigFile(projectPath, ts.sys.fileExists, "tsconfig.json");
|
|
245
|
+
let compilerOptions = {
|
|
246
|
+
target: ts.ScriptTarget.ES2020,
|
|
247
|
+
module: ts.ModuleKind.CommonJS,
|
|
248
|
+
moduleResolution: ts.ModuleResolutionKind.Bundler,
|
|
249
|
+
esModuleInterop: true,
|
|
250
|
+
allowSyntheticDefaultImports: true,
|
|
251
|
+
skipLibCheck: true,
|
|
252
|
+
allowJs: true,
|
|
253
|
+
declaration: true,
|
|
254
|
+
typeRoots: ["./node_modules/@types"],
|
|
255
|
+
baseUrl: "."
|
|
256
|
+
};
|
|
257
|
+
let rootNames = [];
|
|
258
|
+
if (configPath) {
|
|
259
|
+
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
260
|
+
if (configFile.config) {
|
|
261
|
+
const parsedConfig = ts.parseJsonConfigFileContent(configFile.config, ts.sys, q.dirname(configPath));
|
|
262
|
+
compilerOptions = { ...compilerOptions, ...parsedConfig.options };
|
|
263
|
+
rootNames = parsedConfig.fileNames;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
fileNames: rootNames,
|
|
268
|
+
options: compilerOptions
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
function resolveModule(moduleName, compilerOptions) {
|
|
272
|
+
if (moduleName.startsWith("./") || moduleName.startsWith("../") || moduleName.includes(".") && !moduleName.includes("/")) {
|
|
273
|
+
const absolutePath = q.resolve(moduleName);
|
|
274
|
+
if (ts.sys.fileExists(absolutePath)) {
|
|
275
|
+
const dedicatedProgram = ts.createProgram([absolutePath], compilerOptions);
|
|
276
|
+
const sourceFile = dedicatedProgram.getSourceFile(absolutePath);
|
|
277
|
+
if (sourceFile) {
|
|
278
|
+
return { sourceFile, program: dedicatedProgram };
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const moduleResolver = ts.resolveModuleName(moduleName, q.resolve("./index.ts"), compilerOptions, ts.sys);
|
|
283
|
+
if (moduleResolver.resolvedModule) {
|
|
284
|
+
const { resolvedFileName } = moduleResolver.resolvedModule;
|
|
285
|
+
const dedicatedProgram = ts.createProgram([resolvedFileName], compilerOptions);
|
|
286
|
+
const sourceFile = dedicatedProgram.getSourceFile(resolvedFileName);
|
|
287
|
+
if (sourceFile) {
|
|
288
|
+
return { sourceFile, program: dedicatedProgram };
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return resolveError(moduleName, process.cwd());
|
|
292
|
+
}
|
|
293
|
+
function resolveNodeBuiltin(moduleName, compilerOptions) {
|
|
294
|
+
if (!moduleName.startsWith("node:")) {
|
|
295
|
+
return resolveError(moduleName, process.cwd());
|
|
296
|
+
}
|
|
297
|
+
const symbolName = moduleName.slice(5);
|
|
298
|
+
const globalBuiltins = [
|
|
299
|
+
"Math",
|
|
300
|
+
"Date",
|
|
301
|
+
"JSON",
|
|
302
|
+
"Object",
|
|
303
|
+
"Array",
|
|
304
|
+
"String",
|
|
305
|
+
"Number",
|
|
306
|
+
"Boolean",
|
|
307
|
+
"RegExp",
|
|
308
|
+
"Function",
|
|
309
|
+
"Promise",
|
|
310
|
+
"Map",
|
|
311
|
+
"Set",
|
|
312
|
+
"WeakMap",
|
|
313
|
+
"WeakSet",
|
|
314
|
+
"Symbol",
|
|
315
|
+
"Error",
|
|
316
|
+
"console",
|
|
317
|
+
"process",
|
|
318
|
+
"Buffer",
|
|
319
|
+
"global",
|
|
320
|
+
"__dirname",
|
|
321
|
+
"__filename"
|
|
322
|
+
];
|
|
323
|
+
if (globalBuiltins.includes(symbolName)) {
|
|
324
|
+
const syntheticContent = `declare const ${symbolName}: typeof globalThis.${symbolName};`;
|
|
325
|
+
const syntheticFileName = `synthetic-global-${symbolName}.d.ts`;
|
|
326
|
+
const host = ts.createCompilerHost(compilerOptions);
|
|
327
|
+
const originalGetSourceFile = host.getSourceFile;
|
|
328
|
+
host.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
|
|
329
|
+
if (fileName === syntheticFileName) {
|
|
330
|
+
return ts.createSourceFile(fileName, syntheticContent, ts.ScriptTarget.Latest, true);
|
|
331
|
+
}
|
|
332
|
+
return originalGetSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile);
|
|
333
|
+
};
|
|
334
|
+
const dedicatedProgram = ts.createProgram([syntheticFileName], compilerOptions, host);
|
|
335
|
+
const sourceFile = dedicatedProgram.getSourceFile(syntheticFileName);
|
|
336
|
+
if (sourceFile) {
|
|
337
|
+
return { sourceFile, program: dedicatedProgram };
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return resolveError(moduleName, process.cwd());
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// src/resolution/symbol-finder.ts
|
|
344
|
+
import ts4 from "typescript";
|
|
345
|
+
|
|
346
|
+
// src/resolution/utils.ts
|
|
347
|
+
import ts2 from "typescript";
|
|
348
|
+
function getLocation(symbol) {
|
|
349
|
+
if (symbol.valueDeclaration) {
|
|
350
|
+
const sourceFile = symbol.valueDeclaration.getSourceFile();
|
|
351
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(symbol.valueDeclaration.getStart());
|
|
352
|
+
let { fileName } = sourceFile;
|
|
353
|
+
const cwd = process.cwd();
|
|
354
|
+
if (fileName.startsWith(cwd)) {
|
|
355
|
+
fileName = q.relative(cwd, fileName);
|
|
356
|
+
}
|
|
357
|
+
return `${fileName}:${line + 1}:${character + 1}`;
|
|
358
|
+
}
|
|
359
|
+
if (symbol.declarations && symbol.declarations.length > 0) {
|
|
360
|
+
const [firstDeclaration] = symbol.declarations;
|
|
361
|
+
const sourceFile = firstDeclaration?.getSourceFile();
|
|
362
|
+
if (sourceFile === undefined || firstDeclaration === undefined)
|
|
363
|
+
return "unknown";
|
|
364
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(firstDeclaration.getStart());
|
|
365
|
+
let fileName = sourceFile?.fileName;
|
|
366
|
+
const cwd = process.cwd();
|
|
367
|
+
if (fileName?.startsWith(cwd)) {
|
|
368
|
+
fileName = q.relative(cwd, fileName);
|
|
369
|
+
}
|
|
370
|
+
return `${fileName}:${line + 1}:${character + 1}`;
|
|
371
|
+
}
|
|
372
|
+
return "unknown";
|
|
373
|
+
}
|
|
374
|
+
function getDocumentation(checker, symbol) {
|
|
375
|
+
return ts2.displayPartsToString(symbol.getDocumentationComment(checker));
|
|
376
|
+
}
|
|
377
|
+
function getJSDoc(checker, symbol) {
|
|
378
|
+
const jsDocTags = symbol.getJsDocTags(checker);
|
|
379
|
+
return jsDocTags.map((tag) => {
|
|
380
|
+
const tagName = tag.name;
|
|
381
|
+
const tagText = tag.text ? ts2.displayPartsToString(tag.text) : "";
|
|
382
|
+
return `@${tagName}${tagText ? " " + tagText : ""}`;
|
|
383
|
+
}).join(`
|
|
384
|
+
`);
|
|
385
|
+
}
|
|
386
|
+
function getSymbolKind(symbol) {
|
|
387
|
+
const flags = symbol.getFlags();
|
|
388
|
+
if (flags & ts2.SymbolFlags.Function)
|
|
389
|
+
return "function";
|
|
390
|
+
if (flags & ts2.SymbolFlags.Class)
|
|
391
|
+
return "class";
|
|
392
|
+
if (flags & ts2.SymbolFlags.Interface)
|
|
393
|
+
return "interface";
|
|
394
|
+
if (flags & ts2.SymbolFlags.TypeAlias)
|
|
395
|
+
return "type";
|
|
396
|
+
if (flags & ts2.SymbolFlags.Variable)
|
|
397
|
+
return "variable";
|
|
398
|
+
if (flags & ts2.SymbolFlags.Property)
|
|
399
|
+
return "property";
|
|
400
|
+
if (flags & ts2.SymbolFlags.Method)
|
|
401
|
+
return "method";
|
|
402
|
+
if (flags & ts2.SymbolFlags.Enum)
|
|
403
|
+
return "enum";
|
|
404
|
+
if (flags & ts2.SymbolFlags.Module)
|
|
405
|
+
return "module";
|
|
406
|
+
if (symbol.valueDeclaration) {
|
|
407
|
+
if (ts2.isFunctionDeclaration(symbol.valueDeclaration)) {
|
|
408
|
+
return "function";
|
|
409
|
+
}
|
|
410
|
+
if (ts2.isClassDeclaration(symbol.valueDeclaration)) {
|
|
411
|
+
return "class";
|
|
412
|
+
}
|
|
413
|
+
if (ts2.isVariableDeclaration(symbol.valueDeclaration)) {
|
|
414
|
+
return "variable";
|
|
415
|
+
}
|
|
416
|
+
if (ts2.isMethodDeclaration(symbol.valueDeclaration)) {
|
|
417
|
+
return "method";
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return "unknown";
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// src/resolution/formatters.ts
|
|
424
|
+
import ts3 from "typescript";
|
|
425
|
+
function getSignature(checker, symbol, type) {
|
|
426
|
+
const signatures = checker.getSignaturesOfType(type, ts3.SignatureKind.Call);
|
|
427
|
+
if (signatures.length > 0) {
|
|
428
|
+
return signatures.map((sig) => {
|
|
429
|
+
const sigString = checker.signatureToString(sig);
|
|
430
|
+
return `${symbol.getName()}${sigString}`;
|
|
431
|
+
}).join(`
|
|
432
|
+
`);
|
|
433
|
+
}
|
|
434
|
+
const constructSignatures = checker.getSignaturesOfType(type, ts3.SignatureKind.Construct);
|
|
435
|
+
if (constructSignatures.length > 0) {
|
|
436
|
+
return constructSignatures.map((sig) => "new " + checker.signatureToString(sig)).join(`
|
|
437
|
+
`);
|
|
438
|
+
}
|
|
439
|
+
if (symbol.valueDeclaration || symbol.declarations && symbol.declarations.length > 0) {
|
|
440
|
+
const declaration = symbol.valueDeclaration || symbol.declarations[0];
|
|
441
|
+
if (!declaration)
|
|
442
|
+
return checker.typeToString(type);
|
|
443
|
+
const sourceFile = declaration.getSourceFile();
|
|
444
|
+
if (ts3.isFunctionDeclaration(declaration) && declaration.name) {
|
|
445
|
+
const functionType = checker.getTypeOfSymbolAtLocation(symbol, declaration);
|
|
446
|
+
const functionSignatures = checker.getSignaturesOfType(functionType, ts3.SignatureKind.Call);
|
|
447
|
+
if (functionSignatures.length > 0) {
|
|
448
|
+
return functionSignatures.map((sig) => checker.signatureToString(sig)).join(`
|
|
449
|
+
`);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
if (ts3.isInterfaceDeclaration(declaration) || ts3.isTypeAliasDeclaration(declaration)) {
|
|
453
|
+
const start2 = declaration.getStart();
|
|
454
|
+
const end2 = declaration.getEnd();
|
|
455
|
+
const text2 = sourceFile.text.substring(start2, end2);
|
|
456
|
+
const lines = text2.split(`
|
|
457
|
+
`).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
458
|
+
if (ts3.isInterfaceDeclaration(declaration)) {
|
|
459
|
+
const bodyStart = text2.indexOf("{");
|
|
460
|
+
const bodyEnd = text2.lastIndexOf("}");
|
|
461
|
+
if (bodyStart !== -1 && bodyEnd !== -1) {
|
|
462
|
+
const body = text2.substring(bodyStart, bodyEnd + 1);
|
|
463
|
+
const interfaceName = `interface ${declaration.name.text}`;
|
|
464
|
+
const compactBody = body.replace(/\s*\n\s*/g, " ").replace(/\s+/g, " ");
|
|
465
|
+
return `${interfaceName} ${compactBody}`;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return lines.join(" ").replace(/\s+/g, " ");
|
|
469
|
+
}
|
|
470
|
+
if (ts3.isClassDeclaration(declaration)) {
|
|
471
|
+
const classType = checker.getTypeOfSymbolAtLocation(symbol, declaration);
|
|
472
|
+
const classConstructSignatures = checker.getSignaturesOfType(classType, ts3.SignatureKind.Construct);
|
|
473
|
+
if (classConstructSignatures.length > 0) {
|
|
474
|
+
return classConstructSignatures.map((sig) => "new " + checker.signatureToString(sig)).join(`
|
|
475
|
+
`);
|
|
476
|
+
} else {
|
|
477
|
+
const start2 = declaration.getStart();
|
|
478
|
+
const end2 = Math.min(declaration.getStart() + 100, declaration.getEnd());
|
|
479
|
+
const text2 = sourceFile.text.substring(start2, end2);
|
|
480
|
+
return text2.split(`
|
|
481
|
+
`)[0]?.trim() + (text2.includes(`
|
|
482
|
+
`) ? "..." : "") || "";
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
const start = declaration.getStart();
|
|
486
|
+
const end = Math.min(declaration.getStart() + 100, declaration.getEnd());
|
|
487
|
+
const text = sourceFile.text.substring(start, end);
|
|
488
|
+
return text.split(`
|
|
489
|
+
`)[0]?.trim() + (text.includes(`
|
|
490
|
+
`) ? "..." : "") || "";
|
|
491
|
+
}
|
|
492
|
+
return checker.typeToString(type);
|
|
493
|
+
}
|
|
494
|
+
function getTypeString(checker, symbol, type) {
|
|
495
|
+
if (symbol.flags & (ts3.SymbolFlags.Interface | ts3.SymbolFlags.TypeAlias)) {
|
|
496
|
+
const declaration = symbol.valueDeclaration || symbol.declarations && symbol.declarations[0];
|
|
497
|
+
if (declaration && ts3.isInterfaceDeclaration(declaration)) {
|
|
498
|
+
const properties = type.getProperties();
|
|
499
|
+
if (properties.length > 0) {
|
|
500
|
+
const propertyStrings = properties.map((prop) => {
|
|
501
|
+
const propDeclaration = prop.valueDeclaration || prop.declarations && prop.declarations[0];
|
|
502
|
+
const propType = propDeclaration ? checker.getTypeOfSymbolAtLocation(prop, propDeclaration) : checker.getTypeAtLocation(prop.declarations[0]);
|
|
503
|
+
const propTypeString = checker.typeToString(propType);
|
|
504
|
+
const isOptional = prop.flags & ts3.SymbolFlags.Optional;
|
|
505
|
+
return `${prop.getName()}${isOptional ? "?" : ""}: ${propTypeString}`;
|
|
506
|
+
});
|
|
507
|
+
return `{ ${propertyStrings.join("; ")} }`;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
const defaultTypeString = checker.typeToString(type);
|
|
512
|
+
if (defaultTypeString === "any" && symbol.flags & ts3.SymbolFlags.Interface) {
|
|
513
|
+
return `interface ${symbol.getName()}`;
|
|
514
|
+
}
|
|
515
|
+
return defaultTypeString;
|
|
516
|
+
}
|
|
517
|
+
function formatOutput(info) {
|
|
518
|
+
const output = [];
|
|
519
|
+
output.push(`
|
|
520
|
+
${info.name}`);
|
|
521
|
+
output.push(`Kind: ${info.kind}`);
|
|
522
|
+
output.push(`Location: ${info.location}`);
|
|
523
|
+
output.push("");
|
|
524
|
+
if (info.signature) {
|
|
525
|
+
output.push("Signature:");
|
|
526
|
+
output.push(info.signature);
|
|
527
|
+
output.push("");
|
|
528
|
+
}
|
|
529
|
+
if (info.documentation) {
|
|
530
|
+
output.push("Documentation:");
|
|
531
|
+
output.push(info.documentation);
|
|
532
|
+
output.push("");
|
|
533
|
+
}
|
|
534
|
+
if (info.jsDoc) {
|
|
535
|
+
output.push("JSDoc Tags:");
|
|
536
|
+
output.push(info.jsDoc);
|
|
537
|
+
output.push("");
|
|
538
|
+
}
|
|
539
|
+
output.push("Type:");
|
|
540
|
+
output.push(info.type);
|
|
541
|
+
return output.join(`
|
|
542
|
+
`);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// src/resolution/symbol-finder.ts
|
|
546
|
+
function findSymbolInJavaScriptFile(sourceFile, checker, symbolName) {
|
|
547
|
+
for (const statement of sourceFile.statements) {
|
|
548
|
+
if (ts4.isFunctionDeclaration(statement) && statement.name?.text === symbolName) {
|
|
549
|
+
return checker.getSymbolAtLocation(statement.name);
|
|
550
|
+
}
|
|
551
|
+
if (ts4.isClassDeclaration(statement) && statement.name?.text === symbolName) {
|
|
552
|
+
return checker.getSymbolAtLocation(statement.name);
|
|
553
|
+
}
|
|
554
|
+
if (ts4.isVariableStatement(statement)) {
|
|
555
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
556
|
+
if (ts4.isIdentifier(declaration.name) && declaration.name.text === symbolName) {
|
|
557
|
+
return checker.getSymbolAtLocation(declaration.name);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
if (ts4.isExpressionStatement(statement)) {
|
|
562
|
+
const { expression } = statement;
|
|
563
|
+
if (ts4.isBinaryExpression(expression) && expression.operatorToken.kind === ts4.SyntaxKind.EqualsToken) {
|
|
564
|
+
const { left, right } = expression;
|
|
565
|
+
if (ts4.isPropertyAccessExpression(left) && ts4.isIdentifier(left.expression) && left.expression.text === "module" && ts4.isIdentifier(left.name) && left.name.text === "exports" && ts4.isObjectLiteralExpression(right)) {
|
|
566
|
+
for (const prop of right.properties) {
|
|
567
|
+
if (ts4.isPropertyAssignment(prop) || ts4.isShorthandPropertyAssignment(prop)) {
|
|
568
|
+
const propName = ts4.isIdentifier(prop.name) ? prop.name.text : undefined;
|
|
569
|
+
if (propName === symbolName) {
|
|
570
|
+
let targetIdentifier;
|
|
571
|
+
if (ts4.isShorthandPropertyAssignment(prop)) {
|
|
572
|
+
targetIdentifier = prop.name;
|
|
573
|
+
} else if (ts4.isPropertyAssignment(prop) && ts4.isIdentifier(prop.initializer)) {
|
|
574
|
+
targetIdentifier = prop.initializer;
|
|
575
|
+
}
|
|
576
|
+
if (targetIdentifier) {
|
|
577
|
+
for (const statement2 of sourceFile.statements) {
|
|
578
|
+
if (ts4.isFunctionDeclaration(statement2) && statement2.name?.text === targetIdentifier.text) {
|
|
579
|
+
const originalSymbol = checker.getSymbolAtLocation(statement2.name);
|
|
580
|
+
if (originalSymbol) {
|
|
581
|
+
return originalSymbol;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
if (ts4.isClassDeclaration(statement2) && statement2.name?.text === targetIdentifier.text) {
|
|
585
|
+
const originalSymbol = checker.getSymbolAtLocation(statement2.name);
|
|
586
|
+
if (originalSymbol) {
|
|
587
|
+
return originalSymbol;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
if (ts4.isVariableStatement(statement2)) {
|
|
591
|
+
for (const declaration of statement2.declarationList.declarations) {
|
|
592
|
+
if (ts4.isIdentifier(declaration.name) && declaration.name.text === targetIdentifier.text) {
|
|
593
|
+
const originalSymbol = checker.getSymbolAtLocation(declaration.name);
|
|
594
|
+
if (originalSymbol) {
|
|
595
|
+
return originalSymbol;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
const exportSymbol = checker.getSymbolAtLocation(targetIdentifier);
|
|
602
|
+
return exportSymbol;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
function getSymbolInfo(checker, symbol, member, isStatic) {
|
|
614
|
+
const declaration = symbol.valueDeclaration || symbol.declarations && symbol.declarations[0];
|
|
615
|
+
if (!declaration && (!symbol.declarations || symbol.declarations.length === 0)) {
|
|
616
|
+
return createExtractError("TYPE_ERROR", `Symbol '${symbol.getName()}' has no declarations`);
|
|
617
|
+
}
|
|
618
|
+
const targetDeclaration = declaration || symbol.declarations[0];
|
|
619
|
+
const type = checker.getTypeOfSymbolAtLocation(symbol, targetDeclaration);
|
|
620
|
+
const symbolName = symbol.getName();
|
|
621
|
+
let targetSymbol = symbol;
|
|
622
|
+
let targetType = type;
|
|
623
|
+
let name = symbolName;
|
|
624
|
+
if (member) {
|
|
625
|
+
if (isStatic) {
|
|
626
|
+
const staticMembers = checker.getPropertiesOfType(type);
|
|
627
|
+
const staticMember = staticMembers.find((s) => s.getName() === member);
|
|
628
|
+
if (staticMember) {
|
|
629
|
+
targetSymbol = staticMember;
|
|
630
|
+
targetType = checker.getTypeOfSymbolAtLocation(staticMember, staticMember.valueDeclaration);
|
|
631
|
+
name = `${symbolName}.${member}`;
|
|
632
|
+
} else {
|
|
633
|
+
return createExtractError("MEMBER_NOT_FOUND", `Static member '${member}' not found on '${symbolName}'`);
|
|
634
|
+
}
|
|
635
|
+
} else {
|
|
636
|
+
let instanceType;
|
|
637
|
+
if (symbol.flags & ts4.SymbolFlags.Class) {
|
|
638
|
+
instanceType = checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration);
|
|
639
|
+
const constructSignatures = instanceType.getConstructSignatures();
|
|
640
|
+
if (constructSignatures.length > 0) {
|
|
641
|
+
const [constructSignature] = constructSignatures;
|
|
642
|
+
if (constructSignature) {
|
|
643
|
+
const instanceTypeFromConstruct = checker.getReturnTypeOfSignature(constructSignature);
|
|
644
|
+
const instanceMembers = checker.getPropertiesOfType(instanceTypeFromConstruct);
|
|
645
|
+
const instanceMember = instanceMembers.find((s) => s.getName() === member);
|
|
646
|
+
if (instanceMember) {
|
|
647
|
+
targetSymbol = instanceMember;
|
|
648
|
+
targetType = checker.getTypeOfSymbolAtLocation(instanceMember, instanceMember.valueDeclaration);
|
|
649
|
+
name = `${symbolName}#${member}`;
|
|
650
|
+
} else {
|
|
651
|
+
return createExtractError("MEMBER_NOT_FOUND", `Instance member '${member}' not found on '${symbolName}'. Available: ${instanceMembers.map((m) => m.getName()).join(", ")}`);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
} else {
|
|
655
|
+
const instanceMembers = checker.getPropertiesOfType(instanceType);
|
|
656
|
+
const instanceMember = instanceMembers.find((s) => s.getName() === member);
|
|
657
|
+
if (instanceMember) {
|
|
658
|
+
targetSymbol = instanceMember;
|
|
659
|
+
targetType = checker.getTypeOfSymbolAtLocation(instanceMember, instanceMember.valueDeclaration);
|
|
660
|
+
name = `${symbolName}#${member}`;
|
|
661
|
+
} else {
|
|
662
|
+
return createExtractError("MEMBER_NOT_FOUND", `Instance member '${member}' not found on '${symbolName}'. Available: ${instanceMembers.map((m) => m.getName()).join(", ")}`);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
} else {
|
|
666
|
+
const callSignatures = type.getCallSignatures();
|
|
667
|
+
const constructSignatures = type.getConstructSignatures();
|
|
668
|
+
if (constructSignatures.length > 0) {
|
|
669
|
+
const [constructSignature] = constructSignatures;
|
|
670
|
+
if (constructSignature) {
|
|
671
|
+
instanceType = checker.getReturnTypeOfSignature(constructSignature);
|
|
672
|
+
}
|
|
673
|
+
} else if (callSignatures.length > 0) {
|
|
674
|
+
const [callSignature] = callSignatures;
|
|
675
|
+
if (callSignature) {
|
|
676
|
+
instanceType = checker.getReturnTypeOfSignature(callSignature);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
if (instanceType) {
|
|
680
|
+
const instanceMembers = checker.getPropertiesOfType(instanceType);
|
|
681
|
+
const instanceMember = instanceMembers.find((s) => s.getName() === member);
|
|
682
|
+
if (instanceMember) {
|
|
683
|
+
targetSymbol = instanceMember;
|
|
684
|
+
targetType = checker.getTypeOfSymbolAtLocation(instanceMember, instanceMember.valueDeclaration);
|
|
685
|
+
name = `${symbolName}#${member}`;
|
|
686
|
+
} else {
|
|
687
|
+
return createExtractError("MEMBER_NOT_FOUND", `Instance member '${member}' not found on '${symbolName}'`);
|
|
688
|
+
}
|
|
689
|
+
} else {
|
|
690
|
+
return createExtractError("TYPE_ERROR", `'${symbolName}' is not a constructor or class`);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
const typeString = getTypeString(checker, targetSymbol, targetType);
|
|
696
|
+
const signature = getSignature(checker, targetSymbol, targetType);
|
|
697
|
+
const documentation = getDocumentation(checker, targetSymbol);
|
|
698
|
+
const jsDoc = getJSDoc(checker, targetSymbol);
|
|
699
|
+
const kind = getSymbolKind(targetSymbol);
|
|
700
|
+
const location = getLocation(targetSymbol);
|
|
701
|
+
return {
|
|
702
|
+
name,
|
|
703
|
+
kind,
|
|
704
|
+
type: typeString,
|
|
705
|
+
documentation,
|
|
706
|
+
jsDoc,
|
|
707
|
+
signature,
|
|
708
|
+
location
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// src/resolution/index.ts
|
|
713
|
+
function parseModulePath(modulePath) {
|
|
714
|
+
let module;
|
|
715
|
+
let symbolPath;
|
|
716
|
+
if (modulePath.startsWith("node:")) {
|
|
717
|
+
const nodeSymbol = modulePath.slice(5);
|
|
718
|
+
const [baseSymbol] = nodeSymbol.split(".");
|
|
719
|
+
module = `node:${baseSymbol}`;
|
|
720
|
+
symbolPath = nodeSymbol;
|
|
721
|
+
} else {
|
|
722
|
+
const [mod, symPath] = modulePath.split(":");
|
|
723
|
+
if (!mod || !symPath) {
|
|
724
|
+
return createExtractError("INVALID_REQUEST", `Invalid format. Expected 'module:symbol', got '${modulePath}'`);
|
|
725
|
+
}
|
|
726
|
+
module = mod;
|
|
727
|
+
symbolPath = symPath;
|
|
728
|
+
}
|
|
729
|
+
if (symbolPath.includes("#")) {
|
|
730
|
+
const [symbol, member] = symbolPath.split("#");
|
|
731
|
+
if (!symbol || !member) {
|
|
732
|
+
return createExtractError("INVALID_REQUEST", `Invalid format. Expected 'symbol#instance-member', got '${symbolPath}'`);
|
|
733
|
+
}
|
|
734
|
+
return { module, symbol, member, isStatic: false };
|
|
735
|
+
}
|
|
736
|
+
if (symbolPath.includes(".")) {
|
|
737
|
+
const [symbol, member] = symbolPath.split(".");
|
|
738
|
+
if (!symbol || !member) {
|
|
739
|
+
return createExtractError("INVALID_REQUEST", `Invalid format. Expected 'symbol.static-member', got '${symbolPath}'`);
|
|
740
|
+
}
|
|
741
|
+
return { module, symbol, member, isStatic: true };
|
|
742
|
+
}
|
|
743
|
+
return { module, symbol: symbolPath, member: undefined, isStatic: false };
|
|
744
|
+
}
|
|
745
|
+
async function extractDocs(modulePath) {
|
|
746
|
+
const options = { prefix: process.cwd() };
|
|
747
|
+
const parseResult = parseModulePath(modulePath);
|
|
748
|
+
if ("error" in parseResult) {
|
|
749
|
+
return parseResult;
|
|
750
|
+
}
|
|
751
|
+
const { module, symbol, member, isStatic } = parseResult;
|
|
752
|
+
const config = loadTsConfig(options.prefix);
|
|
753
|
+
let resolvedModule = resolveModule(module, config.options);
|
|
754
|
+
let isGlobalModule = false;
|
|
755
|
+
if (isResolveError(resolvedModule)) {
|
|
756
|
+
const nodeBuiltinResolution = resolveNodeBuiltin(module, config.options);
|
|
757
|
+
if (!isResolveError(nodeBuiltinResolution)) {
|
|
758
|
+
resolvedModule = nodeBuiltinResolution;
|
|
759
|
+
isGlobalModule = true;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
if (isResolveError(resolvedModule)) {
|
|
763
|
+
return createExtractError("MODULE_NOT_FOUND", `Module '${module}' not found`);
|
|
764
|
+
}
|
|
765
|
+
const { sourceFile, program } = resolvedModule;
|
|
766
|
+
const checker = program.getTypeChecker();
|
|
767
|
+
let targetSymbol;
|
|
768
|
+
if (isGlobalModule) {
|
|
769
|
+
const actualSymbolName = module.startsWith("node:") ? module.slice(5) : module;
|
|
770
|
+
const globalSymbols = checker.getSymbolsInScope(sourceFile, ts5.SymbolFlags.Value);
|
|
771
|
+
targetSymbol = globalSymbols.find((s) => s.getName() === actualSymbolName);
|
|
772
|
+
if (!targetSymbol) {
|
|
773
|
+
const [identifierNode] = sourceFile.statements;
|
|
774
|
+
if (identifierNode && ts5.isVariableStatement(identifierNode)) {
|
|
775
|
+
const [declaration] = identifierNode.declarationList.declarations;
|
|
776
|
+
if (declaration && ts5.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
777
|
+
targetSymbol = checker.getSymbolAtLocation(declaration.initializer);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
} else {
|
|
782
|
+
const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
|
|
783
|
+
if (moduleSymbol) {
|
|
784
|
+
const exports = checker.getExportsOfModule(moduleSymbol);
|
|
785
|
+
const exportSymbol = exports.find((exp) => exp.getName() === symbol);
|
|
786
|
+
if (exportSymbol) {
|
|
787
|
+
if (exportSymbol.valueDeclaration && (ts5.isFunctionDeclaration(exportSymbol.valueDeclaration) || ts5.isClassDeclaration(exportSymbol.valueDeclaration) || ts5.isVariableDeclaration(exportSymbol.valueDeclaration))) {
|
|
788
|
+
targetSymbol = exportSymbol;
|
|
789
|
+
} else if (exportSymbol.flags & (ts5.SymbolFlags.Interface | ts5.SymbolFlags.TypeAlias)) {
|
|
790
|
+
targetSymbol = exportSymbol;
|
|
791
|
+
} else {
|
|
792
|
+
targetSymbol = findSymbolInJavaScriptFile(sourceFile, checker, symbol);
|
|
793
|
+
}
|
|
794
|
+
} else {
|
|
795
|
+
return createExtractError("SYMBOL_NOT_FOUND", `Symbol '${symbol}' not found in module '${module}'. Available exports: ${exports.map((e) => e.getName()).join(", ")}`);
|
|
796
|
+
}
|
|
797
|
+
} else {
|
|
798
|
+
targetSymbol = findSymbolInJavaScriptFile(sourceFile, checker, symbol);
|
|
799
|
+
if (!targetSymbol) {
|
|
800
|
+
return createExtractError("SYMBOL_NOT_FOUND", `Symbol '${symbol}' not found in JavaScript module '${module}'`);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
if (!targetSymbol) {
|
|
805
|
+
let symbolToShow;
|
|
806
|
+
if (isGlobalModule) {
|
|
807
|
+
symbolToShow = module.startsWith("node:") ? module.slice(5) : module;
|
|
808
|
+
} else {
|
|
809
|
+
symbolToShow = symbol;
|
|
810
|
+
}
|
|
811
|
+
return createExtractError("SYMBOL_NOT_FOUND", `Symbol '${symbolToShow}' not found`);
|
|
812
|
+
}
|
|
813
|
+
const result = getSymbolInfo(checker, targetSymbol, member, isStatic);
|
|
814
|
+
return result;
|
|
815
|
+
}
|
|
816
|
+
async function getSourceLocation(reference) {
|
|
817
|
+
const options = { prefix: process.cwd() };
|
|
818
|
+
if (reference.includes(":")) {
|
|
819
|
+
const parseResult = parseModulePath(reference);
|
|
820
|
+
if ("error" in parseResult) {
|
|
821
|
+
return {
|
|
822
|
+
success: false,
|
|
823
|
+
error: {
|
|
824
|
+
code: "MODULE_NOT_FOUND",
|
|
825
|
+
message: parseResult.error.message
|
|
826
|
+
}
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
const { module, symbol, member, isStatic } = parseResult;
|
|
830
|
+
const config2 = loadTsConfig(options.prefix);
|
|
831
|
+
let resolvedModule = resolveModule(module, config2.options);
|
|
832
|
+
let isGlobalModule = false;
|
|
833
|
+
if (isResolveError(resolvedModule)) {
|
|
834
|
+
const nodeBuiltinResolution = resolveNodeBuiltin(module, config2.options);
|
|
835
|
+
if (!isResolveError(nodeBuiltinResolution)) {
|
|
836
|
+
resolvedModule = nodeBuiltinResolution;
|
|
837
|
+
isGlobalModule = true;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
if (isResolveError(resolvedModule)) {
|
|
841
|
+
return {
|
|
842
|
+
success: false,
|
|
843
|
+
error: {
|
|
844
|
+
code: "MODULE_NOT_FOUND",
|
|
845
|
+
message: `Module '${module}' not found`
|
|
846
|
+
}
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
const { sourceFile, program } = resolvedModule;
|
|
850
|
+
const checker = program.getTypeChecker();
|
|
851
|
+
let targetSymbol;
|
|
852
|
+
if (isGlobalModule) {
|
|
853
|
+
const actualSymbolName = module.startsWith("node:") ? module.slice(5) : module;
|
|
854
|
+
const globalSymbols = checker.getSymbolsInScope(sourceFile, ts5.SymbolFlags.Value);
|
|
855
|
+
targetSymbol = globalSymbols.find((s) => s.getName() === actualSymbolName);
|
|
856
|
+
if (!targetSymbol) {
|
|
857
|
+
const [identifierNode] = sourceFile.statements;
|
|
858
|
+
if (identifierNode && ts5.isVariableStatement(identifierNode)) {
|
|
859
|
+
const [declaration] = identifierNode.declarationList.declarations;
|
|
860
|
+
if (declaration && ts5.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
861
|
+
targetSymbol = checker.getSymbolAtLocation(declaration.initializer);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
} else {
|
|
866
|
+
const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
|
|
867
|
+
if (moduleSymbol) {
|
|
868
|
+
const exports = checker.getExportsOfModule(moduleSymbol);
|
|
869
|
+
const exportSymbol = exports.find((exp) => exp.getName() === symbol);
|
|
870
|
+
if (exportSymbol) {
|
|
871
|
+
targetSymbol = exportSymbol;
|
|
872
|
+
} else {
|
|
873
|
+
return {
|
|
874
|
+
success: false,
|
|
875
|
+
error: {
|
|
876
|
+
code: "MODULE_NOT_FOUND",
|
|
877
|
+
message: `Symbol '${symbol}' not found in module '${module}'`
|
|
878
|
+
}
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
} else {
|
|
882
|
+
targetSymbol = findSymbolInJavaScriptFile(sourceFile, checker, symbol);
|
|
883
|
+
if (!targetSymbol) {
|
|
884
|
+
return {
|
|
885
|
+
success: false,
|
|
886
|
+
error: {
|
|
887
|
+
code: "MODULE_NOT_FOUND",
|
|
888
|
+
message: `Symbol '${symbol}' not found in JavaScript module '${module}'`
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
if (!targetSymbol) {
|
|
895
|
+
return {
|
|
896
|
+
success: false,
|
|
897
|
+
error: {
|
|
898
|
+
code: "MODULE_NOT_FOUND",
|
|
899
|
+
message: `Symbol '${symbol}' not found`
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
const symbolInfo = getSymbolInfo(checker, targetSymbol, member, isStatic);
|
|
904
|
+
if (isExtractError(symbolInfo)) {
|
|
905
|
+
return {
|
|
906
|
+
success: false,
|
|
907
|
+
error: {
|
|
908
|
+
code: "MODULE_NOT_FOUND",
|
|
909
|
+
message: symbolInfo.error.message
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
return { path: symbolInfo.location, format: "typescript" };
|
|
914
|
+
}
|
|
915
|
+
const moduleName = reference;
|
|
916
|
+
if (moduleName.startsWith("./") || moduleName.startsWith("../")) {
|
|
917
|
+
const absolutePath = q.resolve(moduleName);
|
|
918
|
+
if (ts5.sys.fileExists(absolutePath)) {
|
|
919
|
+
const cwd = process.cwd();
|
|
920
|
+
let finalPath;
|
|
921
|
+
if (absolutePath.startsWith(cwd)) {
|
|
922
|
+
const relativePath = q.relative(cwd, absolutePath);
|
|
923
|
+
finalPath = relativePath.startsWith("..") ? absolutePath : relativePath;
|
|
924
|
+
} else {
|
|
925
|
+
finalPath = absolutePath;
|
|
926
|
+
}
|
|
927
|
+
return { path: finalPath, format: "typescript" };
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
const config = loadTsConfig(options.prefix);
|
|
931
|
+
const moduleResolver = ts5.resolveModuleName(moduleName, q.resolve("./index.ts"), config.options, ts5.sys);
|
|
932
|
+
if (moduleResolver.resolvedModule) {
|
|
933
|
+
const { resolvedFileName } = moduleResolver.resolvedModule;
|
|
934
|
+
const cwd = process.cwd();
|
|
935
|
+
let finalPath;
|
|
936
|
+
if (resolvedFileName.startsWith(cwd)) {
|
|
937
|
+
const relativePath = q.relative(cwd, resolvedFileName);
|
|
938
|
+
finalPath = relativePath.startsWith("..") ? resolvedFileName : relativePath;
|
|
939
|
+
} else {
|
|
940
|
+
finalPath = resolvedFileName;
|
|
941
|
+
}
|
|
942
|
+
return { path: finalPath, format: "typescript" };
|
|
943
|
+
}
|
|
944
|
+
return resolveError(moduleName, process.cwd());
|
|
945
|
+
}
|
|
946
|
+
async function extractSymbol(request, options = {}) {
|
|
947
|
+
try {
|
|
948
|
+
if (!request.symbol) {
|
|
949
|
+
return {
|
|
950
|
+
error: {
|
|
951
|
+
code: "INVALID_REQUEST",
|
|
952
|
+
message: "Symbol name is required"
|
|
953
|
+
}
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
const config = loadTsConfig(options.prefix);
|
|
957
|
+
const resolvedModule = resolveModule(request.module, config.options);
|
|
958
|
+
if (isResolveError(resolvedModule)) {
|
|
959
|
+
return {
|
|
960
|
+
error: {
|
|
961
|
+
code: "MODULE_NOT_FOUND",
|
|
962
|
+
message: `Module '${request.module}' not found`
|
|
963
|
+
}
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
const { sourceFile, program } = resolvedModule;
|
|
967
|
+
const checker = program.getTypeChecker();
|
|
968
|
+
const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
|
|
969
|
+
let targetSymbol;
|
|
970
|
+
if (moduleSymbol) {
|
|
971
|
+
const exports = checker.getExportsOfModule(moduleSymbol);
|
|
972
|
+
targetSymbol = exports.find((exp) => exp.getName() === request.symbol);
|
|
973
|
+
if (!targetSymbol) {
|
|
974
|
+
return {
|
|
975
|
+
error: {
|
|
976
|
+
code: "SYMBOL_NOT_FOUND",
|
|
977
|
+
message: `Symbol '${request.symbol}' not found in module '${request.module}'. Available exports: ${exports.map((e) => e.getName()).join(", ")}`
|
|
978
|
+
}
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
} else {
|
|
982
|
+
targetSymbol = findSymbolInJavaScriptFile(sourceFile, checker, request.symbol);
|
|
983
|
+
if (!targetSymbol) {
|
|
984
|
+
return {
|
|
985
|
+
error: {
|
|
986
|
+
code: "SYMBOL_NOT_FOUND",
|
|
987
|
+
message: `Symbol '${request.symbol}' not found in JavaScript module '${request.module}'`
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
const result = getSymbolInfo(checker, targetSymbol, request.member, request.isStatic);
|
|
993
|
+
return result;
|
|
994
|
+
} catch (error) {
|
|
995
|
+
return {
|
|
996
|
+
error: {
|
|
997
|
+
code: "PARSE_ERROR",
|
|
998
|
+
message: `Extraction failed: ${error instanceof Error ? error.message : String(error)}`
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
// src/index.ts
|
|
1004
|
+
var TidewaveExtractor = {
|
|
1005
|
+
extractDocs,
|
|
1006
|
+
getSourceLocation,
|
|
1007
|
+
formatOutput
|
|
1008
|
+
};
|
|
1009
|
+
|
|
1010
|
+
// src/mcp.ts
|
|
1011
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1012
|
+
|
|
1013
|
+
// src/tools.ts
|
|
1014
|
+
import { z } from "zod";
|
|
1015
|
+
var referenceDescription = `Module path in format 'module:symbol[#method|.method]'. Supports local files, dependencies, and Node.js builtins.
|
|
1016
|
+
|
|
1017
|
+
Module reference format:
|
|
1018
|
+
- module:symbol - Extract a top-level symbol
|
|
1019
|
+
- module:Class#method - Extract an instance method
|
|
1020
|
+
- module:Class.method - Extract a static method
|
|
1021
|
+
- node:Class#method - Extract a global/builtin instance method
|
|
1022
|
+
- node:Class.method - Extract a global/builtin static method
|
|
1023
|
+
|
|
1024
|
+
Examples:
|
|
1025
|
+
- src/types.ts:SymbolInfo (local file symbol)
|
|
1026
|
+
- lodash:isEmpty (dependency function)
|
|
1027
|
+
- react:Component#render (instance method)
|
|
1028
|
+
- node:Math.max (builtin static method)`;
|
|
1029
|
+
var docsInputSchema = z.object({
|
|
1030
|
+
reference: z.string().describe(referenceDescription)
|
|
1031
|
+
});
|
|
1032
|
+
var sourceInputSchema = z.object({
|
|
1033
|
+
reference: z.string().describe(referenceDescription)
|
|
1034
|
+
});
|
|
1035
|
+
var tools = {
|
|
1036
|
+
docs: {
|
|
1037
|
+
mcp: {
|
|
1038
|
+
name: "get_docs",
|
|
1039
|
+
description: "Extract TypeScript/JavaScript documentation and type information for symbols, classes, functions, and methods. This works for modules in the current project, as well as dependencies, and builtin node modules",
|
|
1040
|
+
inputSchema: docsInputSchema
|
|
1041
|
+
},
|
|
1042
|
+
cli: {
|
|
1043
|
+
command: "docs",
|
|
1044
|
+
description: "Extract documentation for a symbol",
|
|
1045
|
+
argument: "<module-path>",
|
|
1046
|
+
argumentDescription: referenceDescription,
|
|
1047
|
+
options: {
|
|
1048
|
+
prefix: {
|
|
1049
|
+
flag: "-p, --prefix <path>",
|
|
1050
|
+
desc: "Path to a custom project path (which contains tsconfig.json/package.json)"
|
|
1051
|
+
},
|
|
1052
|
+
json: {
|
|
1053
|
+
flag: "-j, --json",
|
|
1054
|
+
desc: "If the output should be in JSON format or not"
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
},
|
|
1059
|
+
source: {
|
|
1060
|
+
mcp: {
|
|
1061
|
+
name: "get_source_location",
|
|
1062
|
+
description: "Extract TypeScript/JavaScript source location for the given reference. This works for modules in the current project, as well as dependencies, and builtin node modules",
|
|
1063
|
+
inputSchema: sourceInputSchema
|
|
1064
|
+
},
|
|
1065
|
+
cli: {
|
|
1066
|
+
command: "source",
|
|
1067
|
+
description: "Get the source file path for a module",
|
|
1068
|
+
argument: "<module>",
|
|
1069
|
+
argumentDescription: referenceDescription,
|
|
1070
|
+
options: {
|
|
1071
|
+
prefix: {
|
|
1072
|
+
flag: "-p, --prefix <path>",
|
|
1073
|
+
desc: "Path to a custom project path (which contains tsconfig.json/package.json)"
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
1079
|
+
|
|
1080
|
+
// package.json
|
|
1081
|
+
var name = "tidewave";
|
|
1082
|
+
var version = "0.1.0";
|
|
1083
|
+
|
|
1084
|
+
// src/mcp.ts
|
|
1085
|
+
var {
|
|
1086
|
+
docs: { mcp: docsMcp },
|
|
1087
|
+
source: { mcp: sourceMcp }
|
|
1088
|
+
} = tools;
|
|
1089
|
+
async function handleGetDocs({ reference }) {
|
|
1090
|
+
const docs = await TidewaveExtractor.extractDocs(reference);
|
|
1091
|
+
if (isExtractError(docs)) {
|
|
1092
|
+
return {
|
|
1093
|
+
content: [
|
|
1094
|
+
{
|
|
1095
|
+
type: "text",
|
|
1096
|
+
text: `Documentation not found for ${reference}, got an error: ${JSON.stringify(docs)}`
|
|
1097
|
+
}
|
|
1098
|
+
],
|
|
1099
|
+
isError: true
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
if (!docs.documentation) {
|
|
1103
|
+
return {
|
|
1104
|
+
content: [
|
|
1105
|
+
{
|
|
1106
|
+
type: "text",
|
|
1107
|
+
text: `Documentation not avaialble for ${reference}, reference did not include it`
|
|
1108
|
+
}
|
|
1109
|
+
],
|
|
1110
|
+
isError: true
|
|
1111
|
+
};
|
|
1112
|
+
}
|
|
1113
|
+
return {
|
|
1114
|
+
content: [{ type: "text", text: TidewaveExtractor.formatOutput(docs) }],
|
|
1115
|
+
isError: false
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
async function handleGetSourcePath({ reference }) {
|
|
1119
|
+
const sourceResult = await TidewaveExtractor.getSourceLocation(reference);
|
|
1120
|
+
if (isResolveError(sourceResult)) {
|
|
1121
|
+
return {
|
|
1122
|
+
content: [
|
|
1123
|
+
{
|
|
1124
|
+
type: "text",
|
|
1125
|
+
text: `Failed to get source location for ${reference}: ${JSON.stringify(sourceResult)}`
|
|
1126
|
+
}
|
|
1127
|
+
],
|
|
1128
|
+
isError: true
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
1131
|
+
const { path, format } = sourceResult;
|
|
1132
|
+
return {
|
|
1133
|
+
content: [{ type: "text", text: `${path}(${format})` }],
|
|
1134
|
+
isError: false
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
async function serveMcp(transport) {
|
|
1138
|
+
const server = new McpServer({ name, version });
|
|
1139
|
+
server.registerTool(docsMcp.name, {
|
|
1140
|
+
description: docsMcp.description,
|
|
1141
|
+
inputSchema: docsMcp.inputSchema.shape
|
|
1142
|
+
}, handleGetDocs);
|
|
1143
|
+
server.registerTool(sourceMcp.name, {
|
|
1144
|
+
description: sourceMcp.description,
|
|
1145
|
+
inputSchema: sourceMcp.inputSchema.shape
|
|
1146
|
+
}, handleGetSourcePath);
|
|
1147
|
+
await server.connect(transport);
|
|
1148
|
+
}
|
|
1149
|
+
export {
|
|
1150
|
+
serveMcp
|
|
1151
|
+
};
|