@oxog/npm-llms 1.0.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/LICENSE +21 -0
- package/README.md +286 -0
- package/dist/cli/index.cjs +5154 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +5152 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.cjs +3589 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +427 -0
- package/dist/index.d.ts +427 -0
- package/dist/index.js +3558 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel-I4Zn2uXv.d.cts +559 -0
- package/dist/kernel-I4Zn2uXv.d.ts +559 -0
- package/dist/plugins/index.cjs +4171 -0
- package/dist/plugins/index.cjs.map +1 -0
- package/dist/plugins/index.d.cts +452 -0
- package/dist/plugins/index.d.ts +452 -0
- package/dist/plugins/index.js +4133 -0
- package/dist/plugins/index.js.map +1 -0
- package/package.json +88 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,3589 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var crypto = require('crypto');
|
|
4
|
+
var path = require('path');
|
|
5
|
+
var os = require('os');
|
|
6
|
+
var promises = require('fs/promises');
|
|
7
|
+
var fs = require('fs');
|
|
8
|
+
var zlib = require('zlib');
|
|
9
|
+
|
|
10
|
+
// src/errors.ts
|
|
11
|
+
var NpmLlmsError = class extends Error {
|
|
12
|
+
/**
|
|
13
|
+
* Create a new NpmLlmsError
|
|
14
|
+
* @param message - Error message
|
|
15
|
+
* @param code - Error code
|
|
16
|
+
* @param details - Additional error details
|
|
17
|
+
*/
|
|
18
|
+
constructor(message, code, details) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.code = code;
|
|
21
|
+
this.details = details;
|
|
22
|
+
this.name = "NpmLlmsError";
|
|
23
|
+
if (Error.captureStackTrace) {
|
|
24
|
+
Error.captureStackTrace(this, this.constructor);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Convert error to JSON
|
|
29
|
+
*/
|
|
30
|
+
toJSON() {
|
|
31
|
+
return {
|
|
32
|
+
name: this.name,
|
|
33
|
+
message: this.message,
|
|
34
|
+
code: this.code,
|
|
35
|
+
details: this.details
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var PackageNotFoundError = class extends NpmLlmsError {
|
|
40
|
+
constructor(packageName) {
|
|
41
|
+
super(`Package "${packageName}" not found on npm`, "PACKAGE_NOT_FOUND", { packageName });
|
|
42
|
+
this.name = "PackageNotFoundError";
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
var VersionNotFoundError = class extends NpmLlmsError {
|
|
46
|
+
constructor(packageName, version) {
|
|
47
|
+
super(`Version "${version}" not found for package "${packageName}"`, "VERSION_NOT_FOUND", {
|
|
48
|
+
packageName,
|
|
49
|
+
version
|
|
50
|
+
});
|
|
51
|
+
this.name = "VersionNotFoundError";
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var DownloadError = class extends NpmLlmsError {
|
|
55
|
+
constructor(message, url) {
|
|
56
|
+
super(message, "DOWNLOAD_FAILED", { url });
|
|
57
|
+
this.name = "DownloadError";
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var ParseError = class extends NpmLlmsError {
|
|
61
|
+
constructor(message, file, position) {
|
|
62
|
+
super(message, "PARSE_ERROR", { file, position });
|
|
63
|
+
this.name = "ParseError";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var AIError = class extends NpmLlmsError {
|
|
67
|
+
constructor(message, provider) {
|
|
68
|
+
super(message, "AI_ERROR", { provider });
|
|
69
|
+
this.name = "AIError";
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
var PluginError = class extends NpmLlmsError {
|
|
73
|
+
constructor(message, pluginName) {
|
|
74
|
+
super(message, "PLUGIN_ERROR", { pluginName });
|
|
75
|
+
this.name = "PluginError";
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var CacheError = class extends NpmLlmsError {
|
|
79
|
+
constructor(message) {
|
|
80
|
+
super(message, "CACHE_ERROR");
|
|
81
|
+
this.name = "CacheError";
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var ConfigError = class extends NpmLlmsError {
|
|
85
|
+
constructor(message) {
|
|
86
|
+
super(message, "CONFIG_ERROR");
|
|
87
|
+
this.name = "ConfigError";
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
var TarError = class extends NpmLlmsError {
|
|
91
|
+
constructor(message, offset) {
|
|
92
|
+
super(message, "TAR_ERROR", { offset });
|
|
93
|
+
this.name = "TarError";
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
var TimeoutError = class extends NpmLlmsError {
|
|
97
|
+
constructor(message, timeout) {
|
|
98
|
+
super(message, "TIMEOUT_ERROR", { timeout });
|
|
99
|
+
this.name = "TimeoutError";
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
var ValidationError = class extends NpmLlmsError {
|
|
103
|
+
constructor(message, field) {
|
|
104
|
+
super(message, "VALIDATION_ERROR", { field });
|
|
105
|
+
this.name = "ValidationError";
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
function isNpmLlmsError(error) {
|
|
109
|
+
return error instanceof NpmLlmsError;
|
|
110
|
+
}
|
|
111
|
+
function getErrorCode(error) {
|
|
112
|
+
if (isNpmLlmsError(error)) {
|
|
113
|
+
return error.code;
|
|
114
|
+
}
|
|
115
|
+
return "UNKNOWN_ERROR";
|
|
116
|
+
}
|
|
117
|
+
function wrapError(error, code = "UNKNOWN_ERROR") {
|
|
118
|
+
if (isNpmLlmsError(error)) {
|
|
119
|
+
return error;
|
|
120
|
+
}
|
|
121
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
122
|
+
return new NpmLlmsError(message, code, {
|
|
123
|
+
originalError: error instanceof Error ? error.name : typeof error
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/kernel.ts
|
|
128
|
+
function createKernel() {
|
|
129
|
+
const plugins = /* @__PURE__ */ new Map();
|
|
130
|
+
const eventHandlers = /* @__PURE__ */ new Map();
|
|
131
|
+
const handlerToPlugin = /* @__PURE__ */ new Map();
|
|
132
|
+
function handlePluginError(error, pluginName) {
|
|
133
|
+
const plugin = pluginName ? plugins.get(pluginName) : void 0;
|
|
134
|
+
if (plugin?.onError) {
|
|
135
|
+
try {
|
|
136
|
+
plugin.onError(error);
|
|
137
|
+
} catch {
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function use(plugin) {
|
|
142
|
+
if (!plugin.name) {
|
|
143
|
+
throw new PluginError("Plugin must have a name");
|
|
144
|
+
}
|
|
145
|
+
if (plugins.has(plugin.name)) {
|
|
146
|
+
throw new PluginError(`Plugin "${plugin.name}" is already registered`, plugin.name);
|
|
147
|
+
}
|
|
148
|
+
if (plugin.dependencies) {
|
|
149
|
+
for (const dep of plugin.dependencies) {
|
|
150
|
+
if (!plugins.has(dep)) {
|
|
151
|
+
throw new PluginError(
|
|
152
|
+
`Plugin "${plugin.name}" depends on "${dep}" which is not registered`,
|
|
153
|
+
plugin.name
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
plugin.install(kernel);
|
|
160
|
+
plugins.set(plugin.name, plugin);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
163
|
+
throw new PluginError(
|
|
164
|
+
`Failed to install plugin "${plugin.name}": ${err.message}`,
|
|
165
|
+
plugin.name
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
return kernel;
|
|
169
|
+
}
|
|
170
|
+
function unregister(name) {
|
|
171
|
+
const plugin = plugins.get(name);
|
|
172
|
+
if (!plugin) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
for (const [, p] of plugins) {
|
|
176
|
+
if (p.dependencies?.includes(name)) {
|
|
177
|
+
throw new PluginError(
|
|
178
|
+
`Cannot unregister "${name}": plugin "${p.name}" depends on it`,
|
|
179
|
+
name
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
for (const [event, handlers] of eventHandlers) {
|
|
184
|
+
const toRemove = [];
|
|
185
|
+
for (const entry of handlers) {
|
|
186
|
+
if (entry.pluginName === name) {
|
|
187
|
+
toRemove.push(entry);
|
|
188
|
+
handlerToPlugin.delete(entry.handler);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
for (const entry of toRemove) {
|
|
192
|
+
handlers.delete(entry);
|
|
193
|
+
}
|
|
194
|
+
if (handlers.size === 0) {
|
|
195
|
+
eventHandlers.delete(event);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
plugin.onDestroy?.();
|
|
200
|
+
} catch {
|
|
201
|
+
}
|
|
202
|
+
plugins.delete(name);
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
function on(event, handler) {
|
|
206
|
+
if (!eventHandlers.has(event)) {
|
|
207
|
+
eventHandlers.set(event, /* @__PURE__ */ new Set());
|
|
208
|
+
}
|
|
209
|
+
const pluginName = getCurrentPluginContext() ?? "unknown";
|
|
210
|
+
const entry = { handler, pluginName };
|
|
211
|
+
eventHandlers.get(event).add(entry);
|
|
212
|
+
handlerToPlugin.set(handler, pluginName);
|
|
213
|
+
}
|
|
214
|
+
function off(event, handler) {
|
|
215
|
+
const handlers = eventHandlers.get(event);
|
|
216
|
+
if (!handlers) return;
|
|
217
|
+
for (const entry of handlers) {
|
|
218
|
+
if (entry.handler === handler) {
|
|
219
|
+
handlers.delete(entry);
|
|
220
|
+
handlerToPlugin.delete(handler);
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (handlers.size === 0) {
|
|
225
|
+
eventHandlers.delete(event);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
async function emit(event, context, ...args) {
|
|
229
|
+
const handlers = eventHandlers.get(event);
|
|
230
|
+
if (!handlers || handlers.size === 0) return;
|
|
231
|
+
for (const entry of handlers) {
|
|
232
|
+
try {
|
|
233
|
+
await entry.handler(context, ...args);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
236
|
+
handlePluginError(err, entry.pluginName);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function listPlugins() {
|
|
241
|
+
return Array.from(plugins.values()).map((p) => ({
|
|
242
|
+
name: p.name,
|
|
243
|
+
version: p.version,
|
|
244
|
+
category: p.category,
|
|
245
|
+
dependencies: p.dependencies ?? []
|
|
246
|
+
}));
|
|
247
|
+
}
|
|
248
|
+
function getPlugin(name) {
|
|
249
|
+
return plugins.get(name);
|
|
250
|
+
}
|
|
251
|
+
function hasPlugin(name) {
|
|
252
|
+
return plugins.has(name);
|
|
253
|
+
}
|
|
254
|
+
async function destroy() {
|
|
255
|
+
const pluginNames = Array.from(plugins.keys()).reverse();
|
|
256
|
+
for (const name of pluginNames) {
|
|
257
|
+
const plugin = plugins.get(name);
|
|
258
|
+
if (plugin?.onDestroy) {
|
|
259
|
+
try {
|
|
260
|
+
await plugin.onDestroy();
|
|
261
|
+
} catch {
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
plugins.clear();
|
|
266
|
+
eventHandlers.clear();
|
|
267
|
+
handlerToPlugin.clear();
|
|
268
|
+
}
|
|
269
|
+
let currentPluginContext = null;
|
|
270
|
+
function getCurrentPluginContext() {
|
|
271
|
+
return currentPluginContext;
|
|
272
|
+
}
|
|
273
|
+
const originalUse = use;
|
|
274
|
+
function wrappedUse(plugin) {
|
|
275
|
+
currentPluginContext = plugin.name;
|
|
276
|
+
try {
|
|
277
|
+
originalUse(plugin);
|
|
278
|
+
return kernel;
|
|
279
|
+
} finally {
|
|
280
|
+
currentPluginContext = null;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const kernel = {
|
|
284
|
+
use: wrappedUse,
|
|
285
|
+
unregister,
|
|
286
|
+
on,
|
|
287
|
+
off,
|
|
288
|
+
emit,
|
|
289
|
+
listPlugins,
|
|
290
|
+
getPlugin,
|
|
291
|
+
hasPlugin,
|
|
292
|
+
destroy
|
|
293
|
+
};
|
|
294
|
+
return kernel;
|
|
295
|
+
}
|
|
296
|
+
function definePlugin(definition) {
|
|
297
|
+
return definition;
|
|
298
|
+
}
|
|
299
|
+
function composePlugins(name, plugins) {
|
|
300
|
+
return {
|
|
301
|
+
name,
|
|
302
|
+
version: "1.0.0",
|
|
303
|
+
category: "utility",
|
|
304
|
+
dependencies: plugins.flatMap((p) => p.dependencies ?? []),
|
|
305
|
+
install(kernel) {
|
|
306
|
+
for (const plugin of plugins) {
|
|
307
|
+
kernel.use(plugin);
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
async onDestroy() {
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
async function exists(path) {
|
|
315
|
+
try {
|
|
316
|
+
await promises.access(path, fs.constants.F_OK);
|
|
317
|
+
return true;
|
|
318
|
+
} catch {
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
async function ensureDir(dirPath) {
|
|
323
|
+
try {
|
|
324
|
+
await promises.mkdir(dirPath, { recursive: true });
|
|
325
|
+
return true;
|
|
326
|
+
} catch (error) {
|
|
327
|
+
if (error.code === "EEXIST") {
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
throw error;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
async function readJsonFile(filePath) {
|
|
334
|
+
const content = await promises.readFile(filePath, "utf-8");
|
|
335
|
+
return JSON.parse(content);
|
|
336
|
+
}
|
|
337
|
+
async function writeTextFile(filePath, content) {
|
|
338
|
+
await ensureDir(path.dirname(filePath));
|
|
339
|
+
await promises.writeFile(filePath, content, "utf-8");
|
|
340
|
+
}
|
|
341
|
+
async function writeJsonFile(filePath, data, pretty = true) {
|
|
342
|
+
const content = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
|
|
343
|
+
await writeTextFile(filePath, content);
|
|
344
|
+
}
|
|
345
|
+
async function deleteFile(filePath) {
|
|
346
|
+
try {
|
|
347
|
+
await promises.unlink(filePath);
|
|
348
|
+
return true;
|
|
349
|
+
} catch (error) {
|
|
350
|
+
if (error.code === "ENOENT") {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
throw error;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
async function deleteDir(dirPath) {
|
|
357
|
+
try {
|
|
358
|
+
await promises.rm(dirPath, { recursive: true, force: true });
|
|
359
|
+
return true;
|
|
360
|
+
} catch (error) {
|
|
361
|
+
if (error.code === "ENOENT") {
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
throw error;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
async function listFiles(dirPath, recursive = false) {
|
|
368
|
+
const files = [];
|
|
369
|
+
async function scanDir(currentPath, prefix = "") {
|
|
370
|
+
const entries = await promises.readdir(currentPath, { withFileTypes: true });
|
|
371
|
+
for (const entry of entries) {
|
|
372
|
+
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
373
|
+
if (entry.isFile()) {
|
|
374
|
+
files.push(relativePath);
|
|
375
|
+
} else if (entry.isDirectory() && recursive) {
|
|
376
|
+
await scanDir(path.join(currentPath, entry.name), relativePath);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
try {
|
|
381
|
+
await scanDir(dirPath);
|
|
382
|
+
} catch (error) {
|
|
383
|
+
if (error.code === "ENOENT") {
|
|
384
|
+
return [];
|
|
385
|
+
}
|
|
386
|
+
throw error;
|
|
387
|
+
}
|
|
388
|
+
return files;
|
|
389
|
+
}
|
|
390
|
+
async function getDirSize(dirPath) {
|
|
391
|
+
let totalSize = 0;
|
|
392
|
+
async function scanDir(currentPath) {
|
|
393
|
+
try {
|
|
394
|
+
const entries = await promises.readdir(currentPath, { withFileTypes: true });
|
|
395
|
+
for (const entry of entries) {
|
|
396
|
+
const fullPath = path.join(currentPath, entry.name);
|
|
397
|
+
if (entry.isFile()) {
|
|
398
|
+
const stats = await promises.stat(fullPath);
|
|
399
|
+
totalSize += stats.size;
|
|
400
|
+
} else if (entry.isDirectory()) {
|
|
401
|
+
await scanDir(fullPath);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
} catch {
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
await scanDir(dirPath);
|
|
408
|
+
return totalSize;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// src/core/cache.ts
|
|
412
|
+
var DEFAULT_CACHE_DIR = ".npm-llms-cache";
|
|
413
|
+
var DEFAULT_TTL = 7 * 24 * 60 * 60 * 1e3;
|
|
414
|
+
var CACHE_VERSION = 1;
|
|
415
|
+
var FileCache = class {
|
|
416
|
+
dir;
|
|
417
|
+
defaultTtl;
|
|
418
|
+
/**
|
|
419
|
+
* Create a new FileCache
|
|
420
|
+
* @param dir - Cache directory path
|
|
421
|
+
* @param defaultTtl - Default TTL in milliseconds
|
|
422
|
+
*/
|
|
423
|
+
constructor(dir, defaultTtl = DEFAULT_TTL) {
|
|
424
|
+
this.dir = dir ?? path.join(os.tmpdir(), DEFAULT_CACHE_DIR);
|
|
425
|
+
this.defaultTtl = defaultTtl;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Generate a cache key hash
|
|
429
|
+
* @param input - Input string
|
|
430
|
+
* @returns Hashed key
|
|
431
|
+
*/
|
|
432
|
+
getKey(input) {
|
|
433
|
+
return crypto.createHash("sha256").update(input).digest("hex").slice(0, 16);
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Get file path for a cache key
|
|
437
|
+
* @param key - Cache key
|
|
438
|
+
* @returns File path
|
|
439
|
+
*/
|
|
440
|
+
getPath(key) {
|
|
441
|
+
const hash = this.getKey(key);
|
|
442
|
+
return path.join(this.dir, hash.slice(0, 2), `${hash}.json`);
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Get cached data
|
|
446
|
+
* @param key - Cache key
|
|
447
|
+
* @returns Cached data or null if not found/expired
|
|
448
|
+
*/
|
|
449
|
+
async get(key) {
|
|
450
|
+
const path = this.getPath(key);
|
|
451
|
+
try {
|
|
452
|
+
if (!await exists(path)) {
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
const entry = await readJsonFile(path);
|
|
456
|
+
if (entry.version !== CACHE_VERSION) {
|
|
457
|
+
await this.delete(key);
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
const age = Date.now() - entry.timestamp;
|
|
461
|
+
if (age > entry.ttl) {
|
|
462
|
+
await this.delete(key);
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
return entry.data;
|
|
466
|
+
} catch {
|
|
467
|
+
await this.delete(key).catch(() => {
|
|
468
|
+
});
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Set cached data
|
|
474
|
+
* @param key - Cache key
|
|
475
|
+
* @param data - Data to cache
|
|
476
|
+
* @param ttl - Optional TTL override
|
|
477
|
+
*/
|
|
478
|
+
async set(key, data, ttl) {
|
|
479
|
+
const path = this.getPath(key);
|
|
480
|
+
const entry = {
|
|
481
|
+
data,
|
|
482
|
+
timestamp: Date.now(),
|
|
483
|
+
ttl: ttl ?? this.defaultTtl,
|
|
484
|
+
key,
|
|
485
|
+
version: CACHE_VERSION
|
|
486
|
+
};
|
|
487
|
+
try {
|
|
488
|
+
await writeJsonFile(path, entry, false);
|
|
489
|
+
} catch (error) {
|
|
490
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
491
|
+
throw new CacheError(`Failed to write cache: ${message}`);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Delete a cached entry
|
|
496
|
+
* @param key - Cache key
|
|
497
|
+
* @returns True if deleted, false if not found
|
|
498
|
+
*/
|
|
499
|
+
async delete(key) {
|
|
500
|
+
const path = this.getPath(key);
|
|
501
|
+
return deleteFile(path);
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Check if a key is cached and not expired
|
|
505
|
+
* @param key - Cache key
|
|
506
|
+
* @returns True if cached and valid
|
|
507
|
+
*/
|
|
508
|
+
async has(key) {
|
|
509
|
+
const data = await this.get(key);
|
|
510
|
+
return data !== null;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Clear all cached data
|
|
514
|
+
*/
|
|
515
|
+
async clear() {
|
|
516
|
+
try {
|
|
517
|
+
await deleteDir(this.dir);
|
|
518
|
+
await ensureDir(this.dir);
|
|
519
|
+
} catch (error) {
|
|
520
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
521
|
+
throw new CacheError(`Failed to clear cache: ${message}`);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Remove expired entries
|
|
526
|
+
* @returns Number of entries removed
|
|
527
|
+
*/
|
|
528
|
+
async prune() {
|
|
529
|
+
let removed = 0;
|
|
530
|
+
try {
|
|
531
|
+
const files = await listFiles(this.dir, true);
|
|
532
|
+
for (const file of files) {
|
|
533
|
+
if (!file.endsWith(".json")) continue;
|
|
534
|
+
const path$1 = path.join(this.dir, file);
|
|
535
|
+
try {
|
|
536
|
+
const entry = await readJsonFile(path$1);
|
|
537
|
+
const expired = entry.version !== CACHE_VERSION || Date.now() - entry.timestamp > entry.ttl;
|
|
538
|
+
if (expired) {
|
|
539
|
+
await deleteFile(path$1);
|
|
540
|
+
removed++;
|
|
541
|
+
}
|
|
542
|
+
} catch {
|
|
543
|
+
await deleteFile(path$1);
|
|
544
|
+
removed++;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
} catch {
|
|
548
|
+
}
|
|
549
|
+
return removed;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Get cache statistics
|
|
553
|
+
* @returns Cache stats
|
|
554
|
+
*/
|
|
555
|
+
async getStats() {
|
|
556
|
+
try {
|
|
557
|
+
if (!await exists(this.dir)) {
|
|
558
|
+
return { entries: 0, size: 0, dir: this.dir };
|
|
559
|
+
}
|
|
560
|
+
const files = await listFiles(this.dir, true);
|
|
561
|
+
const jsonFiles = files.filter((f) => f.endsWith(".json"));
|
|
562
|
+
const size = await getDirSize(this.dir);
|
|
563
|
+
return {
|
|
564
|
+
entries: jsonFiles.length,
|
|
565
|
+
size,
|
|
566
|
+
dir: this.dir
|
|
567
|
+
};
|
|
568
|
+
} catch {
|
|
569
|
+
return { entries: 0, size: 0, dir: this.dir };
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Get cache directory path
|
|
574
|
+
*/
|
|
575
|
+
getDir() {
|
|
576
|
+
return this.dir;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Get default TTL
|
|
580
|
+
*/
|
|
581
|
+
getDefaultTtl() {
|
|
582
|
+
return this.defaultTtl;
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
function createCache(options) {
|
|
586
|
+
if (options?.enabled === false) {
|
|
587
|
+
return null;
|
|
588
|
+
}
|
|
589
|
+
const dir = options?.dir ?? path.join(process.cwd(), DEFAULT_CACHE_DIR);
|
|
590
|
+
const ttl = options?.ttl ?? DEFAULT_TTL;
|
|
591
|
+
return new FileCache(dir, ttl);
|
|
592
|
+
}
|
|
593
|
+
function formatBytes(bytes) {
|
|
594
|
+
if (bytes < 1024) {
|
|
595
|
+
return `${bytes} B`;
|
|
596
|
+
}
|
|
597
|
+
if (bytes < 1024 * 1024) {
|
|
598
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
599
|
+
}
|
|
600
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
601
|
+
}
|
|
602
|
+
function buildPackageCacheKey(name, version, type = "result") {
|
|
603
|
+
return `pkg:${name}@${version}:${type}`;
|
|
604
|
+
}
|
|
605
|
+
var DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
606
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
607
|
+
function createTimeoutController(timeout) {
|
|
608
|
+
const controller = new AbortController();
|
|
609
|
+
const timeoutId = setTimeout(() => {
|
|
610
|
+
controller.abort();
|
|
611
|
+
}, timeout);
|
|
612
|
+
return {
|
|
613
|
+
controller,
|
|
614
|
+
cleanup: () => clearTimeout(timeoutId)
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
async function fetchJson(url, options = {}) {
|
|
618
|
+
const timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
619
|
+
const { controller, cleanup } = createTimeoutController(timeout);
|
|
620
|
+
try {
|
|
621
|
+
const response = await fetch(url, {
|
|
622
|
+
method: "GET",
|
|
623
|
+
headers: {
|
|
624
|
+
Accept: "application/json",
|
|
625
|
+
...options.headers
|
|
626
|
+
},
|
|
627
|
+
signal: controller.signal
|
|
628
|
+
});
|
|
629
|
+
if (!response.ok) {
|
|
630
|
+
throw new DownloadError(`HTTP ${response.status}: ${response.statusText}`, url);
|
|
631
|
+
}
|
|
632
|
+
const data = await response.json();
|
|
633
|
+
return {
|
|
634
|
+
data,
|
|
635
|
+
status: response.status,
|
|
636
|
+
headers: response.headers
|
|
637
|
+
};
|
|
638
|
+
} catch (error) {
|
|
639
|
+
if (error instanceof DownloadError) {
|
|
640
|
+
throw error;
|
|
641
|
+
}
|
|
642
|
+
if (error instanceof Error) {
|
|
643
|
+
if (error.name === "AbortError") {
|
|
644
|
+
throw new TimeoutError(`Request timed out after ${timeout}ms`, timeout);
|
|
645
|
+
}
|
|
646
|
+
throw new DownloadError(error.message, url);
|
|
647
|
+
}
|
|
648
|
+
throw new DownloadError("Unknown fetch error", url);
|
|
649
|
+
} finally {
|
|
650
|
+
cleanup();
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
async function fetchBinary(url, options = {}) {
|
|
654
|
+
const timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
655
|
+
const { controller, cleanup } = createTimeoutController(timeout);
|
|
656
|
+
try {
|
|
657
|
+
const response = await fetch(url, {
|
|
658
|
+
method: "GET",
|
|
659
|
+
headers: {
|
|
660
|
+
Accept: "application/octet-stream",
|
|
661
|
+
...options.headers
|
|
662
|
+
},
|
|
663
|
+
signal: controller.signal
|
|
664
|
+
});
|
|
665
|
+
if (!response.ok) {
|
|
666
|
+
throw new DownloadError(`HTTP ${response.status}: ${response.statusText}`, url);
|
|
667
|
+
}
|
|
668
|
+
const data = await response.arrayBuffer();
|
|
669
|
+
return {
|
|
670
|
+
data,
|
|
671
|
+
status: response.status,
|
|
672
|
+
headers: response.headers
|
|
673
|
+
};
|
|
674
|
+
} catch (error) {
|
|
675
|
+
if (error instanceof DownloadError) {
|
|
676
|
+
throw error;
|
|
677
|
+
}
|
|
678
|
+
if (error instanceof Error) {
|
|
679
|
+
if (error.name === "AbortError") {
|
|
680
|
+
throw new TimeoutError(`Request timed out after ${timeout}ms`, timeout);
|
|
681
|
+
}
|
|
682
|
+
throw new DownloadError(error.message, url);
|
|
683
|
+
}
|
|
684
|
+
throw new DownloadError("Unknown fetch error", url);
|
|
685
|
+
} finally {
|
|
686
|
+
cleanup();
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
async function fetchGzipped(url, options = {}) {
|
|
690
|
+
const { data: gzipped } = await fetchBinary(url, options);
|
|
691
|
+
try {
|
|
692
|
+
return zlib.gunzipSync(Buffer.from(gzipped));
|
|
693
|
+
} catch (error) {
|
|
694
|
+
const message = error instanceof Error ? error.message : "Unknown decompression error";
|
|
695
|
+
throw new DownloadError(`Failed to decompress gzip: ${message}`, url);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
function encodePackageName(name) {
|
|
699
|
+
if (name.startsWith("@")) {
|
|
700
|
+
const slashIndex = name.indexOf("/");
|
|
701
|
+
if (slashIndex === -1) {
|
|
702
|
+
return encodeURIComponent(name);
|
|
703
|
+
}
|
|
704
|
+
const scope = name.slice(0, slashIndex);
|
|
705
|
+
const pkg = name.slice(slashIndex + 1);
|
|
706
|
+
return `${scope}%2F${encodeURIComponent(pkg)}`;
|
|
707
|
+
}
|
|
708
|
+
return encodeURIComponent(name);
|
|
709
|
+
}
|
|
710
|
+
function buildPackageUrl(name, version, registry = DEFAULT_REGISTRY) {
|
|
711
|
+
const encodedName = encodePackageName(name);
|
|
712
|
+
const base = `${registry}/${encodedName}`;
|
|
713
|
+
return version ? `${base}/${version}` : base;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// src/utils/tar.ts
|
|
717
|
+
var BLOCK_SIZE = 512;
|
|
718
|
+
var TAR_TYPES = {
|
|
719
|
+
FILE: "0",
|
|
720
|
+
FILE_ALT: "",
|
|
721
|
+
GNU_LONGNAME: "L"};
|
|
722
|
+
var decoder = new TextDecoder("utf-8");
|
|
723
|
+
function isZeroBlock(buffer, offset) {
|
|
724
|
+
const end = Math.min(offset + BLOCK_SIZE, buffer.length);
|
|
725
|
+
for (let i = offset; i < end; i++) {
|
|
726
|
+
if (buffer[i] !== 0) return false;
|
|
727
|
+
}
|
|
728
|
+
return true;
|
|
729
|
+
}
|
|
730
|
+
function parseOctal(buffer, offset, length) {
|
|
731
|
+
const bytes = buffer.slice(offset, offset + length);
|
|
732
|
+
const str = decoder.decode(bytes).replace(/\0/g, "").trim();
|
|
733
|
+
if (!str) return 0;
|
|
734
|
+
return parseInt(str, 8) || 0;
|
|
735
|
+
}
|
|
736
|
+
function parseString(buffer, offset, length) {
|
|
737
|
+
const bytes = buffer.slice(offset, offset + length);
|
|
738
|
+
const str = decoder.decode(bytes);
|
|
739
|
+
const nullIndex = str.indexOf("\0");
|
|
740
|
+
return nullIndex >= 0 ? str.slice(0, nullIndex) : str;
|
|
741
|
+
}
|
|
742
|
+
function calculateChecksum(buffer, offset) {
|
|
743
|
+
let sum = 0;
|
|
744
|
+
for (let i = 0; i < BLOCK_SIZE; i++) {
|
|
745
|
+
if (i >= 148 && i < 156) {
|
|
746
|
+
sum += 32;
|
|
747
|
+
} else {
|
|
748
|
+
sum += buffer[offset + i] ?? 0;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
return sum;
|
|
752
|
+
}
|
|
753
|
+
function parseTarHeader(buffer, offset) {
|
|
754
|
+
if (isZeroBlock(buffer, offset)) {
|
|
755
|
+
return null;
|
|
756
|
+
}
|
|
757
|
+
if (offset + BLOCK_SIZE > buffer.length) {
|
|
758
|
+
throw new TarError("Unexpected end of tar archive", offset);
|
|
759
|
+
}
|
|
760
|
+
const name = parseString(buffer, offset, 100);
|
|
761
|
+
const mode = parseOctal(buffer, offset + 100, 8);
|
|
762
|
+
const uid = parseOctal(buffer, offset + 108, 8);
|
|
763
|
+
const gid = parseOctal(buffer, offset + 116, 8);
|
|
764
|
+
const size = parseOctal(buffer, offset + 124, 12);
|
|
765
|
+
const mtime = parseOctal(buffer, offset + 136, 12);
|
|
766
|
+
const checksum = parseOctal(buffer, offset + 148, 8);
|
|
767
|
+
const type = parseString(buffer, offset + 156, 1);
|
|
768
|
+
const linkname = parseString(buffer, offset + 157, 100);
|
|
769
|
+
const calculatedChecksum = calculateChecksum(buffer, offset);
|
|
770
|
+
if (checksum !== 0 && checksum !== calculatedChecksum) {
|
|
771
|
+
throw new TarError(`Invalid tar header checksum: expected ${checksum}, got ${calculatedChecksum}`, offset);
|
|
772
|
+
}
|
|
773
|
+
const magic = parseString(buffer, offset + 257, 6);
|
|
774
|
+
let fullName = name;
|
|
775
|
+
if (magic === "ustar" || magic === "ustar ") {
|
|
776
|
+
const prefix = parseString(buffer, offset + 345, 155);
|
|
777
|
+
if (prefix) {
|
|
778
|
+
fullName = `${prefix}/${name}`;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
return {
|
|
782
|
+
name: fullName,
|
|
783
|
+
mode,
|
|
784
|
+
uid,
|
|
785
|
+
gid,
|
|
786
|
+
size,
|
|
787
|
+
mtime,
|
|
788
|
+
checksum,
|
|
789
|
+
type,
|
|
790
|
+
linkname
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
function sanitizePath(path) {
|
|
794
|
+
let normalized = path.replace(/\\/g, "/");
|
|
795
|
+
if (normalized.startsWith("/")) {
|
|
796
|
+
normalized = normalized.slice(1);
|
|
797
|
+
}
|
|
798
|
+
const parts = normalized.split("/");
|
|
799
|
+
const safeParts = [];
|
|
800
|
+
for (const part of parts) {
|
|
801
|
+
if (part === "..") {
|
|
802
|
+
throw new TarError(`Path traversal detected: ${path}`);
|
|
803
|
+
}
|
|
804
|
+
if (part && part !== ".") {
|
|
805
|
+
safeParts.push(part);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
return safeParts.join("/");
|
|
809
|
+
}
|
|
810
|
+
function removePackagePrefix(path) {
|
|
811
|
+
const prefixes = ["package/", "package\\"];
|
|
812
|
+
for (const prefix of prefixes) {
|
|
813
|
+
if (path.startsWith(prefix)) {
|
|
814
|
+
return path.slice(prefix.length);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
return path;
|
|
818
|
+
}
|
|
819
|
+
function getEntryType(_type) {
|
|
820
|
+
return "file";
|
|
821
|
+
}
|
|
822
|
+
function shouldExtract(path) {
|
|
823
|
+
const lower = path.toLowerCase();
|
|
824
|
+
if (lower.endsWith(".d.ts") || lower.endsWith(".d.mts") || lower.endsWith(".d.cts")) {
|
|
825
|
+
return true;
|
|
826
|
+
}
|
|
827
|
+
if (lower.endsWith(".ts") || lower.endsWith(".tsx") || lower.endsWith(".js") || lower.endsWith(".mjs") || lower.endsWith(".cjs") || lower.endsWith(".jsx")) {
|
|
828
|
+
return true;
|
|
829
|
+
}
|
|
830
|
+
if (lower.endsWith(".md") || lower.endsWith(".txt") || lower.endsWith(".json") || lower.endsWith(".yaml") || lower.endsWith(".yml")) {
|
|
831
|
+
return true;
|
|
832
|
+
}
|
|
833
|
+
const filename = path.split("/").pop() ?? "";
|
|
834
|
+
if (filename === "package.json" || filename === "README.md" || filename === "CHANGELOG.md" || filename === "LICENSE" || filename === "LICENSE.md") {
|
|
835
|
+
return true;
|
|
836
|
+
}
|
|
837
|
+
return false;
|
|
838
|
+
}
|
|
839
|
+
function* extractTarSync(buffer) {
|
|
840
|
+
const data = buffer instanceof Buffer ? new Uint8Array(buffer) : new Uint8Array(buffer);
|
|
841
|
+
let offset = 0;
|
|
842
|
+
let gnuLongName = null;
|
|
843
|
+
while (offset < data.length) {
|
|
844
|
+
const header = parseTarHeader(data, offset);
|
|
845
|
+
if (!header) {
|
|
846
|
+
break;
|
|
847
|
+
}
|
|
848
|
+
offset += BLOCK_SIZE;
|
|
849
|
+
if (header.type === TAR_TYPES.GNU_LONGNAME) {
|
|
850
|
+
const contentBytes = data.slice(offset, offset + header.size);
|
|
851
|
+
gnuLongName = decoder.decode(contentBytes).replace(/\0/g, "");
|
|
852
|
+
offset += Math.ceil(header.size / BLOCK_SIZE) * BLOCK_SIZE;
|
|
853
|
+
continue;
|
|
854
|
+
}
|
|
855
|
+
const entryName = gnuLongName ?? header.name;
|
|
856
|
+
gnuLongName = null;
|
|
857
|
+
if (header.type !== TAR_TYPES.FILE && header.type !== TAR_TYPES.FILE_ALT) {
|
|
858
|
+
offset += Math.ceil(header.size / BLOCK_SIZE) * BLOCK_SIZE;
|
|
859
|
+
continue;
|
|
860
|
+
}
|
|
861
|
+
let path;
|
|
862
|
+
try {
|
|
863
|
+
path = sanitizePath(entryName);
|
|
864
|
+
path = removePackagePrefix(path);
|
|
865
|
+
} catch {
|
|
866
|
+
offset += Math.ceil(header.size / BLOCK_SIZE) * BLOCK_SIZE;
|
|
867
|
+
continue;
|
|
868
|
+
}
|
|
869
|
+
if (!shouldExtract(path)) {
|
|
870
|
+
offset += Math.ceil(header.size / BLOCK_SIZE) * BLOCK_SIZE;
|
|
871
|
+
continue;
|
|
872
|
+
}
|
|
873
|
+
const content = data.slice(offset, offset + header.size);
|
|
874
|
+
const textContent = decoder.decode(content);
|
|
875
|
+
yield {
|
|
876
|
+
path,
|
|
877
|
+
content: textContent,
|
|
878
|
+
size: header.size,
|
|
879
|
+
type: getEntryType(header.type)
|
|
880
|
+
};
|
|
881
|
+
offset += Math.ceil(header.size / BLOCK_SIZE) * BLOCK_SIZE;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
function extractTarToMap(buffer) {
|
|
885
|
+
const files = /* @__PURE__ */ new Map();
|
|
886
|
+
for (const entry of extractTarSync(buffer)) {
|
|
887
|
+
if (entry.type === "file") {
|
|
888
|
+
files.set(entry.path, entry.content);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
return files;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
// src/core/fetcher.ts
|
|
895
|
+
function validatePackageName(name) {
|
|
896
|
+
if (!name || typeof name !== "string") {
|
|
897
|
+
throw new ValidationError("Package name is required", "name");
|
|
898
|
+
}
|
|
899
|
+
const validPattern = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
|
|
900
|
+
if (!validPattern.test(name)) {
|
|
901
|
+
throw new ValidationError(
|
|
902
|
+
`Invalid package name: "${name}". Package names must be lowercase and may contain letters, numbers, hyphens, dots, and underscores.`,
|
|
903
|
+
"name"
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
if (name.length > 214) {
|
|
907
|
+
throw new ValidationError("Package name cannot exceed 214 characters", "name");
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
function parsePackageSpec(spec) {
|
|
911
|
+
if (!spec || typeof spec !== "string") {
|
|
912
|
+
throw new ValidationError("Package specifier is required", "spec");
|
|
913
|
+
}
|
|
914
|
+
const trimmed = spec.trim();
|
|
915
|
+
if (trimmed.startsWith("@")) {
|
|
916
|
+
const firstSlash = trimmed.indexOf("/");
|
|
917
|
+
if (firstSlash === -1) {
|
|
918
|
+
throw new ValidationError(`Invalid scoped package: "${spec}"`, "spec");
|
|
919
|
+
}
|
|
920
|
+
const afterScope = trimmed.slice(firstSlash + 1);
|
|
921
|
+
const versionSep = afterScope.lastIndexOf("@");
|
|
922
|
+
if (versionSep > 0) {
|
|
923
|
+
const name = trimmed.slice(0, firstSlash + 1 + versionSep);
|
|
924
|
+
const version = afterScope.slice(versionSep + 1);
|
|
925
|
+
return { name, version: version || void 0 };
|
|
926
|
+
}
|
|
927
|
+
return { name: trimmed };
|
|
928
|
+
}
|
|
929
|
+
const atIndex = trimmed.lastIndexOf("@");
|
|
930
|
+
if (atIndex > 0) {
|
|
931
|
+
const name = trimmed.slice(0, atIndex);
|
|
932
|
+
const version = trimmed.slice(atIndex + 1);
|
|
933
|
+
return { name, version: version || void 0 };
|
|
934
|
+
}
|
|
935
|
+
return { name: trimmed };
|
|
936
|
+
}
|
|
937
|
+
function resolveVersion(packageName, versions, distTags, requested) {
|
|
938
|
+
if (!requested) {
|
|
939
|
+
const latest = distTags["latest"];
|
|
940
|
+
if (latest && versions.includes(latest)) {
|
|
941
|
+
return latest;
|
|
942
|
+
}
|
|
943
|
+
return versions.sort(compareVersions).pop();
|
|
944
|
+
}
|
|
945
|
+
if (distTags[requested]) {
|
|
946
|
+
return distTags[requested];
|
|
947
|
+
}
|
|
948
|
+
if (versions.includes(requested)) {
|
|
949
|
+
return requested;
|
|
950
|
+
}
|
|
951
|
+
const matching = versions.filter((v) => v.startsWith(requested));
|
|
952
|
+
if (matching.length > 0) {
|
|
953
|
+
return matching.sort(compareVersions).pop();
|
|
954
|
+
}
|
|
955
|
+
throw new VersionNotFoundError(packageName, requested);
|
|
956
|
+
}
|
|
957
|
+
function compareVersions(a, b) {
|
|
958
|
+
const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
|
|
959
|
+
const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
|
|
960
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
961
|
+
const na = pa[i] || 0;
|
|
962
|
+
const nb = pb[i] || 0;
|
|
963
|
+
if (na !== nb) return na - nb;
|
|
964
|
+
}
|
|
965
|
+
return 0;
|
|
966
|
+
}
|
|
967
|
+
async function fetchPackageMetadata(name, version, options = {}) {
|
|
968
|
+
validatePackageName(name);
|
|
969
|
+
const registry = options.registry ?? DEFAULT_REGISTRY;
|
|
970
|
+
const httpOptions = { timeout: options.timeout };
|
|
971
|
+
if (version && !["latest", "next", "beta", "alpha"].includes(version)) {
|
|
972
|
+
try {
|
|
973
|
+
const url2 = buildPackageUrl(name, version, registry);
|
|
974
|
+
const { data } = await fetchJson(url2, httpOptions);
|
|
975
|
+
return extractMetadata(data);
|
|
976
|
+
} catch (error) {
|
|
977
|
+
if (!(error instanceof DownloadError) || !error.message.includes("404")) {
|
|
978
|
+
throw error;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
const url = buildPackageUrl(name, void 0, registry);
|
|
983
|
+
try {
|
|
984
|
+
const { data } = await fetchJson(url, httpOptions);
|
|
985
|
+
const versions = Object.keys(data.versions ?? {});
|
|
986
|
+
if (versions.length === 0) {
|
|
987
|
+
throw new PackageNotFoundError(name);
|
|
988
|
+
}
|
|
989
|
+
const resolvedVersion = resolveVersion(
|
|
990
|
+
name,
|
|
991
|
+
versions,
|
|
992
|
+
data["dist-tags"] ?? {},
|
|
993
|
+
version
|
|
994
|
+
);
|
|
995
|
+
const versionData = data.versions[resolvedVersion];
|
|
996
|
+
if (!versionData) {
|
|
997
|
+
throw new VersionNotFoundError(name, resolvedVersion);
|
|
998
|
+
}
|
|
999
|
+
return extractMetadata(versionData);
|
|
1000
|
+
} catch (error) {
|
|
1001
|
+
if (error instanceof DownloadError && error.message.includes("404")) {
|
|
1002
|
+
throw new PackageNotFoundError(name);
|
|
1003
|
+
}
|
|
1004
|
+
throw error;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
function extractMetadata(data) {
|
|
1008
|
+
if (!data.dist?.tarball) {
|
|
1009
|
+
throw new DownloadError("Package metadata missing tarball URL");
|
|
1010
|
+
}
|
|
1011
|
+
let repository;
|
|
1012
|
+
if (data.repository) {
|
|
1013
|
+
if (typeof data.repository === "string") {
|
|
1014
|
+
repository = { type: "git", url: data.repository };
|
|
1015
|
+
} else {
|
|
1016
|
+
repository = data.repository;
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
return {
|
|
1020
|
+
name: data.name,
|
|
1021
|
+
version: data.version,
|
|
1022
|
+
description: data.description,
|
|
1023
|
+
tarball: data.dist.tarball,
|
|
1024
|
+
types: data.types ?? data.typings,
|
|
1025
|
+
main: data.main,
|
|
1026
|
+
exports: data.exports,
|
|
1027
|
+
repository,
|
|
1028
|
+
keywords: data.keywords,
|
|
1029
|
+
author: data.author,
|
|
1030
|
+
license: data.license,
|
|
1031
|
+
homepage: data.homepage
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
async function downloadPackageFiles(tarballUrl, options = {}) {
|
|
1035
|
+
const buffer = await fetchGzipped(tarballUrl, options);
|
|
1036
|
+
return extractTarToMap(buffer);
|
|
1037
|
+
}
|
|
1038
|
+
async function fetchPackage(spec, options = {}) {
|
|
1039
|
+
const { name, version } = parsePackageSpec(spec);
|
|
1040
|
+
const metadata = await fetchPackageMetadata(name, version, options);
|
|
1041
|
+
const files = await downloadPackageFiles(metadata.tarball, {
|
|
1042
|
+
timeout: options.timeout
|
|
1043
|
+
});
|
|
1044
|
+
return {
|
|
1045
|
+
...metadata,
|
|
1046
|
+
files
|
|
1047
|
+
};
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
// src/plugins/core/types-resolver.ts
|
|
1051
|
+
function hasDtsFiles(files) {
|
|
1052
|
+
for (const path of files.keys()) {
|
|
1053
|
+
if (path.endsWith(".d.ts")) {
|
|
1054
|
+
return true;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
return false;
|
|
1058
|
+
}
|
|
1059
|
+
function getTypesPackageName(packageName) {
|
|
1060
|
+
if (packageName.startsWith("@")) {
|
|
1061
|
+
const withoutAt = packageName.slice(1);
|
|
1062
|
+
return `@types/${withoutAt.replace("/", "__")}`;
|
|
1063
|
+
}
|
|
1064
|
+
return `@types/${packageName}`;
|
|
1065
|
+
}
|
|
1066
|
+
function isTypesPackage(packageName) {
|
|
1067
|
+
return packageName.startsWith("@types/");
|
|
1068
|
+
}
|
|
1069
|
+
var typesResolverPlugin = {
|
|
1070
|
+
name: "types-resolver",
|
|
1071
|
+
version: "1.0.0",
|
|
1072
|
+
category: "parser",
|
|
1073
|
+
install(kernel) {
|
|
1074
|
+
kernel.on("package:fetched", async (context) => {
|
|
1075
|
+
const { files, name } = context.package;
|
|
1076
|
+
if (isTypesPackage(name)) {
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
if (hasDtsFiles(files)) {
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
const typesPackageName = getTypesPackageName(name);
|
|
1083
|
+
try {
|
|
1084
|
+
const typesPackage = await fetchPackage(typesPackageName);
|
|
1085
|
+
let mergedCount = 0;
|
|
1086
|
+
for (const [path, content] of typesPackage.files) {
|
|
1087
|
+
if (path.endsWith(".d.ts")) {
|
|
1088
|
+
const newPath = `__types__/${path}`;
|
|
1089
|
+
files.set(newPath, content);
|
|
1090
|
+
mergedCount++;
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
if (typesPackage.types && !context.package.types) {
|
|
1094
|
+
context.package.types = `__types__/${typesPackage.types}`;
|
|
1095
|
+
}
|
|
1096
|
+
if (mergedCount > 0) {
|
|
1097
|
+
console.error(
|
|
1098
|
+
`[types-resolver] Merged ${mergedCount} .d.ts files from ${typesPackageName}`
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1101
|
+
} catch (error) {
|
|
1102
|
+
}
|
|
1103
|
+
});
|
|
1104
|
+
}
|
|
1105
|
+
};
|
|
1106
|
+
|
|
1107
|
+
// src/parsers/jsdoc.ts
|
|
1108
|
+
var TAG_PATTERNS = {
|
|
1109
|
+
/** @param {type} name - description */
|
|
1110
|
+
param: /@param\s+(?:\{([^}]*)\})?\s*(\[?\w+(?:\.\w+)*\]?)\s*(?:-\s*)?(.*)$/gm,
|
|
1111
|
+
/** @returns {type} description */
|
|
1112
|
+
returns: /@returns?\s+(?:\{([^}]*)\})?\s*(.*)/g,
|
|
1113
|
+
/** @example ... */
|
|
1114
|
+
example: /@example\s*([\s\S]*?)(?=@\w|$)/g,
|
|
1115
|
+
/** @deprecated reason */
|
|
1116
|
+
deprecated: /@deprecated\s*(.*)/g,
|
|
1117
|
+
/** @since version */
|
|
1118
|
+
since: /@since\s*(.*)/g,
|
|
1119
|
+
/** @see reference */
|
|
1120
|
+
see: /@see\s*(.*)/g,
|
|
1121
|
+
/** @throws {type} description */
|
|
1122
|
+
throws: /@throws?\s+(?:\{([^}]*)\})?\s*(.*)/g,
|
|
1123
|
+
/** @template T - description */
|
|
1124
|
+
typeParam: /@template\s+(\w+)\s*(?:-\s*)?(.*)/g};
|
|
1125
|
+
function cleanJSDocComment(comment) {
|
|
1126
|
+
return comment.replace(/^\/\*\*\s*/, "").replace(/\s*\*\/$/, "").replace(/^\s*\*\s?/gm, "").trim();
|
|
1127
|
+
}
|
|
1128
|
+
function extractDescription(content) {
|
|
1129
|
+
const tagMatch = content.match(/@\w+/);
|
|
1130
|
+
if (!tagMatch) {
|
|
1131
|
+
return content.trim() || void 0;
|
|
1132
|
+
}
|
|
1133
|
+
const description = content.slice(0, tagMatch.index).trim();
|
|
1134
|
+
return description || void 0;
|
|
1135
|
+
}
|
|
1136
|
+
function parseParams(content) {
|
|
1137
|
+
const params = [];
|
|
1138
|
+
const pattern = new RegExp(TAG_PATTERNS.param.source, "gm");
|
|
1139
|
+
let match;
|
|
1140
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
1141
|
+
const [, type, rawName, description] = match;
|
|
1142
|
+
if (!rawName) continue;
|
|
1143
|
+
const name = rawName;
|
|
1144
|
+
const isOptional = name.startsWith("[") && name.endsWith("]");
|
|
1145
|
+
const cleanName = isOptional ? name.slice(1, -1) : name;
|
|
1146
|
+
params.push({
|
|
1147
|
+
name: cleanName,
|
|
1148
|
+
type: type?.trim(),
|
|
1149
|
+
description: description?.trim() || void 0,
|
|
1150
|
+
optional: isOptional
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
return params;
|
|
1154
|
+
}
|
|
1155
|
+
function parseReturns(content) {
|
|
1156
|
+
const pattern = new RegExp(TAG_PATTERNS.returns.source, "g");
|
|
1157
|
+
const match = pattern.exec(content);
|
|
1158
|
+
if (!match) return void 0;
|
|
1159
|
+
const [, type, description] = match;
|
|
1160
|
+
return {
|
|
1161
|
+
type: type?.trim(),
|
|
1162
|
+
description: description?.trim() || void 0
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
function parseExamples(content) {
|
|
1166
|
+
const examples = [];
|
|
1167
|
+
const pattern = new RegExp(TAG_PATTERNS.example.source, "g");
|
|
1168
|
+
let match;
|
|
1169
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
1170
|
+
const example = match[1]?.trim();
|
|
1171
|
+
if (example) {
|
|
1172
|
+
examples.push(example);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
return examples;
|
|
1176
|
+
}
|
|
1177
|
+
function parseDeprecated(content) {
|
|
1178
|
+
const pattern = new RegExp(TAG_PATTERNS.deprecated.source, "g");
|
|
1179
|
+
const match = pattern.exec(content);
|
|
1180
|
+
return match ? match[1]?.trim() || "true" : void 0;
|
|
1181
|
+
}
|
|
1182
|
+
function parseSince(content) {
|
|
1183
|
+
const pattern = new RegExp(TAG_PATTERNS.since.source, "g");
|
|
1184
|
+
const match = pattern.exec(content);
|
|
1185
|
+
return match ? match[1]?.trim() : void 0;
|
|
1186
|
+
}
|
|
1187
|
+
function parseSee(content) {
|
|
1188
|
+
const refs = [];
|
|
1189
|
+
const pattern = new RegExp(TAG_PATTERNS.see.source, "g");
|
|
1190
|
+
let match;
|
|
1191
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
1192
|
+
const ref = match[1]?.trim();
|
|
1193
|
+
if (ref) {
|
|
1194
|
+
refs.push(ref);
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
return refs;
|
|
1198
|
+
}
|
|
1199
|
+
function parseThrows(content) {
|
|
1200
|
+
const throws = [];
|
|
1201
|
+
const pattern = new RegExp(TAG_PATTERNS.throws.source, "g");
|
|
1202
|
+
let match;
|
|
1203
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
1204
|
+
const [, type, description] = match;
|
|
1205
|
+
throws.push({
|
|
1206
|
+
type: type?.trim(),
|
|
1207
|
+
description: description?.trim() || void 0
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1210
|
+
return throws;
|
|
1211
|
+
}
|
|
1212
|
+
function parseTypeParams(content) {
|
|
1213
|
+
const params = [];
|
|
1214
|
+
const pattern = new RegExp(TAG_PATTERNS.typeParam.source, "g");
|
|
1215
|
+
let match;
|
|
1216
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
1217
|
+
const [, name, description] = match;
|
|
1218
|
+
if (!name) continue;
|
|
1219
|
+
params.push({
|
|
1220
|
+
name: name.trim(),
|
|
1221
|
+
description: description?.trim() || void 0
|
|
1222
|
+
});
|
|
1223
|
+
}
|
|
1224
|
+
return params;
|
|
1225
|
+
}
|
|
1226
|
+
function parseJSDoc(comment) {
|
|
1227
|
+
const content = cleanJSDocComment(comment);
|
|
1228
|
+
return {
|
|
1229
|
+
description: extractDescription(content),
|
|
1230
|
+
params: parseParams(content).map((p) => ({
|
|
1231
|
+
name: p.name,
|
|
1232
|
+
type: p.type,
|
|
1233
|
+
description: p.description,
|
|
1234
|
+
optional: p.optional,
|
|
1235
|
+
defaultValue: p.defaultValue
|
|
1236
|
+
})),
|
|
1237
|
+
returns: parseReturns(content),
|
|
1238
|
+
examples: parseExamples(content),
|
|
1239
|
+
deprecated: parseDeprecated(content),
|
|
1240
|
+
since: parseSince(content),
|
|
1241
|
+
see: parseSee(content),
|
|
1242
|
+
throws: parseThrows(content),
|
|
1243
|
+
typeParams: parseTypeParams(content)
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
function extractJSDocComments(source) {
|
|
1247
|
+
const comments = [];
|
|
1248
|
+
const pattern = /\/\*\*[\s\S]*?\*\//g;
|
|
1249
|
+
let match;
|
|
1250
|
+
while ((match = pattern.exec(source)) !== null) {
|
|
1251
|
+
comments.push({
|
|
1252
|
+
comment: match[0],
|
|
1253
|
+
start: match.index,
|
|
1254
|
+
end: match.index + match[0].length
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
return comments;
|
|
1258
|
+
}
|
|
1259
|
+
function findPrecedingJSDoc(source, position, comments) {
|
|
1260
|
+
const allComments = comments ?? extractJSDocComments(source);
|
|
1261
|
+
for (let i = allComments.length - 1; i >= 0; i--) {
|
|
1262
|
+
const comment = allComments[i];
|
|
1263
|
+
if (!comment || comment.end > position) continue;
|
|
1264
|
+
const between = source.slice(comment.end, position);
|
|
1265
|
+
if (/^\s*$/.test(between)) {
|
|
1266
|
+
return parseJSDoc(comment.comment);
|
|
1267
|
+
}
|
|
1268
|
+
if (comment.end < position - 500) break;
|
|
1269
|
+
}
|
|
1270
|
+
return void 0;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
// src/parsers/dts.ts
|
|
1274
|
+
var PATTERNS = {
|
|
1275
|
+
/** Export function declaration */
|
|
1276
|
+
exportFunction: /export\s+(?:declare\s+)?function\s+(\w+)\s*(<[^>]*>)?\s*\(([^)]*)\)\s*:\s*([^;{]+)/g,
|
|
1277
|
+
/** Export const declaration */
|
|
1278
|
+
exportConst: /export\s+(?:declare\s+)?const\s+(\w+)\s*:\s*([^;=]+)/g,
|
|
1279
|
+
/** Export class declaration */
|
|
1280
|
+
exportClass: /export\s+(?:declare\s+)?(?:abstract\s+)?class\s+(\w+)(?:\s*<([^>]*)>)?(?:\s+extends\s+([^\s{]+))?(?:\s+implements\s+([^{]+))?\s*\{/g,
|
|
1281
|
+
/** Export interface declaration */
|
|
1282
|
+
exportInterface: /export\s+(?:declare\s+)?interface\s+(\w+)(?:\s*<([^>]*)>)?(?:\s+extends\s+([^{]+))?\s*\{/g,
|
|
1283
|
+
/** Export type declaration */
|
|
1284
|
+
exportType: /export\s+(?:declare\s+)?type\s+(\w+)(?:\s*<([^>]*)>)?\s*=\s*([^;]+)/g,
|
|
1285
|
+
/** Export enum declaration */
|
|
1286
|
+
exportEnum: /export\s+(?:declare\s+)?(?:const\s+)?enum\s+(\w+)\s*\{/g,
|
|
1287
|
+
/** Import statement */
|
|
1288
|
+
importStatement: /import\s*(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s*from\s*['"]([^'"]+)['"]/g,
|
|
1289
|
+
/** Declare module (module augmentation) */
|
|
1290
|
+
declareModule: /declare\s+module\s+['"]([^'"]+)['"]\s*\{/g};
|
|
1291
|
+
function parseParameters(paramStr) {
|
|
1292
|
+
if (!paramStr.trim()) return [];
|
|
1293
|
+
const params = [];
|
|
1294
|
+
const parts = splitParameters(paramStr);
|
|
1295
|
+
for (const part of parts) {
|
|
1296
|
+
const trimmed = part.trim();
|
|
1297
|
+
if (!trimmed) continue;
|
|
1298
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
1299
|
+
const colonIndex = findTypeColonIndex(trimmed);
|
|
1300
|
+
if (colonIndex > 0) {
|
|
1301
|
+
params.push({
|
|
1302
|
+
name: "options",
|
|
1303
|
+
type: trimmed.slice(colonIndex + 1).trim(),
|
|
1304
|
+
optional: trimmed.includes("?")
|
|
1305
|
+
});
|
|
1306
|
+
}
|
|
1307
|
+
continue;
|
|
1308
|
+
}
|
|
1309
|
+
const match = trimmed.match(/^(\w+)(\?)?\s*:\s*(.+?)(?:\s*=\s*(.+))?$/);
|
|
1310
|
+
if (match) {
|
|
1311
|
+
const [, name, optional, type, defaultValue] = match;
|
|
1312
|
+
if (name && type) {
|
|
1313
|
+
params.push({
|
|
1314
|
+
name,
|
|
1315
|
+
type: type.trim(),
|
|
1316
|
+
optional: !!optional,
|
|
1317
|
+
defaultValue: defaultValue?.trim()
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
} else {
|
|
1321
|
+
const nameMatch = trimmed.match(/^(\w+)(\?)?$/);
|
|
1322
|
+
if (nameMatch && nameMatch[1]) {
|
|
1323
|
+
params.push({
|
|
1324
|
+
name: nameMatch[1],
|
|
1325
|
+
type: "unknown",
|
|
1326
|
+
optional: !!nameMatch[2]
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
return params;
|
|
1332
|
+
}
|
|
1333
|
+
function splitParameters(paramStr) {
|
|
1334
|
+
const parts = [];
|
|
1335
|
+
let current = "";
|
|
1336
|
+
let depth = 0;
|
|
1337
|
+
for (let i = 0; i < paramStr.length; i++) {
|
|
1338
|
+
const char = paramStr[i];
|
|
1339
|
+
if (char === "<" || char === "{" || char === "[" || char === "(") {
|
|
1340
|
+
depth++;
|
|
1341
|
+
current += char;
|
|
1342
|
+
} else if (char === ">" || char === "}" || char === "]" || char === ")") {
|
|
1343
|
+
depth--;
|
|
1344
|
+
current += char;
|
|
1345
|
+
} else if (char === "," && depth === 0) {
|
|
1346
|
+
parts.push(current);
|
|
1347
|
+
current = "";
|
|
1348
|
+
} else {
|
|
1349
|
+
current += char;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
if (current.trim()) {
|
|
1353
|
+
parts.push(current);
|
|
1354
|
+
}
|
|
1355
|
+
return parts;
|
|
1356
|
+
}
|
|
1357
|
+
function findTypeColonIndex(str) {
|
|
1358
|
+
let depth = 0;
|
|
1359
|
+
for (let i = 0; i < str.length; i++) {
|
|
1360
|
+
const char = str[i];
|
|
1361
|
+
if (char === "{" || char === "[" || char === "<" || char === "(") {
|
|
1362
|
+
depth++;
|
|
1363
|
+
} else if (char === "}" || char === "]" || char === ">" || char === ")") {
|
|
1364
|
+
depth--;
|
|
1365
|
+
} else if (char === ":" && depth === 0) {
|
|
1366
|
+
return i;
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
return -1;
|
|
1370
|
+
}
|
|
1371
|
+
function extractBody(source, startIndex) {
|
|
1372
|
+
let depth = 0;
|
|
1373
|
+
let i = startIndex;
|
|
1374
|
+
while (i < source.length) {
|
|
1375
|
+
if (source[i] === "{") depth++;
|
|
1376
|
+
else if (source[i] === "}") {
|
|
1377
|
+
depth--;
|
|
1378
|
+
if (depth === 0) break;
|
|
1379
|
+
}
|
|
1380
|
+
i++;
|
|
1381
|
+
}
|
|
1382
|
+
return source.slice(startIndex + 1, i);
|
|
1383
|
+
}
|
|
1384
|
+
function parseClassMembers(body, comments, bodyOffset) {
|
|
1385
|
+
const methods = [];
|
|
1386
|
+
const properties = [];
|
|
1387
|
+
const methodPattern = /(?:(?:public|private|protected|static|readonly)\s+)*(\w+)\s*(<[^>]*>)?\s*\(([^)]*)\)\s*:\s*([^;{]+)/g;
|
|
1388
|
+
let match;
|
|
1389
|
+
while ((match = methodPattern.exec(body)) !== null) {
|
|
1390
|
+
const [fullMatch, name, generics, params, returnType] = match;
|
|
1391
|
+
if (!name || !returnType) continue;
|
|
1392
|
+
const jsdoc = findPrecedingJSDoc(body, match.index, comments.map((c) => ({
|
|
1393
|
+
...c,
|
|
1394
|
+
start: c.start - bodyOffset,
|
|
1395
|
+
end: c.end - bodyOffset
|
|
1396
|
+
})));
|
|
1397
|
+
methods.push({
|
|
1398
|
+
kind: "function",
|
|
1399
|
+
name,
|
|
1400
|
+
signature: `${name}${generics || ""}(${params || ""}): ${returnType.trim()}`,
|
|
1401
|
+
description: jsdoc?.description,
|
|
1402
|
+
params: mergeParamDocs(parseParameters(params || ""), jsdoc?.params),
|
|
1403
|
+
returns: {
|
|
1404
|
+
type: returnType.trim(),
|
|
1405
|
+
description: jsdoc?.returns?.description
|
|
1406
|
+
},
|
|
1407
|
+
examples: jsdoc?.examples
|
|
1408
|
+
});
|
|
1409
|
+
}
|
|
1410
|
+
const propPattern = /(?:(?:public|private|protected|static|readonly)\s+)*(\w+)(\?)?\s*:\s*([^;]+)/g;
|
|
1411
|
+
while ((match = propPattern.exec(body)) !== null) {
|
|
1412
|
+
const [, name, optional, type] = match;
|
|
1413
|
+
if (!name || !type) continue;
|
|
1414
|
+
if (type.includes("=>") || type.includes("(")) continue;
|
|
1415
|
+
properties.push({
|
|
1416
|
+
kind: "constant",
|
|
1417
|
+
name,
|
|
1418
|
+
signature: `${name}${optional || ""}: ${type.trim()}`,
|
|
1419
|
+
description: findPrecedingJSDoc(body, match.index)?.description
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1422
|
+
return { methods, properties };
|
|
1423
|
+
}
|
|
1424
|
+
function mergeParamDocs(sigParams, jsdocParams) {
|
|
1425
|
+
if (!jsdocParams || jsdocParams.length === 0) return sigParams;
|
|
1426
|
+
return sigParams.map((param) => {
|
|
1427
|
+
const jsdocParam = jsdocParams.find((p) => p.name === param.name);
|
|
1428
|
+
if (jsdocParam) {
|
|
1429
|
+
return {
|
|
1430
|
+
...param,
|
|
1431
|
+
description: jsdocParam.description || param.description,
|
|
1432
|
+
type: param.type || jsdocParam.type,
|
|
1433
|
+
optional: param.optional || jsdocParam.optional,
|
|
1434
|
+
defaultValue: param.defaultValue || jsdocParam.defaultValue
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1437
|
+
return param;
|
|
1438
|
+
});
|
|
1439
|
+
}
|
|
1440
|
+
function parseEnumMembers(body) {
|
|
1441
|
+
const members = [];
|
|
1442
|
+
const pattern = /(\w+)\s*(?:=\s*([^,}]+))?/g;
|
|
1443
|
+
let match;
|
|
1444
|
+
while ((match = pattern.exec(body)) !== null) {
|
|
1445
|
+
const [, name, value] = match;
|
|
1446
|
+
if (!name) continue;
|
|
1447
|
+
let parsedValue;
|
|
1448
|
+
if (value !== void 0) {
|
|
1449
|
+
const trimmed = value.trim();
|
|
1450
|
+
const num = Number(trimmed);
|
|
1451
|
+
if (!isNaN(num)) {
|
|
1452
|
+
parsedValue = num;
|
|
1453
|
+
} else {
|
|
1454
|
+
parsedValue = trimmed.replace(/^['"]|['"]$/g, "");
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
members.push({ name, value: parsedValue });
|
|
1458
|
+
}
|
|
1459
|
+
return members;
|
|
1460
|
+
}
|
|
1461
|
+
function parseDts(content, filePath) {
|
|
1462
|
+
const exports$1 = [];
|
|
1463
|
+
const imports = [];
|
|
1464
|
+
let moduleName;
|
|
1465
|
+
const comments = extractJSDocComments(content);
|
|
1466
|
+
const moduleMatch = PATTERNS.declareModule.exec(content);
|
|
1467
|
+
if (moduleMatch) {
|
|
1468
|
+
moduleName = moduleMatch[1];
|
|
1469
|
+
}
|
|
1470
|
+
let match;
|
|
1471
|
+
PATTERNS.exportFunction.lastIndex = 0;
|
|
1472
|
+
while ((match = PATTERNS.exportFunction.exec(content)) !== null) {
|
|
1473
|
+
const [fullMatch, name, generics, params, returnType] = match;
|
|
1474
|
+
if (!name || !returnType) continue;
|
|
1475
|
+
const jsdoc = findPrecedingJSDoc(content, match.index, comments);
|
|
1476
|
+
exports$1.push({
|
|
1477
|
+
kind: "function",
|
|
1478
|
+
name,
|
|
1479
|
+
signature: `function ${name}${generics || ""}(${params || ""}): ${returnType.trim()}`,
|
|
1480
|
+
description: jsdoc?.description,
|
|
1481
|
+
params: mergeParamDocs(parseParameters(params || ""), jsdoc?.params),
|
|
1482
|
+
returns: {
|
|
1483
|
+
type: returnType.trim(),
|
|
1484
|
+
description: jsdoc?.returns?.description
|
|
1485
|
+
},
|
|
1486
|
+
examples: jsdoc?.examples,
|
|
1487
|
+
deprecated: jsdoc?.deprecated ? jsdoc.deprecated : void 0,
|
|
1488
|
+
since: jsdoc?.since,
|
|
1489
|
+
see: jsdoc?.see,
|
|
1490
|
+
sourceFile: filePath
|
|
1491
|
+
});
|
|
1492
|
+
}
|
|
1493
|
+
PATTERNS.exportConst.lastIndex = 0;
|
|
1494
|
+
while ((match = PATTERNS.exportConst.exec(content)) !== null) {
|
|
1495
|
+
const [, name, type] = match;
|
|
1496
|
+
if (!name || !type) continue;
|
|
1497
|
+
const jsdoc = findPrecedingJSDoc(content, match.index, comments);
|
|
1498
|
+
exports$1.push({
|
|
1499
|
+
kind: "constant",
|
|
1500
|
+
name,
|
|
1501
|
+
signature: `const ${name}: ${type.trim()}`,
|
|
1502
|
+
description: jsdoc?.description,
|
|
1503
|
+
deprecated: jsdoc?.deprecated ? jsdoc.deprecated : void 0,
|
|
1504
|
+
sourceFile: filePath
|
|
1505
|
+
});
|
|
1506
|
+
}
|
|
1507
|
+
PATTERNS.exportClass.lastIndex = 0;
|
|
1508
|
+
while ((match = PATTERNS.exportClass.exec(content)) !== null) {
|
|
1509
|
+
const [, name, generics, extendsClause, implementsClause] = match;
|
|
1510
|
+
if (!name) continue;
|
|
1511
|
+
const jsdoc = findPrecedingJSDoc(content, match.index, comments);
|
|
1512
|
+
const bodyStart = match.index + match[0].length - 1;
|
|
1513
|
+
const body = extractBody(content, bodyStart);
|
|
1514
|
+
const { methods, properties } = parseClassMembers(body, comments, bodyStart);
|
|
1515
|
+
exports$1.push({
|
|
1516
|
+
kind: "class",
|
|
1517
|
+
name,
|
|
1518
|
+
signature: `class ${name}${generics ? `<${generics}>` : ""}`,
|
|
1519
|
+
description: jsdoc?.description,
|
|
1520
|
+
extends: extendsClause ? [extendsClause.trim()] : void 0,
|
|
1521
|
+
implements: implementsClause ? implementsClause.split(",").map((s) => s.trim()) : void 0,
|
|
1522
|
+
methods,
|
|
1523
|
+
properties,
|
|
1524
|
+
typeParams: generics ? generics.split(",").map((s) => s.trim()) : void 0,
|
|
1525
|
+
deprecated: jsdoc?.deprecated ? jsdoc.deprecated : void 0,
|
|
1526
|
+
sourceFile: filePath
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
PATTERNS.exportInterface.lastIndex = 0;
|
|
1530
|
+
while ((match = PATTERNS.exportInterface.exec(content)) !== null) {
|
|
1531
|
+
const [, name, generics, extendsClause] = match;
|
|
1532
|
+
if (!name) continue;
|
|
1533
|
+
const jsdoc = findPrecedingJSDoc(content, match.index, comments);
|
|
1534
|
+
const bodyStart = match.index + match[0].length - 1;
|
|
1535
|
+
const body = extractBody(content, bodyStart);
|
|
1536
|
+
const { methods, properties } = parseClassMembers(body, comments, bodyStart);
|
|
1537
|
+
exports$1.push({
|
|
1538
|
+
kind: "interface",
|
|
1539
|
+
name,
|
|
1540
|
+
signature: `interface ${name}${generics ? `<${generics}>` : ""}`,
|
|
1541
|
+
description: jsdoc?.description,
|
|
1542
|
+
extends: extendsClause ? extendsClause.split(",").map((s) => s.trim()) : void 0,
|
|
1543
|
+
methods,
|
|
1544
|
+
properties,
|
|
1545
|
+
typeParams: generics ? generics.split(",").map((s) => s.trim()) : void 0,
|
|
1546
|
+
deprecated: jsdoc?.deprecated ? jsdoc.deprecated : void 0,
|
|
1547
|
+
sourceFile: filePath
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1550
|
+
PATTERNS.exportType.lastIndex = 0;
|
|
1551
|
+
while ((match = PATTERNS.exportType.exec(content)) !== null) {
|
|
1552
|
+
const [, name, generics, definition] = match;
|
|
1553
|
+
if (!name || !definition) continue;
|
|
1554
|
+
const jsdoc = findPrecedingJSDoc(content, match.index, comments);
|
|
1555
|
+
exports$1.push({
|
|
1556
|
+
kind: "type",
|
|
1557
|
+
name,
|
|
1558
|
+
signature: `type ${name}${generics ? `<${generics}>` : ""} = ${definition.trim()}`,
|
|
1559
|
+
description: jsdoc?.description,
|
|
1560
|
+
typeParams: generics ? generics.split(",").map((s) => s.trim()) : void 0,
|
|
1561
|
+
deprecated: jsdoc?.deprecated ? jsdoc.deprecated : void 0,
|
|
1562
|
+
sourceFile: filePath
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1565
|
+
PATTERNS.exportEnum.lastIndex = 0;
|
|
1566
|
+
while ((match = PATTERNS.exportEnum.exec(content)) !== null) {
|
|
1567
|
+
const [, name] = match;
|
|
1568
|
+
if (!name) continue;
|
|
1569
|
+
const jsdoc = findPrecedingJSDoc(content, match.index, comments);
|
|
1570
|
+
const bodyStart = match.index + match[0].length - 1;
|
|
1571
|
+
const body = extractBody(content, bodyStart);
|
|
1572
|
+
const members = parseEnumMembers(body);
|
|
1573
|
+
exports$1.push({
|
|
1574
|
+
kind: "enum",
|
|
1575
|
+
name,
|
|
1576
|
+
signature: `enum ${name}`,
|
|
1577
|
+
description: jsdoc?.description,
|
|
1578
|
+
members,
|
|
1579
|
+
deprecated: jsdoc?.deprecated ? jsdoc.deprecated : void 0,
|
|
1580
|
+
sourceFile: filePath
|
|
1581
|
+
});
|
|
1582
|
+
}
|
|
1583
|
+
PATTERNS.importStatement.lastIndex = 0;
|
|
1584
|
+
while ((match = PATTERNS.importStatement.exec(content)) !== null) {
|
|
1585
|
+
if (match[1]) {
|
|
1586
|
+
imports.push(match[1]);
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
PATTERNS.declareModule.lastIndex = 0;
|
|
1590
|
+
while ((match = PATTERNS.declareModule.exec(content)) !== null) {
|
|
1591
|
+
const moduleBodyStart = match.index + match[0].length - 1;
|
|
1592
|
+
const moduleBody = extractBody(content, moduleBodyStart);
|
|
1593
|
+
const moduleExports = parseModuleAugmentation(moduleBody, comments, moduleBodyStart, filePath);
|
|
1594
|
+
for (const entry of moduleExports) {
|
|
1595
|
+
exports$1.push(entry);
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
return { exports: exports$1, imports, moduleName };
|
|
1599
|
+
}
|
|
1600
|
+
function parseModuleAugmentation(body, _comments, _bodyOffset, filePath) {
|
|
1601
|
+
const entries = [];
|
|
1602
|
+
const moduleComments = extractJSDocComments(body);
|
|
1603
|
+
const interfacePattern = /interface\s+(\w+)(?:\s*<([^>]*)>)?(?:\s+extends\s+([^{]+))?\s*\{/g;
|
|
1604
|
+
let match;
|
|
1605
|
+
while ((match = interfacePattern.exec(body)) !== null) {
|
|
1606
|
+
const [, interfaceName, generics, extendsClause] = match;
|
|
1607
|
+
if (!interfaceName) continue;
|
|
1608
|
+
const ifaceBodyStart = match.index + match[0].length - 1;
|
|
1609
|
+
const ifaceBody = extractBody(body, ifaceBodyStart);
|
|
1610
|
+
if (interfaceName === "LoDashStatic" || interfaceName.endsWith("Static")) {
|
|
1611
|
+
const methods = parseInterfaceMethodsAsExports(
|
|
1612
|
+
ifaceBody,
|
|
1613
|
+
moduleComments,
|
|
1614
|
+
ifaceBodyStart,
|
|
1615
|
+
filePath
|
|
1616
|
+
);
|
|
1617
|
+
for (const method of methods) {
|
|
1618
|
+
entries.push(method);
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
return entries;
|
|
1623
|
+
}
|
|
1624
|
+
function parseInterfaceMethodsAsExports(body, _comments, _bodyOffset, filePath) {
|
|
1625
|
+
const methods = [];
|
|
1626
|
+
const bodyComments = extractJSDocComments(body);
|
|
1627
|
+
const methodPattern = /(\w+)\s*(<[^>]*>)?\s*\(([^)]*)\)\s*:\s*([^;]+);/g;
|
|
1628
|
+
let match;
|
|
1629
|
+
while ((match = methodPattern.exec(body)) !== null) {
|
|
1630
|
+
const [fullMatch, name, generics, params, returnType] = match;
|
|
1631
|
+
if (!name || !returnType) continue;
|
|
1632
|
+
if (["constructor", "toString", "valueOf", "toJSON"].includes(name)) continue;
|
|
1633
|
+
const jsdoc = findPrecedingJSDoc(body, match.index, bodyComments);
|
|
1634
|
+
methods.push({
|
|
1635
|
+
kind: "function",
|
|
1636
|
+
name,
|
|
1637
|
+
signature: `function ${name}${generics || ""}(${params || ""}): ${returnType.trim()}`,
|
|
1638
|
+
description: jsdoc?.description,
|
|
1639
|
+
params: mergeParamDocs(parseParameters(params || ""), jsdoc?.params),
|
|
1640
|
+
returns: {
|
|
1641
|
+
type: returnType.trim(),
|
|
1642
|
+
description: jsdoc?.returns?.description
|
|
1643
|
+
},
|
|
1644
|
+
examples: jsdoc?.examples,
|
|
1645
|
+
deprecated: jsdoc?.deprecated ? jsdoc.deprecated : void 0,
|
|
1646
|
+
since: jsdoc?.since,
|
|
1647
|
+
see: jsdoc?.see,
|
|
1648
|
+
sourceFile: filePath
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
1651
|
+
return methods;
|
|
1652
|
+
}
|
|
1653
|
+
function sortExports(exports$1) {
|
|
1654
|
+
const kindOrder = {
|
|
1655
|
+
function: 1,
|
|
1656
|
+
class: 2,
|
|
1657
|
+
interface: 3,
|
|
1658
|
+
type: 4,
|
|
1659
|
+
enum: 5,
|
|
1660
|
+
constant: 6
|
|
1661
|
+
};
|
|
1662
|
+
return [...exports$1].sort((a, b) => {
|
|
1663
|
+
const kindDiff = kindOrder[a.kind] - kindOrder[b.kind];
|
|
1664
|
+
if (kindDiff !== 0) return kindDiff;
|
|
1665
|
+
return a.name.localeCompare(b.name);
|
|
1666
|
+
});
|
|
1667
|
+
}
|
|
1668
|
+
function findMainDtsFile(files, typesField) {
|
|
1669
|
+
if (typesField) {
|
|
1670
|
+
const normalized = typesField.replace(/^\.\//, "");
|
|
1671
|
+
if (files.has(normalized)) return normalized;
|
|
1672
|
+
}
|
|
1673
|
+
const priorities = [
|
|
1674
|
+
"index.d.ts",
|
|
1675
|
+
"dist/index.d.ts",
|
|
1676
|
+
"lib/index.d.ts",
|
|
1677
|
+
"types/index.d.ts",
|
|
1678
|
+
"src/index.d.ts",
|
|
1679
|
+
// @types packages merged via types-resolver plugin
|
|
1680
|
+
"__types__/index.d.ts",
|
|
1681
|
+
"__types__/dist/index.d.ts",
|
|
1682
|
+
"__types__/lib/index.d.ts",
|
|
1683
|
+
"__types__/types/index.d.ts"
|
|
1684
|
+
];
|
|
1685
|
+
for (const path of priorities) {
|
|
1686
|
+
if (files.has(path)) return path;
|
|
1687
|
+
}
|
|
1688
|
+
for (const path of files.keys()) {
|
|
1689
|
+
if (path.endsWith(".d.ts") && !path.startsWith("__types__/")) {
|
|
1690
|
+
return path;
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
for (const path of files.keys()) {
|
|
1694
|
+
if (path.endsWith(".d.ts") && path.startsWith("__types__/")) {
|
|
1695
|
+
return path;
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
return void 0;
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
// src/plugins/core/dts-parser.ts
|
|
1702
|
+
var dtsParserPlugin = {
|
|
1703
|
+
name: "dts-parser",
|
|
1704
|
+
version: "1.0.0",
|
|
1705
|
+
category: "parser",
|
|
1706
|
+
install(kernel) {
|
|
1707
|
+
kernel.on("parse:start", async (context) => {
|
|
1708
|
+
const { files } = context.package;
|
|
1709
|
+
const mainDts = findMainDtsFile(files, context.package.types);
|
|
1710
|
+
if (!mainDts) {
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1713
|
+
const dtsFiles = Array.from(files.entries()).filter(([path]) => path.endsWith(".d.ts")).sort(([a], [b]) => {
|
|
1714
|
+
if (a === mainDts) return -1;
|
|
1715
|
+
if (b === mainDts) return 1;
|
|
1716
|
+
if (a.includes("index.d.ts")) return -1;
|
|
1717
|
+
if (b.includes("index.d.ts")) return 1;
|
|
1718
|
+
return a.localeCompare(b);
|
|
1719
|
+
});
|
|
1720
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
1721
|
+
for (const [path, content] of dtsFiles) {
|
|
1722
|
+
try {
|
|
1723
|
+
const result = parseDts(content, path);
|
|
1724
|
+
for (const entry of result.exports) {
|
|
1725
|
+
if (!seenNames.has(entry.name)) {
|
|
1726
|
+
seenNames.add(entry.name);
|
|
1727
|
+
context.api.push(entry);
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
} catch (error) {
|
|
1731
|
+
context.errors.push(error instanceof Error ? error : new Error(String(error)));
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
context.api = sortExports(context.api);
|
|
1735
|
+
});
|
|
1736
|
+
}
|
|
1737
|
+
};
|
|
1738
|
+
|
|
1739
|
+
// src/parsers/typescript.ts
|
|
1740
|
+
var PATTERNS2 = {
|
|
1741
|
+
/** Export function */
|
|
1742
|
+
exportFunction: /export\s+(?:async\s+)?function\s+(\w+)\s*(<[^>]*>)?\s*\(([^)]*)\)(?:\s*:\s*([^{]+))?\s*\{/g,
|
|
1743
|
+
/** Export arrow function */
|
|
1744
|
+
exportArrow: /export\s+const\s+(\w+)\s*(?::\s*([^=]+))?\s*=\s*(?:async\s*)?\([^)]*\)\s*(?::\s*([^=]+))?\s*=>/g,
|
|
1745
|
+
/** Export class */
|
|
1746
|
+
exportClass: /export\s+(?:abstract\s+)?class\s+(\w+)(?:\s*<([^>]*)>)?(?:\s+extends\s+([^\s{]+))?(?:\s+implements\s+([^{]+))?\s*\{/g,
|
|
1747
|
+
/** Export interface */
|
|
1748
|
+
exportInterface: /export\s+interface\s+(\w+)(?:\s*<([^>]*)>)?(?:\s+extends\s+([^{]+))?\s*\{/g,
|
|
1749
|
+
/** Export type */
|
|
1750
|
+
exportType: /export\s+type\s+(\w+)(?:\s*<([^>]*)>)?\s*=\s*([^;]+)/g,
|
|
1751
|
+
/** Export const/let */
|
|
1752
|
+
exportConst: /export\s+(?:const|let)\s+(\w+)(?:\s*:\s*([^=]+))?\s*=/g,
|
|
1753
|
+
/** Export enum */
|
|
1754
|
+
exportEnum: /export\s+(?:const\s+)?enum\s+(\w+)\s*\{/g};
|
|
1755
|
+
function parseSourceParams(paramStr) {
|
|
1756
|
+
if (!paramStr.trim()) return [];
|
|
1757
|
+
const params = [];
|
|
1758
|
+
const parts = splitParams(paramStr);
|
|
1759
|
+
for (const part of parts) {
|
|
1760
|
+
const trimmed = part.trim();
|
|
1761
|
+
if (!trimmed) continue;
|
|
1762
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
1763
|
+
const colonIndex = findBalancedColon(trimmed);
|
|
1764
|
+
if (colonIndex > 0) {
|
|
1765
|
+
params.push({
|
|
1766
|
+
name: "options",
|
|
1767
|
+
type: trimmed.slice(colonIndex + 1).trim(),
|
|
1768
|
+
optional: trimmed.includes("?")
|
|
1769
|
+
});
|
|
1770
|
+
} else {
|
|
1771
|
+
params.push({
|
|
1772
|
+
name: "options",
|
|
1773
|
+
type: "object"
|
|
1774
|
+
});
|
|
1775
|
+
}
|
|
1776
|
+
continue;
|
|
1777
|
+
}
|
|
1778
|
+
const match = trimmed.match(/^(\w+)(\?)?\s*(?::\s*(.+?))?(?:\s*=\s*(.+))?$/);
|
|
1779
|
+
if (match && match[1]) {
|
|
1780
|
+
const [, name, optional, type, defaultValue] = match;
|
|
1781
|
+
params.push({
|
|
1782
|
+
name,
|
|
1783
|
+
type: type?.trim() || inferTypeFromDefault(defaultValue),
|
|
1784
|
+
optional: !!optional || !!defaultValue,
|
|
1785
|
+
defaultValue: defaultValue?.trim()
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
return params;
|
|
1790
|
+
}
|
|
1791
|
+
function splitParams(str) {
|
|
1792
|
+
const parts = [];
|
|
1793
|
+
let current = "";
|
|
1794
|
+
let depth = 0;
|
|
1795
|
+
for (const char of str) {
|
|
1796
|
+
if (char === "<" || char === "{" || char === "[" || char === "(") {
|
|
1797
|
+
depth++;
|
|
1798
|
+
current += char;
|
|
1799
|
+
} else if (char === ">" || char === "}" || char === "]" || char === ")") {
|
|
1800
|
+
depth--;
|
|
1801
|
+
current += char;
|
|
1802
|
+
} else if (char === "," && depth === 0) {
|
|
1803
|
+
parts.push(current);
|
|
1804
|
+
current = "";
|
|
1805
|
+
} else {
|
|
1806
|
+
current += char;
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
if (current.trim()) parts.push(current);
|
|
1810
|
+
return parts;
|
|
1811
|
+
}
|
|
1812
|
+
function findBalancedColon(str) {
|
|
1813
|
+
let depth = 0;
|
|
1814
|
+
for (let i = 0; i < str.length; i++) {
|
|
1815
|
+
const char = str[i];
|
|
1816
|
+
if (char === "{" || char === "[" || char === "<" || char === "(") {
|
|
1817
|
+
depth++;
|
|
1818
|
+
} else if (char === "}" || char === "]" || char === ">" || char === ")") {
|
|
1819
|
+
depth--;
|
|
1820
|
+
} else if (char === ":" && depth === 0) {
|
|
1821
|
+
return i;
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
return -1;
|
|
1825
|
+
}
|
|
1826
|
+
function inferTypeFromDefault(defaultValue) {
|
|
1827
|
+
if (!defaultValue) return "unknown";
|
|
1828
|
+
const trimmed = defaultValue.trim();
|
|
1829
|
+
if (trimmed === "true" || trimmed === "false") return "boolean";
|
|
1830
|
+
if (trimmed.startsWith("'") || trimmed.startsWith('"') || trimmed.startsWith("`")) {
|
|
1831
|
+
return "string";
|
|
1832
|
+
}
|
|
1833
|
+
if (/^-?\d+(\.\d+)?$/.test(trimmed)) return "number";
|
|
1834
|
+
if (trimmed === "null") return "null";
|
|
1835
|
+
if (trimmed === "undefined") return "undefined";
|
|
1836
|
+
if (trimmed.startsWith("[")) return "unknown[]";
|
|
1837
|
+
if (trimmed.startsWith("{")) return "object";
|
|
1838
|
+
if (trimmed.startsWith("()") || trimmed.includes("=>")) return "Function";
|
|
1839
|
+
return "unknown";
|
|
1840
|
+
}
|
|
1841
|
+
function parseTypeScript(content, filePath) {
|
|
1842
|
+
const exports$1 = [];
|
|
1843
|
+
let hasTypes = false;
|
|
1844
|
+
hasTypes = /:\s*\w+/.test(content) || content.includes("interface ") || content.includes("type ");
|
|
1845
|
+
const comments = extractJSDocComments(content);
|
|
1846
|
+
let match;
|
|
1847
|
+
PATTERNS2.exportFunction.lastIndex = 0;
|
|
1848
|
+
while ((match = PATTERNS2.exportFunction.exec(content)) !== null) {
|
|
1849
|
+
const [, name, generics, params, returnType] = match;
|
|
1850
|
+
if (!name) continue;
|
|
1851
|
+
const jsdoc = findPrecedingJSDoc(content, match.index, comments);
|
|
1852
|
+
const paramStr = params || "";
|
|
1853
|
+
exports$1.push({
|
|
1854
|
+
kind: "function",
|
|
1855
|
+
name,
|
|
1856
|
+
signature: `function ${name}${generics || ""}(${paramStr})${returnType ? `: ${returnType.trim()}` : ""}`,
|
|
1857
|
+
description: jsdoc?.description,
|
|
1858
|
+
params: mergeParams(parseSourceParams(paramStr), jsdoc?.params),
|
|
1859
|
+
returns: returnType ? { type: returnType.trim(), description: jsdoc?.returns?.description } : void 0,
|
|
1860
|
+
examples: jsdoc?.examples,
|
|
1861
|
+
deprecated: jsdoc?.deprecated ? jsdoc.deprecated : void 0,
|
|
1862
|
+
sourceFile: filePath
|
|
1863
|
+
});
|
|
1864
|
+
}
|
|
1865
|
+
PATTERNS2.exportArrow.lastIndex = 0;
|
|
1866
|
+
while ((match = PATTERNS2.exportArrow.exec(content)) !== null) {
|
|
1867
|
+
const [fullMatch, name, typeAnnotation, returnType] = match;
|
|
1868
|
+
if (!name || !fullMatch) continue;
|
|
1869
|
+
const jsdoc = findPrecedingJSDoc(content, match.index, comments);
|
|
1870
|
+
const paramsStart = fullMatch.indexOf("(");
|
|
1871
|
+
const paramsEnd = fullMatch.indexOf(")", paramsStart);
|
|
1872
|
+
const params = fullMatch.slice(paramsStart + 1, paramsEnd);
|
|
1873
|
+
exports$1.push({
|
|
1874
|
+
kind: "function",
|
|
1875
|
+
name,
|
|
1876
|
+
signature: typeAnnotation ? `const ${name}: ${typeAnnotation.trim()}` : `const ${name} = (${params})${returnType ? ` => ${returnType.trim()}` : ""}`,
|
|
1877
|
+
description: jsdoc?.description,
|
|
1878
|
+
params: mergeParams(parseSourceParams(params), jsdoc?.params),
|
|
1879
|
+
returns: returnType ? { type: returnType.trim(), description: jsdoc?.returns?.description } : void 0,
|
|
1880
|
+
examples: jsdoc?.examples,
|
|
1881
|
+
deprecated: jsdoc?.deprecated ? jsdoc.deprecated : void 0,
|
|
1882
|
+
sourceFile: filePath
|
|
1883
|
+
});
|
|
1884
|
+
}
|
|
1885
|
+
PATTERNS2.exportClass.lastIndex = 0;
|
|
1886
|
+
while ((match = PATTERNS2.exportClass.exec(content)) !== null) {
|
|
1887
|
+
const [, name, generics, extendsClause, implementsClause] = match;
|
|
1888
|
+
if (!name) continue;
|
|
1889
|
+
const jsdoc = findPrecedingJSDoc(content, match.index, comments);
|
|
1890
|
+
exports$1.push({
|
|
1891
|
+
kind: "class",
|
|
1892
|
+
name,
|
|
1893
|
+
signature: `class ${name}${generics ? `<${generics}>` : ""}`,
|
|
1894
|
+
description: jsdoc?.description,
|
|
1895
|
+
extends: extendsClause ? [extendsClause.trim()] : void 0,
|
|
1896
|
+
implements: implementsClause ? implementsClause.split(",").map((s) => s.trim()) : void 0,
|
|
1897
|
+
deprecated: jsdoc?.deprecated ? jsdoc.deprecated : void 0,
|
|
1898
|
+
sourceFile: filePath
|
|
1899
|
+
});
|
|
1900
|
+
}
|
|
1901
|
+
PATTERNS2.exportInterface.lastIndex = 0;
|
|
1902
|
+
while ((match = PATTERNS2.exportInterface.exec(content)) !== null) {
|
|
1903
|
+
const [, name, generics, extendsClause] = match;
|
|
1904
|
+
if (!name) continue;
|
|
1905
|
+
const jsdoc = findPrecedingJSDoc(content, match.index, comments);
|
|
1906
|
+
exports$1.push({
|
|
1907
|
+
kind: "interface",
|
|
1908
|
+
name,
|
|
1909
|
+
signature: `interface ${name}${generics ? `<${generics}>` : ""}`,
|
|
1910
|
+
description: jsdoc?.description,
|
|
1911
|
+
extends: extendsClause ? extendsClause.split(",").map((s) => s.trim()) : void 0,
|
|
1912
|
+
deprecated: jsdoc?.deprecated ? jsdoc.deprecated : void 0,
|
|
1913
|
+
sourceFile: filePath
|
|
1914
|
+
});
|
|
1915
|
+
}
|
|
1916
|
+
PATTERNS2.exportType.lastIndex = 0;
|
|
1917
|
+
while ((match = PATTERNS2.exportType.exec(content)) !== null) {
|
|
1918
|
+
const [, name, generics, definition] = match;
|
|
1919
|
+
if (!name || !definition) continue;
|
|
1920
|
+
const jsdoc = findPrecedingJSDoc(content, match.index, comments);
|
|
1921
|
+
exports$1.push({
|
|
1922
|
+
kind: "type",
|
|
1923
|
+
name,
|
|
1924
|
+
signature: `type ${name}${generics ? `<${generics}>` : ""} = ${definition.trim()}`,
|
|
1925
|
+
description: jsdoc?.description,
|
|
1926
|
+
deprecated: jsdoc?.deprecated ? jsdoc.deprecated : void 0,
|
|
1927
|
+
sourceFile: filePath
|
|
1928
|
+
});
|
|
1929
|
+
}
|
|
1930
|
+
PATTERNS2.exportConst.lastIndex = 0;
|
|
1931
|
+
while ((match = PATTERNS2.exportConst.exec(content)) !== null) {
|
|
1932
|
+
const [, name, type] = match;
|
|
1933
|
+
if (!name) continue;
|
|
1934
|
+
if (content.slice(match.index, match.index + 200).includes("=>")) continue;
|
|
1935
|
+
const jsdoc = findPrecedingJSDoc(content, match.index, comments);
|
|
1936
|
+
exports$1.push({
|
|
1937
|
+
kind: "constant",
|
|
1938
|
+
name,
|
|
1939
|
+
signature: `const ${name}${type ? `: ${type.trim()}` : ""}`,
|
|
1940
|
+
description: jsdoc?.description,
|
|
1941
|
+
deprecated: jsdoc?.deprecated ? jsdoc.deprecated : void 0,
|
|
1942
|
+
sourceFile: filePath
|
|
1943
|
+
});
|
|
1944
|
+
}
|
|
1945
|
+
PATTERNS2.exportEnum.lastIndex = 0;
|
|
1946
|
+
while ((match = PATTERNS2.exportEnum.exec(content)) !== null) {
|
|
1947
|
+
const [, name] = match;
|
|
1948
|
+
if (!name) continue;
|
|
1949
|
+
const jsdoc = findPrecedingJSDoc(content, match.index, comments);
|
|
1950
|
+
exports$1.push({
|
|
1951
|
+
kind: "enum",
|
|
1952
|
+
name,
|
|
1953
|
+
signature: `enum ${name}`,
|
|
1954
|
+
description: jsdoc?.description,
|
|
1955
|
+
deprecated: jsdoc?.deprecated ? jsdoc.deprecated : void 0,
|
|
1956
|
+
sourceFile: filePath
|
|
1957
|
+
});
|
|
1958
|
+
}
|
|
1959
|
+
return { exports: exports$1, hasTypes };
|
|
1960
|
+
}
|
|
1961
|
+
function mergeParams(sourceParams, jsdocParams) {
|
|
1962
|
+
if (!jsdocParams || jsdocParams.length === 0) return sourceParams;
|
|
1963
|
+
return sourceParams.map((param) => {
|
|
1964
|
+
const jsdocParam = jsdocParams.find((p) => p.name === param.name);
|
|
1965
|
+
if (jsdocParam) {
|
|
1966
|
+
return {
|
|
1967
|
+
...param,
|
|
1968
|
+
description: jsdocParam.description || param.description,
|
|
1969
|
+
type: param.type !== "unknown" ? param.type : jsdocParam.type
|
|
1970
|
+
};
|
|
1971
|
+
}
|
|
1972
|
+
return param;
|
|
1973
|
+
});
|
|
1974
|
+
}
|
|
1975
|
+
function findTypeScriptFiles(files, mainField) {
|
|
1976
|
+
const tsFiles = [];
|
|
1977
|
+
const priorities = [];
|
|
1978
|
+
if (mainField) {
|
|
1979
|
+
const base = mainField.replace(/^\.\//, "").replace(/\.[jt]sx?$/, "");
|
|
1980
|
+
priorities.push(
|
|
1981
|
+
`${base}.ts`,
|
|
1982
|
+
`${base}.tsx`,
|
|
1983
|
+
`src/${base}.ts`,
|
|
1984
|
+
`src/${base}.tsx`
|
|
1985
|
+
);
|
|
1986
|
+
}
|
|
1987
|
+
priorities.push(
|
|
1988
|
+
"src/index.ts",
|
|
1989
|
+
"src/index.tsx",
|
|
1990
|
+
"index.ts",
|
|
1991
|
+
"index.tsx",
|
|
1992
|
+
"lib/index.ts",
|
|
1993
|
+
"src/main.ts"
|
|
1994
|
+
);
|
|
1995
|
+
for (const path of priorities) {
|
|
1996
|
+
if (files.has(path) && !tsFiles.includes(path)) {
|
|
1997
|
+
tsFiles.push(path);
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
for (const path of files.keys()) {
|
|
2001
|
+
if ((path.endsWith(".ts") || path.endsWith(".tsx")) && !path.endsWith(".d.ts")) {
|
|
2002
|
+
if (!tsFiles.includes(path)) {
|
|
2003
|
+
tsFiles.push(path);
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
return tsFiles;
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
// src/plugins/core/ts-source-parser.ts
|
|
2011
|
+
var tsSourceParserPlugin = {
|
|
2012
|
+
name: "ts-source-parser",
|
|
2013
|
+
version: "1.0.0",
|
|
2014
|
+
category: "parser",
|
|
2015
|
+
install(kernel) {
|
|
2016
|
+
kernel.on("parse:start", async (context) => {
|
|
2017
|
+
if (context.api.length > 0) {
|
|
2018
|
+
return;
|
|
2019
|
+
}
|
|
2020
|
+
const { files } = context.package;
|
|
2021
|
+
const tsFiles = findTypeScriptFiles(files, context.package.main);
|
|
2022
|
+
if (tsFiles.length === 0) {
|
|
2023
|
+
return;
|
|
2024
|
+
}
|
|
2025
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
2026
|
+
for (const path of tsFiles) {
|
|
2027
|
+
const content = files.get(path);
|
|
2028
|
+
if (!content) continue;
|
|
2029
|
+
try {
|
|
2030
|
+
const result = parseTypeScript(content, path);
|
|
2031
|
+
for (const entry of result.exports) {
|
|
2032
|
+
if (!seenNames.has(entry.name)) {
|
|
2033
|
+
seenNames.add(entry.name);
|
|
2034
|
+
context.api.push(entry);
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
} catch (error) {
|
|
2038
|
+
context.errors.push(error instanceof Error ? error : new Error(String(error)));
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
context.api = sortExports(context.api);
|
|
2042
|
+
});
|
|
2043
|
+
}
|
|
2044
|
+
};
|
|
2045
|
+
|
|
2046
|
+
// src/parsers/readme.ts
|
|
2047
|
+
var SECTION_PATTERNS = {
|
|
2048
|
+
installation: /^#+\s*(installation|install|setup|getting started)/i,
|
|
2049
|
+
quickStart: /^#+\s*(quick\s*start|usage|getting\s*started|basic\s*usage)/i,
|
|
2050
|
+
api: /^#+\s*(api|api\s*reference|reference|methods|functions)/i,
|
|
2051
|
+
examples: /^#+\s*(examples?|code\s*examples?)/i};
|
|
2052
|
+
var BADGE_PATTERN = /\[!\[([^\]]*)\]\(([^)]+)\)\]\([^)]+\)|\!\[([^\]]*)\]\(([^)]+)\)/g;
|
|
2053
|
+
var CODE_BLOCK_PATTERN = /```(\w+)?\s*\n([\s\S]*?)```/g;
|
|
2054
|
+
function parseReadme(content) {
|
|
2055
|
+
const sections = extractSections(content);
|
|
2056
|
+
const badges = extractBadges(content);
|
|
2057
|
+
const { title, description } = extractTitleAndDescription(content, sections);
|
|
2058
|
+
const installation = findSection(sections, SECTION_PATTERNS.installation);
|
|
2059
|
+
const quickStart = findSection(sections, SECTION_PATTERNS.quickStart);
|
|
2060
|
+
const api = findSection(sections, SECTION_PATTERNS.api);
|
|
2061
|
+
const examples = findExampleSections(sections);
|
|
2062
|
+
return {
|
|
2063
|
+
title,
|
|
2064
|
+
description,
|
|
2065
|
+
badges,
|
|
2066
|
+
installation: installation?.content,
|
|
2067
|
+
quickStart: quickStart?.content || findQuickStartFromCode(content),
|
|
2068
|
+
examples,
|
|
2069
|
+
api: api?.content,
|
|
2070
|
+
sections
|
|
2071
|
+
};
|
|
2072
|
+
}
|
|
2073
|
+
function extractSections(content) {
|
|
2074
|
+
const sections = [];
|
|
2075
|
+
const lines = content.split("\n");
|
|
2076
|
+
let currentSection = null;
|
|
2077
|
+
let currentContent = [];
|
|
2078
|
+
let charIndex = 0;
|
|
2079
|
+
function finishSection() {
|
|
2080
|
+
if (currentSection) {
|
|
2081
|
+
currentSection.content = currentContent.join("\n").trim();
|
|
2082
|
+
currentSection.endIndex = charIndex;
|
|
2083
|
+
sections.push(currentSection);
|
|
2084
|
+
currentContent = [];
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
for (const line of lines) {
|
|
2088
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
2089
|
+
if (headingMatch && headingMatch[1] && headingMatch[2]) {
|
|
2090
|
+
finishSection();
|
|
2091
|
+
const level = headingMatch[1].length;
|
|
2092
|
+
const title = headingMatch[2].trim();
|
|
2093
|
+
currentSection = {
|
|
2094
|
+
title,
|
|
2095
|
+
content: "",
|
|
2096
|
+
level,
|
|
2097
|
+
startIndex: charIndex,
|
|
2098
|
+
endIndex: 0
|
|
2099
|
+
};
|
|
2100
|
+
currentContent = [];
|
|
2101
|
+
} else if (currentSection) {
|
|
2102
|
+
currentContent.push(line);
|
|
2103
|
+
}
|
|
2104
|
+
charIndex += line.length + 1;
|
|
2105
|
+
}
|
|
2106
|
+
finishSection();
|
|
2107
|
+
return sections;
|
|
2108
|
+
}
|
|
2109
|
+
function findSection(sections, pattern) {
|
|
2110
|
+
return sections.find((s) => pattern.test(`# ${s.title}`));
|
|
2111
|
+
}
|
|
2112
|
+
function findExampleSections(sections) {
|
|
2113
|
+
const examples = [];
|
|
2114
|
+
for (const section of sections) {
|
|
2115
|
+
if (SECTION_PATTERNS.examples.test(`# ${section.title}`)) {
|
|
2116
|
+
const codeBlocks = extractCodeBlocks(section.content);
|
|
2117
|
+
examples.push(...codeBlocks);
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
return examples;
|
|
2121
|
+
}
|
|
2122
|
+
function extractCodeBlocks(content) {
|
|
2123
|
+
const blocks = [];
|
|
2124
|
+
const pattern = new RegExp(CODE_BLOCK_PATTERN.source, "g");
|
|
2125
|
+
let match;
|
|
2126
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
2127
|
+
const [, language, code] = match;
|
|
2128
|
+
if (code && code.trim()) {
|
|
2129
|
+
blocks.push(language ? `\`\`\`${language}
|
|
2130
|
+
${code.trim()}
|
|
2131
|
+
\`\`\`` : code.trim());
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
return blocks;
|
|
2135
|
+
}
|
|
2136
|
+
function extractBadges(content) {
|
|
2137
|
+
const badges = [];
|
|
2138
|
+
const pattern = new RegExp(BADGE_PATTERN.source, "g");
|
|
2139
|
+
let match;
|
|
2140
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
2141
|
+
const altText = match[1] || match[3] || "";
|
|
2142
|
+
if (altText) {
|
|
2143
|
+
badges.push(altText);
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
return badges;
|
|
2147
|
+
}
|
|
2148
|
+
function extractTitleAndDescription(content, sections) {
|
|
2149
|
+
let title;
|
|
2150
|
+
let description;
|
|
2151
|
+
const firstHeading = sections[0];
|
|
2152
|
+
if (firstHeading?.level === 1) {
|
|
2153
|
+
title = firstHeading.title;
|
|
2154
|
+
} else {
|
|
2155
|
+
const lines = content.split("\n");
|
|
2156
|
+
for (const line of lines) {
|
|
2157
|
+
const trimmed = line.trim();
|
|
2158
|
+
if (!trimmed) continue;
|
|
2159
|
+
if (trimmed.startsWith("!") || trimmed.startsWith("[!")) continue;
|
|
2160
|
+
if (trimmed.startsWith("#")) {
|
|
2161
|
+
title = trimmed.replace(/^#+\s*/, "");
|
|
2162
|
+
break;
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
const afterTitle = content.split("\n").slice(1);
|
|
2167
|
+
let foundContent = false;
|
|
2168
|
+
for (const line of afterTitle) {
|
|
2169
|
+
const trimmed = line.trim();
|
|
2170
|
+
if (trimmed.startsWith("!") || trimmed.startsWith("[!")) continue;
|
|
2171
|
+
if (trimmed.startsWith("#")) break;
|
|
2172
|
+
if (!trimmed && !foundContent) continue;
|
|
2173
|
+
if (!trimmed && foundContent) break;
|
|
2174
|
+
if (trimmed) {
|
|
2175
|
+
foundContent = true;
|
|
2176
|
+
if (!description) {
|
|
2177
|
+
description = trimmed;
|
|
2178
|
+
} else {
|
|
2179
|
+
description += " " + trimmed;
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
if (description) {
|
|
2184
|
+
description = description.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/\*([^*]+)\*/g, "$1").trim();
|
|
2185
|
+
}
|
|
2186
|
+
return { title, description };
|
|
2187
|
+
}
|
|
2188
|
+
function findQuickStartFromCode(content) {
|
|
2189
|
+
const installMatch = content.match(/installation|install|setup/i);
|
|
2190
|
+
const startIndex = installMatch?.index ?? 0;
|
|
2191
|
+
const searchArea = content.slice(startIndex, startIndex + 2e3);
|
|
2192
|
+
const codeBlocks = extractCodeBlocks(searchArea);
|
|
2193
|
+
for (const block of codeBlocks) {
|
|
2194
|
+
if (block.startsWith("```javascript") || block.startsWith("```typescript") || block.startsWith("```js") || block.startsWith("```ts") || block.startsWith("```jsx") || block.startsWith("```tsx")) {
|
|
2195
|
+
return block;
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
return codeBlocks[0];
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
// src/plugins/core/readme-parser.ts
|
|
2202
|
+
var readmeParserPlugin = {
|
|
2203
|
+
name: "readme-parser",
|
|
2204
|
+
version: "1.0.0",
|
|
2205
|
+
category: "parser",
|
|
2206
|
+
install(kernel) {
|
|
2207
|
+
kernel.on("parse:start", async (context) => {
|
|
2208
|
+
const { files } = context.package;
|
|
2209
|
+
let readmeContent;
|
|
2210
|
+
const readmePatterns = [
|
|
2211
|
+
"README.md",
|
|
2212
|
+
"readme.md",
|
|
2213
|
+
"Readme.md",
|
|
2214
|
+
"README.MD",
|
|
2215
|
+
"README",
|
|
2216
|
+
"readme"
|
|
2217
|
+
];
|
|
2218
|
+
for (const pattern of readmePatterns) {
|
|
2219
|
+
if (files.has(pattern)) {
|
|
2220
|
+
readmeContent = files.get(pattern);
|
|
2221
|
+
break;
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
if (!readmeContent) {
|
|
2225
|
+
for (const [path, content] of files) {
|
|
2226
|
+
if (path.toLowerCase().includes("readme")) {
|
|
2227
|
+
readmeContent = content;
|
|
2228
|
+
break;
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
if (!readmeContent) {
|
|
2233
|
+
return;
|
|
2234
|
+
}
|
|
2235
|
+
try {
|
|
2236
|
+
context.readme = parseReadme(readmeContent);
|
|
2237
|
+
if (!context.package.description && context.readme.description) {
|
|
2238
|
+
context.package.description = context.readme.description;
|
|
2239
|
+
}
|
|
2240
|
+
} catch (error) {
|
|
2241
|
+
context.errors.push(error instanceof Error ? error : new Error(String(error)));
|
|
2242
|
+
}
|
|
2243
|
+
});
|
|
2244
|
+
}
|
|
2245
|
+
};
|
|
2246
|
+
|
|
2247
|
+
// src/core/tokens.ts
|
|
2248
|
+
var CHARS_PER_TOKEN = {
|
|
2249
|
+
/** English prose: ~4 chars per token */
|
|
2250
|
+
prose: 4,
|
|
2251
|
+
/** Code blocks: ~3 chars per token (more special tokens) */
|
|
2252
|
+
code: 3};
|
|
2253
|
+
var PRIORITY_ORDER = {
|
|
2254
|
+
functions: 100,
|
|
2255
|
+
examples: 90,
|
|
2256
|
+
classes: 80,
|
|
2257
|
+
interfaces: 70,
|
|
2258
|
+
types: 60,
|
|
2259
|
+
readme: 50
|
|
2260
|
+
};
|
|
2261
|
+
function countTokens(text) {
|
|
2262
|
+
if (!text) return 0;
|
|
2263
|
+
let tokens = 0;
|
|
2264
|
+
const codeBlockRegex = /```[\s\S]*?```/g;
|
|
2265
|
+
const parts = [];
|
|
2266
|
+
let lastIndex = 0;
|
|
2267
|
+
let match;
|
|
2268
|
+
while ((match = codeBlockRegex.exec(text)) !== null) {
|
|
2269
|
+
if (match.index > lastIndex) {
|
|
2270
|
+
parts.push({
|
|
2271
|
+
text: text.slice(lastIndex, match.index),
|
|
2272
|
+
isCode: false
|
|
2273
|
+
});
|
|
2274
|
+
}
|
|
2275
|
+
parts.push({
|
|
2276
|
+
text: match[0],
|
|
2277
|
+
isCode: true
|
|
2278
|
+
});
|
|
2279
|
+
lastIndex = match.index + match[0].length;
|
|
2280
|
+
}
|
|
2281
|
+
if (lastIndex < text.length) {
|
|
2282
|
+
parts.push({
|
|
2283
|
+
text: text.slice(lastIndex),
|
|
2284
|
+
isCode: false
|
|
2285
|
+
});
|
|
2286
|
+
}
|
|
2287
|
+
for (const part of parts) {
|
|
2288
|
+
const charsPerToken = part.isCode ? CHARS_PER_TOKEN.code : CHARS_PER_TOKEN.prose;
|
|
2289
|
+
tokens += Math.ceil(part.text.length / charsPerToken);
|
|
2290
|
+
}
|
|
2291
|
+
return tokens;
|
|
2292
|
+
}
|
|
2293
|
+
function parseSections(text) {
|
|
2294
|
+
const sections = [];
|
|
2295
|
+
const lines = text.split("\n");
|
|
2296
|
+
let currentSection = null;
|
|
2297
|
+
let currentContent = [];
|
|
2298
|
+
function finishSection() {
|
|
2299
|
+
if (currentSection) {
|
|
2300
|
+
currentSection.content = currentContent.join("\n").trim();
|
|
2301
|
+
currentSection.tokens = countTokens(currentSection.content);
|
|
2302
|
+
sections.push(currentSection);
|
|
2303
|
+
currentContent = [];
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
for (const line of lines) {
|
|
2307
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
2308
|
+
if (headingMatch && headingMatch[2]) {
|
|
2309
|
+
finishSection();
|
|
2310
|
+
const title = headingMatch[2].trim();
|
|
2311
|
+
const priority = inferPriority(title);
|
|
2312
|
+
currentSection = {
|
|
2313
|
+
id: title.toLowerCase().replace(/[^a-z0-9]+/g, "-"),
|
|
2314
|
+
title,
|
|
2315
|
+
content: "",
|
|
2316
|
+
priority,
|
|
2317
|
+
tokens: 0
|
|
2318
|
+
};
|
|
2319
|
+
currentContent = [line];
|
|
2320
|
+
} else if (currentSection) {
|
|
2321
|
+
currentContent.push(line);
|
|
2322
|
+
} else {
|
|
2323
|
+
if (line.trim()) {
|
|
2324
|
+
if (!currentSection) {
|
|
2325
|
+
currentSection = {
|
|
2326
|
+
id: "intro",
|
|
2327
|
+
title: "Introduction",
|
|
2328
|
+
content: "",
|
|
2329
|
+
priority: "readme",
|
|
2330
|
+
tokens: 0
|
|
2331
|
+
};
|
|
2332
|
+
}
|
|
2333
|
+
currentContent.push(line);
|
|
2334
|
+
}
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
finishSection();
|
|
2338
|
+
return sections;
|
|
2339
|
+
}
|
|
2340
|
+
function inferPriority(title) {
|
|
2341
|
+
const lower = title.toLowerCase();
|
|
2342
|
+
if (lower.includes("function") || lower.includes("method") || lower.includes("api")) {
|
|
2343
|
+
return "functions";
|
|
2344
|
+
}
|
|
2345
|
+
if (lower.includes("example") || lower.includes("usage") || lower.includes("quick start")) {
|
|
2346
|
+
return "examples";
|
|
2347
|
+
}
|
|
2348
|
+
if (lower.includes("class")) {
|
|
2349
|
+
return "classes";
|
|
2350
|
+
}
|
|
2351
|
+
if (lower.includes("interface")) {
|
|
2352
|
+
return "interfaces";
|
|
2353
|
+
}
|
|
2354
|
+
if (lower.includes("type")) {
|
|
2355
|
+
return "types";
|
|
2356
|
+
}
|
|
2357
|
+
return "readme";
|
|
2358
|
+
}
|
|
2359
|
+
function prioritizeSections(sections, priorities = ["functions", "examples"]) {
|
|
2360
|
+
const customOrder = { ...PRIORITY_ORDER };
|
|
2361
|
+
priorities.forEach((p, i) => {
|
|
2362
|
+
customOrder[p] = 1e3 - i;
|
|
2363
|
+
});
|
|
2364
|
+
return [...sections].sort((a, b) => {
|
|
2365
|
+
return (customOrder[b.priority] ?? 0) - (customOrder[a.priority] ?? 0);
|
|
2366
|
+
});
|
|
2367
|
+
}
|
|
2368
|
+
function truncateToTokenLimit(text, limit, priorities = ["functions", "examples"]) {
|
|
2369
|
+
const currentTokens = countTokens(text);
|
|
2370
|
+
if (currentTokens <= limit) {
|
|
2371
|
+
return {
|
|
2372
|
+
text,
|
|
2373
|
+
truncated: false,
|
|
2374
|
+
tokenCount: currentTokens,
|
|
2375
|
+
includedSections: [],
|
|
2376
|
+
removedSections: []
|
|
2377
|
+
};
|
|
2378
|
+
}
|
|
2379
|
+
const sections = parseSections(text);
|
|
2380
|
+
const prioritized = prioritizeSections(sections, priorities);
|
|
2381
|
+
const included = [];
|
|
2382
|
+
const removed = [];
|
|
2383
|
+
let usedTokens = 0;
|
|
2384
|
+
for (const section of prioritized) {
|
|
2385
|
+
if (usedTokens + section.tokens <= limit) {
|
|
2386
|
+
included.push(section);
|
|
2387
|
+
usedTokens += section.tokens;
|
|
2388
|
+
} else {
|
|
2389
|
+
const remaining = limit - usedTokens;
|
|
2390
|
+
if (remaining > 50 && section.tokens > 0) {
|
|
2391
|
+
const truncated = truncateSectionContent(section, remaining);
|
|
2392
|
+
if (truncated) {
|
|
2393
|
+
included.push(truncated);
|
|
2394
|
+
usedTokens += truncated.tokens;
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
removed.push(section);
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
2400
|
+
const sectionOrder = sections.map((s) => s.id);
|
|
2401
|
+
included.sort((a, b) => sectionOrder.indexOf(a.id) - sectionOrder.indexOf(b.id));
|
|
2402
|
+
const output = included.map((s) => s.content).join("\n\n");
|
|
2403
|
+
return {
|
|
2404
|
+
text: output.trim(),
|
|
2405
|
+
truncated: true,
|
|
2406
|
+
tokenCount: countTokens(output),
|
|
2407
|
+
includedSections: included.map((s) => s.title),
|
|
2408
|
+
removedSections: removed.map((s) => s.title)
|
|
2409
|
+
};
|
|
2410
|
+
}
|
|
2411
|
+
function truncateSectionContent(section, maxTokens) {
|
|
2412
|
+
const lines = section.content.split("\n");
|
|
2413
|
+
const truncatedLines = [];
|
|
2414
|
+
let tokens = 0;
|
|
2415
|
+
for (const line of lines) {
|
|
2416
|
+
const lineTokens = countTokens(line);
|
|
2417
|
+
if (tokens + lineTokens <= maxTokens) {
|
|
2418
|
+
truncatedLines.push(line);
|
|
2419
|
+
tokens += lineTokens;
|
|
2420
|
+
} else {
|
|
2421
|
+
break;
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
if (truncatedLines.length === 0) {
|
|
2425
|
+
return null;
|
|
2426
|
+
}
|
|
2427
|
+
truncatedLines.push("\n...(truncated)");
|
|
2428
|
+
return {
|
|
2429
|
+
...section,
|
|
2430
|
+
content: truncatedLines.join("\n"),
|
|
2431
|
+
tokens: countTokens(truncatedLines.join("\n"))
|
|
2432
|
+
};
|
|
2433
|
+
}
|
|
2434
|
+
function formatTokenCount(tokens) {
|
|
2435
|
+
if (tokens < 1e3) {
|
|
2436
|
+
return `${tokens} tokens`;
|
|
2437
|
+
}
|
|
2438
|
+
return `${(tokens / 1e3).toFixed(1)}k tokens`;
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
// src/outputs/llms.ts
|
|
2442
|
+
var DEFAULT_LLMS_TOKEN_LIMIT = Infinity;
|
|
2443
|
+
function generateLlmsTxt(context, options = {}) {
|
|
2444
|
+
const {
|
|
2445
|
+
tokenLimit = DEFAULT_LLMS_TOKEN_LIMIT,
|
|
2446
|
+
includeInstall = true,
|
|
2447
|
+
includeQuickStart = true,
|
|
2448
|
+
maxFunctions = Infinity,
|
|
2449
|
+
maxClasses = Infinity
|
|
2450
|
+
} = options;
|
|
2451
|
+
const { package: pkg, api, readme } = context;
|
|
2452
|
+
const sections = [];
|
|
2453
|
+
sections.push(`# ${pkg.name}`);
|
|
2454
|
+
if (pkg.description) {
|
|
2455
|
+
sections.push(`
|
|
2456
|
+
> ${pkg.description}`);
|
|
2457
|
+
}
|
|
2458
|
+
sections.push("");
|
|
2459
|
+
if (includeInstall) {
|
|
2460
|
+
sections.push("## Install\n");
|
|
2461
|
+
sections.push("```bash");
|
|
2462
|
+
sections.push(`npm install ${pkg.name}`);
|
|
2463
|
+
sections.push("```\n");
|
|
2464
|
+
}
|
|
2465
|
+
if (includeQuickStart && readme?.quickStart) {
|
|
2466
|
+
sections.push("## Quick Start\n");
|
|
2467
|
+
sections.push(readme.quickStart);
|
|
2468
|
+
sections.push("");
|
|
2469
|
+
}
|
|
2470
|
+
sections.push("## API\n");
|
|
2471
|
+
const functions = api.filter((e) => e.kind === "function");
|
|
2472
|
+
const classes = api.filter((e) => e.kind === "class");
|
|
2473
|
+
const interfaces = api.filter((e) => e.kind === "interface");
|
|
2474
|
+
const types = api.filter((e) => e.kind === "type");
|
|
2475
|
+
const constants = api.filter((e) => e.kind === "constant");
|
|
2476
|
+
if (functions.length > 0) {
|
|
2477
|
+
sections.push("### Functions\n");
|
|
2478
|
+
const limit = Math.min(functions.length, maxFunctions);
|
|
2479
|
+
for (let i = 0; i < limit; i++) {
|
|
2480
|
+
sections.push(formatFunctionBrief(functions[i]));
|
|
2481
|
+
}
|
|
2482
|
+
if (functions.length > maxFunctions && maxFunctions < Infinity) {
|
|
2483
|
+
sections.push(`
|
|
2484
|
+
...and ${functions.length - maxFunctions} more functions.`);
|
|
2485
|
+
}
|
|
2486
|
+
sections.push("");
|
|
2487
|
+
}
|
|
2488
|
+
if (classes.length > 0) {
|
|
2489
|
+
sections.push("### Classes\n");
|
|
2490
|
+
const limit = Math.min(classes.length, maxClasses);
|
|
2491
|
+
for (let i = 0; i < limit; i++) {
|
|
2492
|
+
sections.push(formatClassBrief(classes[i]));
|
|
2493
|
+
}
|
|
2494
|
+
if (classes.length > maxClasses && maxClasses < Infinity) {
|
|
2495
|
+
sections.push(`
|
|
2496
|
+
...and ${classes.length - maxClasses} more classes.`);
|
|
2497
|
+
}
|
|
2498
|
+
sections.push("");
|
|
2499
|
+
}
|
|
2500
|
+
if (interfaces.length > 0 || types.length > 0) {
|
|
2501
|
+
sections.push("### Types\n");
|
|
2502
|
+
const allTypes = [...interfaces, ...types];
|
|
2503
|
+
for (const t of allTypes) {
|
|
2504
|
+
const desc = t.description ? ` - ${truncate(t.description, 80)}` : "";
|
|
2505
|
+
sections.push(`- \`${t.name}\`${desc}`);
|
|
2506
|
+
}
|
|
2507
|
+
sections.push("");
|
|
2508
|
+
}
|
|
2509
|
+
if (constants.length > 0) {
|
|
2510
|
+
sections.push("### Constants\n");
|
|
2511
|
+
for (const c of constants) {
|
|
2512
|
+
const desc = c.description ? ` - ${truncate(c.description, 80)}` : "";
|
|
2513
|
+
sections.push(`- \`${c.name}\`${desc}`);
|
|
2514
|
+
}
|
|
2515
|
+
sections.push("");
|
|
2516
|
+
}
|
|
2517
|
+
let output = sections.join("\n");
|
|
2518
|
+
const currentTokens = countTokens(output);
|
|
2519
|
+
if (currentTokens > tokenLimit) {
|
|
2520
|
+
const result = truncateToTokenLimit(output, tokenLimit, ["functions", "examples"]);
|
|
2521
|
+
output = result.text;
|
|
2522
|
+
context.truncated = result.truncated;
|
|
2523
|
+
}
|
|
2524
|
+
context.tokenCount = countTokens(output);
|
|
2525
|
+
return output;
|
|
2526
|
+
}
|
|
2527
|
+
function formatFunctionBrief(fn) {
|
|
2528
|
+
const params = fn.params?.map((p) => `${p.name}${p.optional ? "?" : ""}`).join(", ") || "";
|
|
2529
|
+
const returnType = fn.returns?.type ? `: ${simplifyType(fn.returns.type)}` : "";
|
|
2530
|
+
const desc = fn.description ? ` - ${truncate(fn.description, 60)}` : "";
|
|
2531
|
+
return `- \`${fn.name}(${params})${returnType}\`${desc}`;
|
|
2532
|
+
}
|
|
2533
|
+
function formatClassBrief(cls) {
|
|
2534
|
+
const lines = [];
|
|
2535
|
+
const desc = cls.description ? ` - ${truncate(cls.description, 60)}` : "";
|
|
2536
|
+
lines.push(`- \`${cls.name}\`${desc}`);
|
|
2537
|
+
if (cls.methods && cls.methods.length > 0) {
|
|
2538
|
+
const keyMethods = cls.methods.slice(0, 3);
|
|
2539
|
+
for (const method of keyMethods) {
|
|
2540
|
+
lines.push(` - \`${method.name}()\``);
|
|
2541
|
+
}
|
|
2542
|
+
if (cls.methods.length > 3) {
|
|
2543
|
+
lines.push(` - ...${cls.methods.length - 3} more methods`);
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
return lines.join("\n");
|
|
2547
|
+
}
|
|
2548
|
+
function simplifyType(type) {
|
|
2549
|
+
if (type.length > 30) {
|
|
2550
|
+
const genericStart = type.indexOf("<");
|
|
2551
|
+
if (genericStart > 0) {
|
|
2552
|
+
return type.slice(0, genericStart) + "<...>";
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
return type;
|
|
2556
|
+
}
|
|
2557
|
+
function truncate(text, maxLength) {
|
|
2558
|
+
if (text.length <= maxLength) return text;
|
|
2559
|
+
return text.slice(0, maxLength - 3) + "...";
|
|
2560
|
+
}
|
|
2561
|
+
|
|
2562
|
+
// src/plugins/core/llms-output.ts
|
|
2563
|
+
var llmsOutputPlugin = {
|
|
2564
|
+
name: "llms-output",
|
|
2565
|
+
version: "1.0.0",
|
|
2566
|
+
category: "output",
|
|
2567
|
+
install(kernel) {
|
|
2568
|
+
kernel.on("output:start", async (context) => {
|
|
2569
|
+
if (!context.options.formats?.includes("llms")) {
|
|
2570
|
+
return;
|
|
2571
|
+
}
|
|
2572
|
+
try {
|
|
2573
|
+
const tokenLimit = context.options.llmsTokenLimit ?? DEFAULT_LLMS_TOKEN_LIMIT;
|
|
2574
|
+
const output = generateLlmsTxt(context, {
|
|
2575
|
+
tokenLimit,
|
|
2576
|
+
includeInstall: true,
|
|
2577
|
+
includeQuickStart: true
|
|
2578
|
+
});
|
|
2579
|
+
context.outputs.set("llms", output);
|
|
2580
|
+
} catch (error) {
|
|
2581
|
+
context.errors.push(error instanceof Error ? error : new Error(String(error)));
|
|
2582
|
+
}
|
|
2583
|
+
});
|
|
2584
|
+
}
|
|
2585
|
+
};
|
|
2586
|
+
|
|
2587
|
+
// src/outputs/llms-full.ts
|
|
2588
|
+
function generateLlmsFullTxt(context, options = {}) {
|
|
2589
|
+
const {
|
|
2590
|
+
includeExamples = true,
|
|
2591
|
+
includeParamDescriptions = true,
|
|
2592
|
+
includeSourceLocations = false,
|
|
2593
|
+
includeDeprecations = true
|
|
2594
|
+
} = options;
|
|
2595
|
+
const { package: pkg, api, readme } = context;
|
|
2596
|
+
const sections = [];
|
|
2597
|
+
sections.push(`# ${pkg.name} v${pkg.version}`);
|
|
2598
|
+
if (pkg.description) {
|
|
2599
|
+
sections.push(`
|
|
2600
|
+
> ${pkg.description}`);
|
|
2601
|
+
}
|
|
2602
|
+
sections.push("");
|
|
2603
|
+
sections.push("## Package Info\n");
|
|
2604
|
+
sections.push(`- **Version:** ${pkg.version}`);
|
|
2605
|
+
if (pkg.license) {
|
|
2606
|
+
sections.push(`- **License:** ${pkg.license}`);
|
|
2607
|
+
}
|
|
2608
|
+
if (pkg.homepage) {
|
|
2609
|
+
sections.push(`- **Homepage:** ${pkg.homepage}`);
|
|
2610
|
+
}
|
|
2611
|
+
if (pkg.repository) {
|
|
2612
|
+
sections.push(`- **Repository:** ${pkg.repository.url}`);
|
|
2613
|
+
}
|
|
2614
|
+
sections.push("");
|
|
2615
|
+
sections.push("## Installation\n");
|
|
2616
|
+
sections.push("```bash");
|
|
2617
|
+
sections.push(`# npm`);
|
|
2618
|
+
sections.push(`npm install ${pkg.name}`);
|
|
2619
|
+
sections.push("");
|
|
2620
|
+
sections.push(`# yarn`);
|
|
2621
|
+
sections.push(`yarn add ${pkg.name}`);
|
|
2622
|
+
sections.push("");
|
|
2623
|
+
sections.push(`# pnpm`);
|
|
2624
|
+
sections.push(`pnpm add ${pkg.name}`);
|
|
2625
|
+
sections.push("```\n");
|
|
2626
|
+
if (readme?.quickStart) {
|
|
2627
|
+
sections.push("## Quick Start\n");
|
|
2628
|
+
sections.push(readme.quickStart);
|
|
2629
|
+
sections.push("");
|
|
2630
|
+
}
|
|
2631
|
+
sections.push("## API Reference\n");
|
|
2632
|
+
const functions = api.filter((e) => e.kind === "function");
|
|
2633
|
+
const classes = api.filter((e) => e.kind === "class");
|
|
2634
|
+
const interfaces = api.filter((e) => e.kind === "interface");
|
|
2635
|
+
const types = api.filter((e) => e.kind === "type");
|
|
2636
|
+
const constants = api.filter((e) => e.kind === "constant");
|
|
2637
|
+
const enums = api.filter((e) => e.kind === "enum");
|
|
2638
|
+
if (functions.length > 0) {
|
|
2639
|
+
sections.push("### Functions\n");
|
|
2640
|
+
for (const fn of functions) {
|
|
2641
|
+
sections.push(formatFunction(fn, { includeExamples, includeParamDescriptions, includeDeprecations, includeSourceLocations }));
|
|
2642
|
+
sections.push("");
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
if (classes.length > 0) {
|
|
2646
|
+
sections.push("### Classes\n");
|
|
2647
|
+
for (const cls of classes) {
|
|
2648
|
+
sections.push(formatClass(cls, { includeExamples, includeDeprecations}));
|
|
2649
|
+
sections.push("");
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
if (interfaces.length > 0) {
|
|
2653
|
+
sections.push("### Interfaces\n");
|
|
2654
|
+
for (const iface of interfaces) {
|
|
2655
|
+
sections.push(formatInterface(iface, { includeDeprecations}));
|
|
2656
|
+
sections.push("");
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
if (types.length > 0) {
|
|
2660
|
+
sections.push("### Types\n");
|
|
2661
|
+
for (const type of types) {
|
|
2662
|
+
sections.push(formatType(type, { includeDeprecations }));
|
|
2663
|
+
sections.push("");
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
if (enums.length > 0) {
|
|
2667
|
+
sections.push("### Enums\n");
|
|
2668
|
+
for (const enumEntry of enums) {
|
|
2669
|
+
sections.push(formatEnum(enumEntry));
|
|
2670
|
+
sections.push("");
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2673
|
+
if (constants.length > 0) {
|
|
2674
|
+
sections.push("### Constants\n");
|
|
2675
|
+
for (const constant of constants) {
|
|
2676
|
+
sections.push(formatConstant(constant));
|
|
2677
|
+
sections.push("");
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
const output = sections.join("\n");
|
|
2681
|
+
context.tokenCount = countTokens(output);
|
|
2682
|
+
return output;
|
|
2683
|
+
}
|
|
2684
|
+
function formatFunction(fn, options) {
|
|
2685
|
+
const lines = [];
|
|
2686
|
+
lines.push(`#### \`${fn.name}\``);
|
|
2687
|
+
if (options.includeDeprecations && fn.deprecated) {
|
|
2688
|
+
lines.push(`
|
|
2689
|
+
> \u26A0\uFE0F **Deprecated:** ${typeof fn.deprecated === "string" ? fn.deprecated : "This function is deprecated."}`);
|
|
2690
|
+
}
|
|
2691
|
+
if (fn.description) {
|
|
2692
|
+
lines.push(`
|
|
2693
|
+
${fn.description}`);
|
|
2694
|
+
}
|
|
2695
|
+
lines.push("\n**Signature:**");
|
|
2696
|
+
lines.push("```typescript");
|
|
2697
|
+
lines.push(fn.signature);
|
|
2698
|
+
lines.push("```");
|
|
2699
|
+
if (fn.params && fn.params.length > 0 && options.includeParamDescriptions) {
|
|
2700
|
+
lines.push("\n**Parameters:**\n");
|
|
2701
|
+
for (const param of fn.params) {
|
|
2702
|
+
const optional = param.optional ? " (optional)" : "";
|
|
2703
|
+
const defaultVal = param.defaultValue ? ` = \`${param.defaultValue}\`` : "";
|
|
2704
|
+
lines.push(`- \`${param.name}: ${param.type || "unknown"}\`${optional}${defaultVal}`);
|
|
2705
|
+
if (param.description) {
|
|
2706
|
+
lines.push(` - ${param.description}`);
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
if (fn.returns) {
|
|
2711
|
+
lines.push("\n**Returns:**");
|
|
2712
|
+
lines.push(`- \`${fn.returns.type}\`${fn.returns.description ? ` - ${fn.returns.description}` : ""}`);
|
|
2713
|
+
}
|
|
2714
|
+
if (options.includeExamples && fn.examples && fn.examples.length > 0) {
|
|
2715
|
+
lines.push("\n**Examples:**");
|
|
2716
|
+
for (const example of fn.examples) {
|
|
2717
|
+
if (example.includes("```")) {
|
|
2718
|
+
lines.push(example);
|
|
2719
|
+
} else {
|
|
2720
|
+
lines.push("```typescript");
|
|
2721
|
+
lines.push(example);
|
|
2722
|
+
lines.push("```");
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
if (options.includeSourceLocations && fn.sourceFile) {
|
|
2727
|
+
lines.push(`
|
|
2728
|
+
*Source: ${fn.sourceFile}${fn.line ? `:${fn.line}` : ""}*`);
|
|
2729
|
+
}
|
|
2730
|
+
return lines.join("\n");
|
|
2731
|
+
}
|
|
2732
|
+
function formatClass(cls, options) {
|
|
2733
|
+
const lines = [];
|
|
2734
|
+
lines.push(`#### \`${cls.name}\``);
|
|
2735
|
+
if (options.includeDeprecations && cls.deprecated) {
|
|
2736
|
+
lines.push(`
|
|
2737
|
+
> \u26A0\uFE0F **Deprecated:** ${typeof cls.deprecated === "string" ? cls.deprecated : "This class is deprecated."}`);
|
|
2738
|
+
}
|
|
2739
|
+
if (cls.description) {
|
|
2740
|
+
lines.push(`
|
|
2741
|
+
${cls.description}`);
|
|
2742
|
+
}
|
|
2743
|
+
lines.push("\n**Signature:**");
|
|
2744
|
+
lines.push("```typescript");
|
|
2745
|
+
let sig = cls.signature;
|
|
2746
|
+
if (cls.extends && cls.extends.length > 0) {
|
|
2747
|
+
sig += ` extends ${cls.extends.join(", ")}`;
|
|
2748
|
+
}
|
|
2749
|
+
if (cls.implements && cls.implements.length > 0) {
|
|
2750
|
+
sig += ` implements ${cls.implements.join(", ")}`;
|
|
2751
|
+
}
|
|
2752
|
+
lines.push(sig);
|
|
2753
|
+
lines.push("```");
|
|
2754
|
+
if (cls.properties && cls.properties.length > 0) {
|
|
2755
|
+
lines.push("\n**Properties:**\n");
|
|
2756
|
+
for (const prop of cls.properties) {
|
|
2757
|
+
lines.push(`- \`${prop.name}\`: \`${prop.signature.split(":").slice(1).join(":").trim() || "unknown"}\``);
|
|
2758
|
+
if (prop.description) {
|
|
2759
|
+
lines.push(` - ${prop.description}`);
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
if (cls.methods && cls.methods.length > 0) {
|
|
2764
|
+
lines.push("\n**Methods:**\n");
|
|
2765
|
+
for (const method of cls.methods) {
|
|
2766
|
+
const params = method.params?.map((p) => `${p.name}: ${p.type || "unknown"}`).join(", ") || "";
|
|
2767
|
+
const returnType = method.returns?.type || "void";
|
|
2768
|
+
lines.push(`- \`${method.name}(${params}): ${returnType}\``);
|
|
2769
|
+
if (method.description) {
|
|
2770
|
+
lines.push(` - ${method.description}`);
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
if (options.includeExamples && cls.examples && cls.examples.length > 0) {
|
|
2775
|
+
lines.push("\n**Examples:**");
|
|
2776
|
+
for (const example of cls.examples) {
|
|
2777
|
+
if (example.includes("```")) {
|
|
2778
|
+
lines.push(example);
|
|
2779
|
+
} else {
|
|
2780
|
+
lines.push("```typescript");
|
|
2781
|
+
lines.push(example);
|
|
2782
|
+
lines.push("```");
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
return lines.join("\n");
|
|
2787
|
+
}
|
|
2788
|
+
function formatInterface(iface, options) {
|
|
2789
|
+
const lines = [];
|
|
2790
|
+
lines.push(`#### \`${iface.name}\``);
|
|
2791
|
+
if (options.includeDeprecations && iface.deprecated) {
|
|
2792
|
+
lines.push(`
|
|
2793
|
+
> \u26A0\uFE0F **Deprecated**`);
|
|
2794
|
+
}
|
|
2795
|
+
if (iface.description) {
|
|
2796
|
+
lines.push(`
|
|
2797
|
+
${iface.description}`);
|
|
2798
|
+
}
|
|
2799
|
+
lines.push("\n```typescript");
|
|
2800
|
+
let sig = iface.signature;
|
|
2801
|
+
if (iface.extends && iface.extends.length > 0) {
|
|
2802
|
+
sig += ` extends ${iface.extends.join(", ")}`;
|
|
2803
|
+
}
|
|
2804
|
+
lines.push(sig + " {");
|
|
2805
|
+
if (iface.properties && iface.properties.length > 0) {
|
|
2806
|
+
for (const prop of iface.properties) {
|
|
2807
|
+
lines.push(` ${prop.signature};`);
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
if (iface.methods && iface.methods.length > 0) {
|
|
2811
|
+
for (const method of iface.methods) {
|
|
2812
|
+
lines.push(` ${method.signature};`);
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
lines.push("}");
|
|
2816
|
+
lines.push("```");
|
|
2817
|
+
return lines.join("\n");
|
|
2818
|
+
}
|
|
2819
|
+
function formatType(type, options) {
|
|
2820
|
+
const lines = [];
|
|
2821
|
+
lines.push(`#### \`${type.name}\``);
|
|
2822
|
+
if (options.includeDeprecations && type.deprecated) {
|
|
2823
|
+
lines.push(`
|
|
2824
|
+
> \u26A0\uFE0F **Deprecated**`);
|
|
2825
|
+
}
|
|
2826
|
+
if (type.description) {
|
|
2827
|
+
lines.push(`
|
|
2828
|
+
${type.description}`);
|
|
2829
|
+
}
|
|
2830
|
+
lines.push("\n```typescript");
|
|
2831
|
+
lines.push(type.signature);
|
|
2832
|
+
lines.push("```");
|
|
2833
|
+
return lines.join("\n");
|
|
2834
|
+
}
|
|
2835
|
+
function formatEnum(enumEntry) {
|
|
2836
|
+
const lines = [];
|
|
2837
|
+
lines.push(`#### \`${enumEntry.name}\``);
|
|
2838
|
+
if (enumEntry.description) {
|
|
2839
|
+
lines.push(`
|
|
2840
|
+
${enumEntry.description}`);
|
|
2841
|
+
}
|
|
2842
|
+
lines.push("\n```typescript");
|
|
2843
|
+
lines.push(`enum ${enumEntry.name} {`);
|
|
2844
|
+
if (enumEntry.members) {
|
|
2845
|
+
for (const member of enumEntry.members) {
|
|
2846
|
+
if (member.value !== void 0) {
|
|
2847
|
+
lines.push(` ${member.name} = ${JSON.stringify(member.value)},`);
|
|
2848
|
+
} else {
|
|
2849
|
+
lines.push(` ${member.name},`);
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
lines.push("}");
|
|
2854
|
+
lines.push("```");
|
|
2855
|
+
return lines.join("\n");
|
|
2856
|
+
}
|
|
2857
|
+
function formatConstant(constant) {
|
|
2858
|
+
const lines = [];
|
|
2859
|
+
lines.push(`#### \`${constant.name}\``);
|
|
2860
|
+
if (constant.description) {
|
|
2861
|
+
lines.push(`
|
|
2862
|
+
${constant.description}`);
|
|
2863
|
+
}
|
|
2864
|
+
lines.push("\n```typescript");
|
|
2865
|
+
lines.push(constant.signature);
|
|
2866
|
+
lines.push("```");
|
|
2867
|
+
return lines.join("\n");
|
|
2868
|
+
}
|
|
2869
|
+
|
|
2870
|
+
// src/plugins/core/llms-full-output.ts
|
|
2871
|
+
var llmsFullOutputPlugin = {
|
|
2872
|
+
name: "llms-full-output",
|
|
2873
|
+
version: "1.0.0",
|
|
2874
|
+
category: "output",
|
|
2875
|
+
install(kernel) {
|
|
2876
|
+
kernel.on("output:start", async (context) => {
|
|
2877
|
+
if (!context.options.formats?.includes("llms-full")) {
|
|
2878
|
+
return;
|
|
2879
|
+
}
|
|
2880
|
+
try {
|
|
2881
|
+
const output = generateLlmsFullTxt(context, {
|
|
2882
|
+
includeExamples: true,
|
|
2883
|
+
includeParamDescriptions: true,
|
|
2884
|
+
includeDeprecations: true
|
|
2885
|
+
});
|
|
2886
|
+
context.outputs.set("llms-full", output);
|
|
2887
|
+
} catch (error) {
|
|
2888
|
+
context.errors.push(error instanceof Error ? error : new Error(String(error)));
|
|
2889
|
+
}
|
|
2890
|
+
});
|
|
2891
|
+
}
|
|
2892
|
+
};
|
|
2893
|
+
|
|
2894
|
+
// src/outputs/markdown.ts
|
|
2895
|
+
function generateMarkdown(context, options = {}) {
|
|
2896
|
+
const {
|
|
2897
|
+
includeToc = true,
|
|
2898
|
+
includeParamTables = true,
|
|
2899
|
+
includeBadges = true,
|
|
2900
|
+
repositoryUrl
|
|
2901
|
+
} = options;
|
|
2902
|
+
const { package: pkg, api, readme } = context;
|
|
2903
|
+
const sections = [];
|
|
2904
|
+
sections.push(`# ${pkg.name}`);
|
|
2905
|
+
sections.push("");
|
|
2906
|
+
if (includeBadges) {
|
|
2907
|
+
const badges = [];
|
|
2908
|
+
badges.push(`})`);
|
|
2909
|
+
if (pkg.license) {
|
|
2910
|
+
badges.push(`})`);
|
|
2911
|
+
}
|
|
2912
|
+
if (badges.length > 0) {
|
|
2913
|
+
sections.push(badges.join(" "));
|
|
2914
|
+
sections.push("");
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
if (pkg.description) {
|
|
2918
|
+
sections.push(`> ${pkg.description}`);
|
|
2919
|
+
sections.push("");
|
|
2920
|
+
}
|
|
2921
|
+
if (includeToc) {
|
|
2922
|
+
sections.push("## Table of Contents\n");
|
|
2923
|
+
sections.push("- [Installation](#installation)");
|
|
2924
|
+
if (readme?.quickStart) {
|
|
2925
|
+
sections.push("- [Quick Start](#quick-start)");
|
|
2926
|
+
}
|
|
2927
|
+
sections.push("- [API Reference](#api-reference)");
|
|
2928
|
+
const functions2 = api.filter((e) => e.kind === "function");
|
|
2929
|
+
const classes2 = api.filter((e) => e.kind === "class");
|
|
2930
|
+
const interfaces2 = api.filter((e) => e.kind === "interface");
|
|
2931
|
+
const types2 = api.filter((e) => e.kind === "type");
|
|
2932
|
+
if (functions2.length > 0) {
|
|
2933
|
+
sections.push(" - [Functions](#functions)");
|
|
2934
|
+
}
|
|
2935
|
+
if (classes2.length > 0) {
|
|
2936
|
+
sections.push(" - [Classes](#classes)");
|
|
2937
|
+
}
|
|
2938
|
+
if (interfaces2.length > 0) {
|
|
2939
|
+
sections.push(" - [Interfaces](#interfaces)");
|
|
2940
|
+
}
|
|
2941
|
+
if (types2.length > 0) {
|
|
2942
|
+
sections.push(" - [Types](#types)");
|
|
2943
|
+
}
|
|
2944
|
+
sections.push("");
|
|
2945
|
+
}
|
|
2946
|
+
sections.push("## Installation\n");
|
|
2947
|
+
sections.push("```bash");
|
|
2948
|
+
sections.push(`npm install ${pkg.name}`);
|
|
2949
|
+
sections.push("```\n");
|
|
2950
|
+
sections.push("Or with yarn:\n");
|
|
2951
|
+
sections.push("```bash");
|
|
2952
|
+
sections.push(`yarn add ${pkg.name}`);
|
|
2953
|
+
sections.push("```\n");
|
|
2954
|
+
if (readme?.quickStart) {
|
|
2955
|
+
sections.push("## Quick Start\n");
|
|
2956
|
+
sections.push(readme.quickStart);
|
|
2957
|
+
sections.push("");
|
|
2958
|
+
}
|
|
2959
|
+
sections.push("## API Reference\n");
|
|
2960
|
+
const functions = api.filter((e) => e.kind === "function");
|
|
2961
|
+
const classes = api.filter((e) => e.kind === "class");
|
|
2962
|
+
const interfaces = api.filter((e) => e.kind === "interface");
|
|
2963
|
+
const types = api.filter((e) => e.kind === "type");
|
|
2964
|
+
const enums = api.filter((e) => e.kind === "enum");
|
|
2965
|
+
const constants = api.filter((e) => e.kind === "constant");
|
|
2966
|
+
if (functions.length > 0) {
|
|
2967
|
+
sections.push("### Functions\n");
|
|
2968
|
+
for (const fn of functions) {
|
|
2969
|
+
sections.push(formatFunctionMd(fn, { includeParamTables, repositoryUrl }));
|
|
2970
|
+
sections.push("");
|
|
2971
|
+
sections.push("---\n");
|
|
2972
|
+
}
|
|
2973
|
+
}
|
|
2974
|
+
if (classes.length > 0) {
|
|
2975
|
+
sections.push("### Classes\n");
|
|
2976
|
+
for (const cls of classes) {
|
|
2977
|
+
sections.push(formatClassMd(cls));
|
|
2978
|
+
sections.push("");
|
|
2979
|
+
sections.push("---\n");
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2982
|
+
if (interfaces.length > 0) {
|
|
2983
|
+
sections.push("### Interfaces\n");
|
|
2984
|
+
for (const iface of interfaces) {
|
|
2985
|
+
sections.push(formatInterfaceMd(iface));
|
|
2986
|
+
sections.push("");
|
|
2987
|
+
sections.push("---\n");
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
if (types.length > 0) {
|
|
2991
|
+
sections.push("### Types\n");
|
|
2992
|
+
for (const type of types) {
|
|
2993
|
+
sections.push(formatTypeMd(type));
|
|
2994
|
+
sections.push("");
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
if (enums.length > 0) {
|
|
2998
|
+
sections.push("### Enums\n");
|
|
2999
|
+
for (const enumEntry of enums) {
|
|
3000
|
+
sections.push(formatEnumMd(enumEntry));
|
|
3001
|
+
sections.push("");
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3004
|
+
if (constants.length > 0) {
|
|
3005
|
+
sections.push("### Constants\n");
|
|
3006
|
+
for (const constant of constants) {
|
|
3007
|
+
sections.push(formatConstantMd(constant));
|
|
3008
|
+
}
|
|
3009
|
+
sections.push("");
|
|
3010
|
+
}
|
|
3011
|
+
const output = sections.join("\n");
|
|
3012
|
+
context.tokenCount = countTokens(output);
|
|
3013
|
+
return output;
|
|
3014
|
+
}
|
|
3015
|
+
function formatFunctionMd(fn, options) {
|
|
3016
|
+
const lines = [];
|
|
3017
|
+
const anchor = fn.name.toLowerCase();
|
|
3018
|
+
lines.push(`<a name="${anchor}"></a>`);
|
|
3019
|
+
lines.push(`#### \`${fn.name}()\``);
|
|
3020
|
+
if (fn.deprecated) {
|
|
3021
|
+
lines.push(`
|
|
3022
|
+
> \u26A0\uFE0F **Deprecated:** ${typeof fn.deprecated === "string" ? fn.deprecated : "This function is deprecated."}
|
|
3023
|
+
`);
|
|
3024
|
+
}
|
|
3025
|
+
if (fn.description) {
|
|
3026
|
+
lines.push(`
|
|
3027
|
+
${fn.description}
|
|
3028
|
+
`);
|
|
3029
|
+
}
|
|
3030
|
+
lines.push("**Signature:**\n");
|
|
3031
|
+
lines.push("```typescript");
|
|
3032
|
+
lines.push(fn.signature);
|
|
3033
|
+
lines.push("```\n");
|
|
3034
|
+
if (fn.params && fn.params.length > 0 && options.includeParamTables) {
|
|
3035
|
+
lines.push("**Parameters:**\n");
|
|
3036
|
+
lines.push("| Name | Type | Required | Description |");
|
|
3037
|
+
lines.push("|------|------|----------|-------------|");
|
|
3038
|
+
for (const param of fn.params) {
|
|
3039
|
+
const required = param.optional ? "No" : "Yes";
|
|
3040
|
+
const desc = param.description || "-";
|
|
3041
|
+
const defaultVal = param.defaultValue ? ` (default: \`${param.defaultValue}\`)` : "";
|
|
3042
|
+
lines.push(`| \`${param.name}\` | \`${param.type || "unknown"}\` | ${required} | ${desc}${defaultVal} |`);
|
|
3043
|
+
}
|
|
3044
|
+
lines.push("");
|
|
3045
|
+
}
|
|
3046
|
+
if (fn.returns) {
|
|
3047
|
+
lines.push("**Returns:**\n");
|
|
3048
|
+
lines.push(`\`${fn.returns.type}\`${fn.returns.description ? ` - ${fn.returns.description}` : ""}
|
|
3049
|
+
`);
|
|
3050
|
+
}
|
|
3051
|
+
if (fn.examples && fn.examples.length > 0) {
|
|
3052
|
+
lines.push("**Example:**\n");
|
|
3053
|
+
for (const example of fn.examples) {
|
|
3054
|
+
if (example.includes("```")) {
|
|
3055
|
+
lines.push(example);
|
|
3056
|
+
} else {
|
|
3057
|
+
lines.push("```typescript");
|
|
3058
|
+
lines.push(example);
|
|
3059
|
+
lines.push("```");
|
|
3060
|
+
}
|
|
3061
|
+
}
|
|
3062
|
+
lines.push("");
|
|
3063
|
+
}
|
|
3064
|
+
if (options.repositoryUrl && fn.sourceFile) {
|
|
3065
|
+
const sourceUrl = `${options.repositoryUrl}/blob/main/${fn.sourceFile}${fn.line ? `#L${fn.line}` : ""}`;
|
|
3066
|
+
lines.push(`[View source](${sourceUrl})
|
|
3067
|
+
`);
|
|
3068
|
+
}
|
|
3069
|
+
return lines.join("\n");
|
|
3070
|
+
}
|
|
3071
|
+
function formatClassMd(cls, options) {
|
|
3072
|
+
const lines = [];
|
|
3073
|
+
const anchor = cls.name.toLowerCase();
|
|
3074
|
+
lines.push(`<a name="${anchor}"></a>`);
|
|
3075
|
+
lines.push(`#### \`${cls.name}\``);
|
|
3076
|
+
if (cls.deprecated) {
|
|
3077
|
+
lines.push(`
|
|
3078
|
+
> \u26A0\uFE0F **Deprecated**
|
|
3079
|
+
`);
|
|
3080
|
+
}
|
|
3081
|
+
if (cls.description) {
|
|
3082
|
+
lines.push(`
|
|
3083
|
+
${cls.description}
|
|
3084
|
+
`);
|
|
3085
|
+
}
|
|
3086
|
+
if (cls.extends && cls.extends.length > 0) {
|
|
3087
|
+
lines.push(`**Extends:** ${cls.extends.map((e) => `\`${e}\``).join(", ")}
|
|
3088
|
+
`);
|
|
3089
|
+
}
|
|
3090
|
+
if (cls.implements && cls.implements.length > 0) {
|
|
3091
|
+
lines.push(`**Implements:** ${cls.implements.map((e) => `\`${e}\``).join(", ")}
|
|
3092
|
+
`);
|
|
3093
|
+
}
|
|
3094
|
+
const constructor = cls.methods?.find((m) => m.name === "constructor");
|
|
3095
|
+
if (constructor) {
|
|
3096
|
+
lines.push("**Constructor:**\n");
|
|
3097
|
+
lines.push("```typescript");
|
|
3098
|
+
lines.push(`new ${cls.name}(${constructor.params?.map((p) => `${p.name}: ${p.type}`).join(", ") || ""})`);
|
|
3099
|
+
lines.push("```\n");
|
|
3100
|
+
}
|
|
3101
|
+
if (cls.properties && cls.properties.length > 0) {
|
|
3102
|
+
lines.push("**Properties:**\n");
|
|
3103
|
+
lines.push("| Name | Type | Description |");
|
|
3104
|
+
lines.push("|------|------|-------------|");
|
|
3105
|
+
for (const prop of cls.properties) {
|
|
3106
|
+
const type = prop.signature.split(":").slice(1).join(":").trim() || "unknown";
|
|
3107
|
+
lines.push(`| \`${prop.name}\` | \`${type}\` | ${prop.description || "-"} |`);
|
|
3108
|
+
}
|
|
3109
|
+
lines.push("");
|
|
3110
|
+
}
|
|
3111
|
+
const methods = cls.methods?.filter((m) => m.name !== "constructor") || [];
|
|
3112
|
+
if (methods.length > 0) {
|
|
3113
|
+
lines.push("**Methods:**\n");
|
|
3114
|
+
lines.push("| Method | Returns | Description |");
|
|
3115
|
+
lines.push("|--------|---------|-------------|");
|
|
3116
|
+
for (const method of methods) {
|
|
3117
|
+
const params = method.params?.map((p) => `${p.name}`).join(", ") || "";
|
|
3118
|
+
const returnType = method.returns?.type || "void";
|
|
3119
|
+
lines.push(`| \`${method.name}(${params})\` | \`${returnType}\` | ${method.description || "-"} |`);
|
|
3120
|
+
}
|
|
3121
|
+
lines.push("");
|
|
3122
|
+
}
|
|
3123
|
+
return lines.join("\n");
|
|
3124
|
+
}
|
|
3125
|
+
function formatInterfaceMd(iface) {
|
|
3126
|
+
const lines = [];
|
|
3127
|
+
lines.push(`#### \`${iface.name}\``);
|
|
3128
|
+
if (iface.description) {
|
|
3129
|
+
lines.push(`
|
|
3130
|
+
${iface.description}
|
|
3131
|
+
`);
|
|
3132
|
+
}
|
|
3133
|
+
if (iface.extends && iface.extends.length > 0) {
|
|
3134
|
+
lines.push(`**Extends:** ${iface.extends.map((e) => `\`${e}\``).join(", ")}
|
|
3135
|
+
`);
|
|
3136
|
+
}
|
|
3137
|
+
if (iface.properties && iface.properties.length > 0) {
|
|
3138
|
+
lines.push("| Property | Type | Description |");
|
|
3139
|
+
lines.push("|----------|------|-------------|");
|
|
3140
|
+
for (const prop of iface.properties) {
|
|
3141
|
+
const type = prop.signature.split(":").slice(1).join(":").trim() || "unknown";
|
|
3142
|
+
lines.push(`| \`${prop.name}\` | \`${type}\` | ${prop.description || "-"} |`);
|
|
3143
|
+
}
|
|
3144
|
+
lines.push("");
|
|
3145
|
+
}
|
|
3146
|
+
lines.push("<details>");
|
|
3147
|
+
lines.push("<summary>Full Definition</summary>\n");
|
|
3148
|
+
lines.push("```typescript");
|
|
3149
|
+
lines.push(`interface ${iface.name} {`);
|
|
3150
|
+
if (iface.properties) {
|
|
3151
|
+
for (const prop of iface.properties) {
|
|
3152
|
+
lines.push(` ${prop.signature};`);
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3155
|
+
if (iface.methods) {
|
|
3156
|
+
for (const method of iface.methods) {
|
|
3157
|
+
lines.push(` ${method.signature};`);
|
|
3158
|
+
}
|
|
3159
|
+
}
|
|
3160
|
+
lines.push("}");
|
|
3161
|
+
lines.push("```");
|
|
3162
|
+
lines.push("</details>");
|
|
3163
|
+
return lines.join("\n");
|
|
3164
|
+
}
|
|
3165
|
+
function formatTypeMd(type) {
|
|
3166
|
+
const lines = [];
|
|
3167
|
+
lines.push(`#### \`${type.name}\``);
|
|
3168
|
+
if (type.description) {
|
|
3169
|
+
lines.push(`
|
|
3170
|
+
${type.description}
|
|
3171
|
+
`);
|
|
3172
|
+
}
|
|
3173
|
+
lines.push("```typescript");
|
|
3174
|
+
lines.push(type.signature);
|
|
3175
|
+
lines.push("```");
|
|
3176
|
+
return lines.join("\n");
|
|
3177
|
+
}
|
|
3178
|
+
function formatEnumMd(enumEntry) {
|
|
3179
|
+
const lines = [];
|
|
3180
|
+
lines.push(`#### \`${enumEntry.name}\``);
|
|
3181
|
+
if (enumEntry.description) {
|
|
3182
|
+
lines.push(`
|
|
3183
|
+
${enumEntry.description}
|
|
3184
|
+
`);
|
|
3185
|
+
}
|
|
3186
|
+
if (enumEntry.members && enumEntry.members.length > 0) {
|
|
3187
|
+
lines.push("| Member | Value |");
|
|
3188
|
+
lines.push("|--------|-------|");
|
|
3189
|
+
for (const member of enumEntry.members) {
|
|
3190
|
+
const value = member.value !== void 0 ? `\`${JSON.stringify(member.value)}\`` : "-";
|
|
3191
|
+
lines.push(`| \`${member.name}\` | ${value} |`);
|
|
3192
|
+
}
|
|
3193
|
+
lines.push("");
|
|
3194
|
+
}
|
|
3195
|
+
return lines.join("\n");
|
|
3196
|
+
}
|
|
3197
|
+
function formatConstantMd(constant) {
|
|
3198
|
+
const lines = [];
|
|
3199
|
+
lines.push(`- **\`${constant.name}\`**: \`${constant.signature.split(":").slice(1).join(":").trim() || "unknown"}\``);
|
|
3200
|
+
if (constant.description) {
|
|
3201
|
+
lines.push(` - ${constant.description}`);
|
|
3202
|
+
}
|
|
3203
|
+
return lines.join("\n");
|
|
3204
|
+
}
|
|
3205
|
+
|
|
3206
|
+
// src/plugins/core/markdown-output.ts
|
|
3207
|
+
var markdownOutputPlugin = {
|
|
3208
|
+
name: "markdown-output",
|
|
3209
|
+
version: "1.0.0",
|
|
3210
|
+
category: "output",
|
|
3211
|
+
install(kernel) {
|
|
3212
|
+
kernel.on("output:start", async (context) => {
|
|
3213
|
+
if (!context.options.formats?.includes("markdown")) {
|
|
3214
|
+
return;
|
|
3215
|
+
}
|
|
3216
|
+
try {
|
|
3217
|
+
const repositoryUrl = context.package.repository?.url?.replace(/^git\+/, "").replace(/\.git$/, "");
|
|
3218
|
+
const output = generateMarkdown(context, {
|
|
3219
|
+
includeToc: true,
|
|
3220
|
+
includeParamTables: true,
|
|
3221
|
+
includeBadges: true,
|
|
3222
|
+
repositoryUrl
|
|
3223
|
+
});
|
|
3224
|
+
context.outputs.set("markdown", output);
|
|
3225
|
+
} catch (error) {
|
|
3226
|
+
context.errors.push(error instanceof Error ? error : new Error(String(error)));
|
|
3227
|
+
}
|
|
3228
|
+
});
|
|
3229
|
+
}
|
|
3230
|
+
};
|
|
3231
|
+
|
|
3232
|
+
// src/outputs/json.ts
|
|
3233
|
+
function generateJson(context, options = {}) {
|
|
3234
|
+
const { pretty = true, includeEmpty = false, includeSourceLocations = true } = options;
|
|
3235
|
+
const output = generateJsonObject(context, { includeEmpty, includeSourceLocations });
|
|
3236
|
+
return pretty ? JSON.stringify(output, null, 2) : JSON.stringify(output);
|
|
3237
|
+
}
|
|
3238
|
+
function generateJsonObject(context, options = {}) {
|
|
3239
|
+
const { includeEmpty = false, includeSourceLocations = true } = options;
|
|
3240
|
+
const { package: pkg, api } = context;
|
|
3241
|
+
const functions = api.filter((e) => e.kind === "function");
|
|
3242
|
+
const classes = api.filter((e) => e.kind === "class");
|
|
3243
|
+
const interfaces = api.filter((e) => e.kind === "interface");
|
|
3244
|
+
const types = api.filter((e) => e.kind === "type");
|
|
3245
|
+
const enums = api.filter((e) => e.kind === "enum");
|
|
3246
|
+
const constants = api.filter((e) => e.kind === "constant");
|
|
3247
|
+
const documented = api.filter((e) => e.description).length;
|
|
3248
|
+
const withExamples = api.filter((e) => e.examples && e.examples.length > 0).length;
|
|
3249
|
+
const output = {
|
|
3250
|
+
$schema: "https://npm-llms.oxog.dev/schema/v1.json",
|
|
3251
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3252
|
+
package: {
|
|
3253
|
+
name: pkg.name,
|
|
3254
|
+
version: pkg.version,
|
|
3255
|
+
description: pkg.description,
|
|
3256
|
+
license: pkg.license,
|
|
3257
|
+
homepage: pkg.homepage,
|
|
3258
|
+
repository: pkg.repository?.url,
|
|
3259
|
+
keywords: pkg.keywords
|
|
3260
|
+
},
|
|
3261
|
+
api: {
|
|
3262
|
+
functions: functions.map((fn) => transformFunction(fn, includeSourceLocations)),
|
|
3263
|
+
classes: classes.map((cls) => transformClass(cls, includeSourceLocations)),
|
|
3264
|
+
interfaces: interfaces.map(transformInterface),
|
|
3265
|
+
types: types.map(transformType),
|
|
3266
|
+
enums: enums.map(transformEnum),
|
|
3267
|
+
constants: constants.map(transformConstant)
|
|
3268
|
+
},
|
|
3269
|
+
stats: {
|
|
3270
|
+
totalExports: api.length,
|
|
3271
|
+
functions: functions.length,
|
|
3272
|
+
classes: classes.length,
|
|
3273
|
+
interfaces: interfaces.length,
|
|
3274
|
+
types: types.length,
|
|
3275
|
+
enums: enums.length,
|
|
3276
|
+
constants: constants.length,
|
|
3277
|
+
documented,
|
|
3278
|
+
withExamples
|
|
3279
|
+
}
|
|
3280
|
+
};
|
|
3281
|
+
if (!includeEmpty) {
|
|
3282
|
+
const apiObj = output.api;
|
|
3283
|
+
for (const [key, value] of Object.entries(apiObj)) {
|
|
3284
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
3285
|
+
delete apiObj[key];
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
return output;
|
|
3290
|
+
}
|
|
3291
|
+
function transformFunction(entry, includeSource) {
|
|
3292
|
+
const result = {
|
|
3293
|
+
name: entry.name,
|
|
3294
|
+
signature: entry.signature,
|
|
3295
|
+
description: entry.description,
|
|
3296
|
+
params: (entry.params || []).map((p) => ({
|
|
3297
|
+
name: p.name,
|
|
3298
|
+
type: p.type || "unknown",
|
|
3299
|
+
optional: p.optional ?? false,
|
|
3300
|
+
defaultValue: p.defaultValue,
|
|
3301
|
+
description: p.description
|
|
3302
|
+
})),
|
|
3303
|
+
returns: entry.returns ? {
|
|
3304
|
+
type: entry.returns.type,
|
|
3305
|
+
description: entry.returns.description
|
|
3306
|
+
} : void 0,
|
|
3307
|
+
examples: entry.examples || [],
|
|
3308
|
+
deprecated: entry.deprecated,
|
|
3309
|
+
since: entry.since,
|
|
3310
|
+
see: entry.see
|
|
3311
|
+
};
|
|
3312
|
+
if (includeSource) {
|
|
3313
|
+
result.sourceFile = entry.sourceFile;
|
|
3314
|
+
result.line = entry.line;
|
|
3315
|
+
}
|
|
3316
|
+
return result;
|
|
3317
|
+
}
|
|
3318
|
+
function transformClass(entry, includeSource) {
|
|
3319
|
+
const result = {
|
|
3320
|
+
name: entry.name,
|
|
3321
|
+
signature: entry.signature,
|
|
3322
|
+
description: entry.description,
|
|
3323
|
+
extends: entry.extends,
|
|
3324
|
+
implements: entry.implements,
|
|
3325
|
+
typeParams: entry.typeParams,
|
|
3326
|
+
properties: (entry.properties || []).map((p) => ({
|
|
3327
|
+
name: p.name,
|
|
3328
|
+
type: p.signature.split(":").slice(1).join(":").trim() || "unknown",
|
|
3329
|
+
description: p.description
|
|
3330
|
+
})),
|
|
3331
|
+
methods: (entry.methods || []).map((m) => transformFunction(m, includeSource)),
|
|
3332
|
+
deprecated: entry.deprecated
|
|
3333
|
+
};
|
|
3334
|
+
if (includeSource) {
|
|
3335
|
+
result.sourceFile = entry.sourceFile;
|
|
3336
|
+
}
|
|
3337
|
+
return result;
|
|
3338
|
+
}
|
|
3339
|
+
function transformInterface(entry) {
|
|
3340
|
+
return {
|
|
3341
|
+
name: entry.name,
|
|
3342
|
+
signature: entry.signature,
|
|
3343
|
+
description: entry.description,
|
|
3344
|
+
extends: entry.extends,
|
|
3345
|
+
typeParams: entry.typeParams,
|
|
3346
|
+
properties: (entry.properties || []).map((p) => ({
|
|
3347
|
+
name: p.name,
|
|
3348
|
+
type: p.signature.split(":").slice(1).join(":").trim() || "unknown",
|
|
3349
|
+
optional: p.signature.includes("?:"),
|
|
3350
|
+
description: p.description
|
|
3351
|
+
})),
|
|
3352
|
+
methods: (entry.methods || []).map((m) => ({
|
|
3353
|
+
name: m.name,
|
|
3354
|
+
signature: m.signature,
|
|
3355
|
+
description: m.description
|
|
3356
|
+
})),
|
|
3357
|
+
deprecated: entry.deprecated
|
|
3358
|
+
};
|
|
3359
|
+
}
|
|
3360
|
+
function transformType(entry) {
|
|
3361
|
+
return {
|
|
3362
|
+
name: entry.name,
|
|
3363
|
+
signature: entry.signature,
|
|
3364
|
+
description: entry.description,
|
|
3365
|
+
typeParams: entry.typeParams,
|
|
3366
|
+
deprecated: entry.deprecated
|
|
3367
|
+
};
|
|
3368
|
+
}
|
|
3369
|
+
function transformEnum(entry) {
|
|
3370
|
+
return {
|
|
3371
|
+
name: entry.name,
|
|
3372
|
+
description: entry.description,
|
|
3373
|
+
members: entry.members || []
|
|
3374
|
+
};
|
|
3375
|
+
}
|
|
3376
|
+
function transformConstant(entry) {
|
|
3377
|
+
return {
|
|
3378
|
+
name: entry.name,
|
|
3379
|
+
type: entry.signature.split(":").slice(1).join(":").trim() || "unknown",
|
|
3380
|
+
description: entry.description
|
|
3381
|
+
};
|
|
3382
|
+
}
|
|
3383
|
+
|
|
3384
|
+
// src/plugins/core/json-output.ts
|
|
3385
|
+
var jsonOutputPlugin = {
|
|
3386
|
+
name: "json-output",
|
|
3387
|
+
version: "1.0.0",
|
|
3388
|
+
category: "output",
|
|
3389
|
+
install(kernel) {
|
|
3390
|
+
kernel.on("output:start", async (context) => {
|
|
3391
|
+
if (!context.options.formats?.includes("json")) {
|
|
3392
|
+
return;
|
|
3393
|
+
}
|
|
3394
|
+
try {
|
|
3395
|
+
const output = generateJson(context, {
|
|
3396
|
+
pretty: true,
|
|
3397
|
+
includeEmpty: false,
|
|
3398
|
+
includeSourceLocations: true
|
|
3399
|
+
});
|
|
3400
|
+
context.outputs.set("json", output);
|
|
3401
|
+
} catch (error) {
|
|
3402
|
+
context.errors.push(error instanceof Error ? error : new Error(String(error)));
|
|
3403
|
+
}
|
|
3404
|
+
});
|
|
3405
|
+
}
|
|
3406
|
+
};
|
|
3407
|
+
|
|
3408
|
+
// src/plugins/core/index.ts
|
|
3409
|
+
var coreParserPlugins = [
|
|
3410
|
+
typesResolverPlugin,
|
|
3411
|
+
dtsParserPlugin,
|
|
3412
|
+
tsSourceParserPlugin,
|
|
3413
|
+
readmeParserPlugin
|
|
3414
|
+
];
|
|
3415
|
+
var coreOutputPlugins = [
|
|
3416
|
+
llmsOutputPlugin,
|
|
3417
|
+
llmsFullOutputPlugin,
|
|
3418
|
+
markdownOutputPlugin,
|
|
3419
|
+
jsonOutputPlugin
|
|
3420
|
+
];
|
|
3421
|
+
var corePlugins = [
|
|
3422
|
+
...coreParserPlugins,
|
|
3423
|
+
...coreOutputPlugins
|
|
3424
|
+
];
|
|
3425
|
+
|
|
3426
|
+
// src/core/extractor.ts
|
|
3427
|
+
var DEFAULT_FORMATS = ["llms", "llms-full", "markdown", "json"];
|
|
3428
|
+
function createExtractor(options = {}) {
|
|
3429
|
+
const kernel = createKernel();
|
|
3430
|
+
const cache = createCache(options.cache);
|
|
3431
|
+
for (const plugin of corePlugins) {
|
|
3432
|
+
kernel.use(plugin);
|
|
3433
|
+
}
|
|
3434
|
+
if (options.plugins) {
|
|
3435
|
+
for (const plugin of options.plugins) {
|
|
3436
|
+
kernel.use(plugin);
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
async function extract2(packageSpec, extractOptions = {}) {
|
|
3440
|
+
const startTime = Date.now();
|
|
3441
|
+
const { name, version } = parsePackageSpec(packageSpec);
|
|
3442
|
+
const cacheKey = buildPackageCacheKey(name, version ?? "latest", "result");
|
|
3443
|
+
let fromCache = false;
|
|
3444
|
+
if (cache && !extractOptions.ignoreCache) {
|
|
3445
|
+
const cached = await cache.get(cacheKey);
|
|
3446
|
+
if (cached) {
|
|
3447
|
+
return {
|
|
3448
|
+
...cached,
|
|
3449
|
+
fromCache: true
|
|
3450
|
+
};
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
const pkg = await fetchPackage(packageSpec, {
|
|
3454
|
+
registry: options.registry,
|
|
3455
|
+
timeout: options.ai?.timeout
|
|
3456
|
+
});
|
|
3457
|
+
const context = createContext(pkg, extractOptions);
|
|
3458
|
+
await kernel.emit("package:fetched", context);
|
|
3459
|
+
await kernel.emit("parse:start", context);
|
|
3460
|
+
await kernel.emit("parse:complete", context);
|
|
3461
|
+
if (extractOptions.enrichWithAI && options.ai) {
|
|
3462
|
+
await kernel.emit("enrich:start", context);
|
|
3463
|
+
await kernel.emit("enrich:complete", context);
|
|
3464
|
+
}
|
|
3465
|
+
await kernel.emit("output:start", context);
|
|
3466
|
+
await kernel.emit("output:complete", context);
|
|
3467
|
+
const result = {
|
|
3468
|
+
package: {
|
|
3469
|
+
name: pkg.name,
|
|
3470
|
+
version: pkg.version,
|
|
3471
|
+
description: pkg.description,
|
|
3472
|
+
tarball: pkg.tarball,
|
|
3473
|
+
types: pkg.types,
|
|
3474
|
+
main: pkg.main,
|
|
3475
|
+
exports: pkg.exports,
|
|
3476
|
+
repository: pkg.repository,
|
|
3477
|
+
keywords: pkg.keywords,
|
|
3478
|
+
author: pkg.author,
|
|
3479
|
+
license: pkg.license,
|
|
3480
|
+
homepage: pkg.homepage
|
|
3481
|
+
},
|
|
3482
|
+
api: context.api,
|
|
3483
|
+
outputs: Object.fromEntries(context.outputs),
|
|
3484
|
+
tokenCount: context.tokenCount,
|
|
3485
|
+
truncated: context.truncated,
|
|
3486
|
+
duration: Date.now() - startTime,
|
|
3487
|
+
fromCache
|
|
3488
|
+
};
|
|
3489
|
+
if (cache && !extractOptions.ignoreCache) {
|
|
3490
|
+
await cache.set(cacheKey, result);
|
|
3491
|
+
}
|
|
3492
|
+
return result;
|
|
3493
|
+
}
|
|
3494
|
+
async function fetchOnly(packageSpec) {
|
|
3495
|
+
return fetchPackage(packageSpec, {
|
|
3496
|
+
registry: options.registry
|
|
3497
|
+
});
|
|
3498
|
+
}
|
|
3499
|
+
function use(plugin) {
|
|
3500
|
+
kernel.use(plugin);
|
|
3501
|
+
return extractor;
|
|
3502
|
+
}
|
|
3503
|
+
function unregister(name) {
|
|
3504
|
+
return kernel.unregister(name);
|
|
3505
|
+
}
|
|
3506
|
+
function listPlugins() {
|
|
3507
|
+
return kernel.listPlugins();
|
|
3508
|
+
}
|
|
3509
|
+
async function clearCache() {
|
|
3510
|
+
if (cache) {
|
|
3511
|
+
await cache.clear();
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
async function getCacheStats() {
|
|
3515
|
+
if (cache) {
|
|
3516
|
+
return cache.getStats();
|
|
3517
|
+
}
|
|
3518
|
+
return { entries: 0, size: 0, dir: "" };
|
|
3519
|
+
}
|
|
3520
|
+
const extractor = {
|
|
3521
|
+
extract: extract2,
|
|
3522
|
+
fetch: fetchOnly,
|
|
3523
|
+
use,
|
|
3524
|
+
unregister,
|
|
3525
|
+
listPlugins,
|
|
3526
|
+
clearCache,
|
|
3527
|
+
getCacheStats
|
|
3528
|
+
};
|
|
3529
|
+
return extractor;
|
|
3530
|
+
}
|
|
3531
|
+
function createContext(pkg, options) {
|
|
3532
|
+
return {
|
|
3533
|
+
package: pkg,
|
|
3534
|
+
api: [],
|
|
3535
|
+
readme: void 0,
|
|
3536
|
+
changelog: void 0,
|
|
3537
|
+
options: {
|
|
3538
|
+
formats: options.formats ?? DEFAULT_FORMATS,
|
|
3539
|
+
enrichWithAI: options.enrichWithAI ?? false,
|
|
3540
|
+
aiTasks: options.aiTasks ?? ["descriptions", "examples", "summary"],
|
|
3541
|
+
llmsTokenLimit: options.llmsTokenLimit ?? 2e3,
|
|
3542
|
+
prioritize: options.prioritize ?? ["functions", "examples"],
|
|
3543
|
+
ignoreCache: options.ignoreCache ?? false
|
|
3544
|
+
},
|
|
3545
|
+
outputs: /* @__PURE__ */ new Map(),
|
|
3546
|
+
tokenCount: 0,
|
|
3547
|
+
truncated: false,
|
|
3548
|
+
startTime: Date.now(),
|
|
3549
|
+
fromCache: false,
|
|
3550
|
+
errors: []
|
|
3551
|
+
};
|
|
3552
|
+
}
|
|
3553
|
+
async function extract(packageSpec, options) {
|
|
3554
|
+
const extractor = createExtractor();
|
|
3555
|
+
return extractor.extract(packageSpec, options);
|
|
3556
|
+
}
|
|
3557
|
+
|
|
3558
|
+
exports.AIError = AIError;
|
|
3559
|
+
exports.CacheError = CacheError;
|
|
3560
|
+
exports.ConfigError = ConfigError;
|
|
3561
|
+
exports.DownloadError = DownloadError;
|
|
3562
|
+
exports.FileCache = FileCache;
|
|
3563
|
+
exports.NpmLlmsError = NpmLlmsError;
|
|
3564
|
+
exports.PackageNotFoundError = PackageNotFoundError;
|
|
3565
|
+
exports.ParseError = ParseError;
|
|
3566
|
+
exports.PluginError = PluginError;
|
|
3567
|
+
exports.TarError = TarError;
|
|
3568
|
+
exports.TimeoutError = TimeoutError;
|
|
3569
|
+
exports.ValidationError = ValidationError;
|
|
3570
|
+
exports.VersionNotFoundError = VersionNotFoundError;
|
|
3571
|
+
exports.composePlugins = composePlugins;
|
|
3572
|
+
exports.countTokens = countTokens;
|
|
3573
|
+
exports.createCache = createCache;
|
|
3574
|
+
exports.createExtractor = createExtractor;
|
|
3575
|
+
exports.createKernel = createKernel;
|
|
3576
|
+
exports.definePlugin = definePlugin;
|
|
3577
|
+
exports.extract = extract;
|
|
3578
|
+
exports.fetchPackage = fetchPackage;
|
|
3579
|
+
exports.fetchPackageMetadata = fetchPackageMetadata;
|
|
3580
|
+
exports.formatBytes = formatBytes;
|
|
3581
|
+
exports.formatTokenCount = formatTokenCount;
|
|
3582
|
+
exports.getErrorCode = getErrorCode;
|
|
3583
|
+
exports.isNpmLlmsError = isNpmLlmsError;
|
|
3584
|
+
exports.parsePackageSpec = parsePackageSpec;
|
|
3585
|
+
exports.truncateToTokenLimit = truncateToTokenLimit;
|
|
3586
|
+
exports.validatePackageName = validatePackageName;
|
|
3587
|
+
exports.wrapError = wrapError;
|
|
3588
|
+
//# sourceMappingURL=index.cjs.map
|
|
3589
|
+
//# sourceMappingURL=index.cjs.map
|