@swarmvaultai/engine 0.6.7 → 0.7.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/dist/chunk-5Q4IV4O3.js +1336 -0
- package/dist/hooks/claude.js +146 -0
- package/dist/hooks/copilot.js +141 -0
- package/dist/hooks/gemini.js +142 -0
- package/dist/hooks/opencode.js +50 -0
- package/dist/index.d.ts +3 -4
- package/dist/index.js +3329 -742
- package/dist/registry-W6ZFRI73.js +12 -0
- package/package.json +10 -2
package/dist/index.js
CHANGED
|
@@ -22,13 +22,44 @@ import {
|
|
|
22
22
|
uniqueBy,
|
|
23
23
|
writeFileIfChanged,
|
|
24
24
|
writeJsonFile
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-5Q4IV4O3.js";
|
|
26
26
|
|
|
27
27
|
// src/agents.ts
|
|
28
28
|
import crypto from "crypto";
|
|
29
29
|
import fs from "fs/promises";
|
|
30
30
|
import path from "path";
|
|
31
|
+
import { fileURLToPath } from "url";
|
|
31
32
|
import YAML from "yaml";
|
|
33
|
+
function resolveHooksDir() {
|
|
34
|
+
const moduleUrl = import.meta.url;
|
|
35
|
+
const modulePath = fileURLToPath(moduleUrl);
|
|
36
|
+
const moduleDir = path.dirname(modulePath);
|
|
37
|
+
if (moduleDir.endsWith(`${path.sep}dist`)) {
|
|
38
|
+
return path.join(moduleDir, "hooks");
|
|
39
|
+
}
|
|
40
|
+
if (moduleDir.endsWith(`${path.sep}src`)) {
|
|
41
|
+
return path.resolve(moduleDir, "..", "dist", "hooks");
|
|
42
|
+
}
|
|
43
|
+
return path.resolve(moduleDir, "hooks");
|
|
44
|
+
}
|
|
45
|
+
var BUILT_HOOKS_DIR = resolveHooksDir();
|
|
46
|
+
var hookContentCache = /* @__PURE__ */ new Map();
|
|
47
|
+
async function readBuiltHook(hookFile) {
|
|
48
|
+
const cached = hookContentCache.get(hookFile);
|
|
49
|
+
if (cached !== void 0) {
|
|
50
|
+
return cached;
|
|
51
|
+
}
|
|
52
|
+
const hookPath2 = path.join(BUILT_HOOKS_DIR, hookFile);
|
|
53
|
+
try {
|
|
54
|
+
const content = await fs.readFile(hookPath2, "utf8");
|
|
55
|
+
hookContentCache.set(hookFile, content);
|
|
56
|
+
return content;
|
|
57
|
+
} catch (error) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`SwarmVault hook bundle not found at ${hookPath2}. Run 'pnpm --filter @swarmvaultai/engine build' so the hook scripts are emitted to dist/hooks/. Underlying error: ${error instanceof Error ? error.message : String(error)}`
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
32
63
|
var managedStart = "<!-- swarmvault:managed:start -->";
|
|
33
64
|
var managedEnd = "<!-- swarmvault:managed:end -->";
|
|
34
65
|
var legacyManagedStart = "<!-- vault:managed:start -->";
|
|
@@ -188,7 +219,7 @@ async function readJsonWithWarnings(filePath, fallback, label) {
|
|
|
188
219
|
async function installClaudeHook(rootDir) {
|
|
189
220
|
const settingsPath = path.join(rootDir, ".claude", "settings.json");
|
|
190
221
|
const scriptPath = path.join(rootDir, ".claude", "hooks", "swarmvault-graph-first.js");
|
|
191
|
-
await writeOwnedFile(scriptPath,
|
|
222
|
+
await writeOwnedFile(scriptPath, await readBuiltHook("claude.js"), true);
|
|
192
223
|
await ensureDir(path.dirname(settingsPath));
|
|
193
224
|
const { data: settings, warnings } = await readJsonWithWarnings(settingsPath, {}, ".claude/settings.json");
|
|
194
225
|
if (warnings.length > 0 && await fileExists(settingsPath)) {
|
|
@@ -218,361 +249,10 @@ async function installClaudeHook(rootDir) {
|
|
|
218
249
|
`, "utf8");
|
|
219
250
|
return { path: settingsPath, warnings: [] };
|
|
220
251
|
}
|
|
221
|
-
function buildClaudeHookScript() {
|
|
222
|
-
return `#!/usr/bin/env node
|
|
223
|
-
import crypto from "node:crypto";
|
|
224
|
-
import fs from "node:fs/promises";
|
|
225
|
-
import os from "node:os";
|
|
226
|
-
import path from "node:path";
|
|
227
|
-
|
|
228
|
-
${markerStateSnippet("claude").trim()}
|
|
229
|
-
|
|
230
|
-
async function readInput() {
|
|
231
|
-
let body = "";
|
|
232
|
-
for await (const chunk of process.stdin) {
|
|
233
|
-
body += chunk;
|
|
234
|
-
}
|
|
235
|
-
if (!body.trim()) {
|
|
236
|
-
return {};
|
|
237
|
-
}
|
|
238
|
-
try {
|
|
239
|
-
return JSON.parse(body);
|
|
240
|
-
} catch {
|
|
241
|
-
return {};
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
function emit(value) {
|
|
246
|
-
process.stdout.write(\`\${JSON.stringify(value)}\\n\`);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const mode = process.argv[2] ?? "";
|
|
250
|
-
const input = await readInput();
|
|
251
|
-
const cwd = resolveInputCwd(input);
|
|
252
|
-
const reportNote = "SwarmVault graph report exists at wiki/graph/report.md. Read it before broad grep/glob searching.";
|
|
253
|
-
|
|
254
|
-
if (!(await hasReport(cwd))) {
|
|
255
|
-
emit({});
|
|
256
|
-
process.exit(0);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
if (mode === "session-start") {
|
|
260
|
-
await resetSession(cwd);
|
|
261
|
-
emit({
|
|
262
|
-
hookSpecificOutput: {
|
|
263
|
-
hookEventName: "SessionStart",
|
|
264
|
-
additionalContext: reportNote
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
process.exit(0);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const toolName = resolveToolName(input);
|
|
271
|
-
if (collectCandidatePaths(input).some((value) => isReportPath(value, cwd))) {
|
|
272
|
-
await markReportRead(cwd);
|
|
273
|
-
emit({});
|
|
274
|
-
process.exit(0);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
if (isBroadSearchTool(toolName) && !(await hasSeenReport(cwd))) {
|
|
278
|
-
emit({
|
|
279
|
-
hookSpecificOutput: {
|
|
280
|
-
hookEventName: "PreToolUse",
|
|
281
|
-
additionalContext: reportNote
|
|
282
|
-
}
|
|
283
|
-
});
|
|
284
|
-
process.exit(0);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
emit({});
|
|
288
|
-
`;
|
|
289
|
-
}
|
|
290
|
-
function markerStateSnippet(agentKey) {
|
|
291
|
-
return `
|
|
292
|
-
function markerState(cwd) {
|
|
293
|
-
const hash = crypto.createHash("sha256").update(cwd).digest("hex");
|
|
294
|
-
const dir = path.join(os.tmpdir(), "swarmvault-agent-hooks", "${agentKey}", hash);
|
|
295
|
-
return {
|
|
296
|
-
dir,
|
|
297
|
-
markerPath: path.join(dir, "report-read")
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
function isReportPath(value, cwd) {
|
|
302
|
-
if (typeof value !== "string" || value.length === 0) {
|
|
303
|
-
return false;
|
|
304
|
-
}
|
|
305
|
-
const reportSuffix = path.join("wiki", "graph", "report.md");
|
|
306
|
-
const normalized = value.replaceAll("\\\\", "/");
|
|
307
|
-
const reportNormalized = reportSuffix.replaceAll("\\\\", "/");
|
|
308
|
-
if (normalized.endsWith(reportNormalized)) {
|
|
309
|
-
return true;
|
|
310
|
-
}
|
|
311
|
-
return path.resolve(cwd, value) === path.resolve(cwd, reportSuffix);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
function collectCandidatePaths(node, acc = []) {
|
|
315
|
-
if (typeof node === "string") {
|
|
316
|
-
acc.push(node);
|
|
317
|
-
return acc;
|
|
318
|
-
}
|
|
319
|
-
if (!node || typeof node !== "object") {
|
|
320
|
-
return acc;
|
|
321
|
-
}
|
|
322
|
-
if (Array.isArray(node)) {
|
|
323
|
-
for (const item of node) {
|
|
324
|
-
collectCandidatePaths(item, acc);
|
|
325
|
-
}
|
|
326
|
-
return acc;
|
|
327
|
-
}
|
|
328
|
-
for (const [key, value] of Object.entries(node)) {
|
|
329
|
-
if (["path", "filePath", "file_path", "paths", "target", "targets"].includes(key)) {
|
|
330
|
-
collectCandidatePaths(value, acc);
|
|
331
|
-
continue;
|
|
332
|
-
}
|
|
333
|
-
collectCandidatePaths(value, acc);
|
|
334
|
-
}
|
|
335
|
-
return acc;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
function resolveInputCwd(input) {
|
|
339
|
-
return path.resolve(
|
|
340
|
-
input?.cwd ??
|
|
341
|
-
input?.directory ??
|
|
342
|
-
input?.workspace?.cwd ??
|
|
343
|
-
input?.toolInput?.cwd ??
|
|
344
|
-
process.cwd()
|
|
345
|
-
);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
function resolveToolName(input) {
|
|
349
|
-
return String(input?.toolName ?? input?.tool_name ?? input?.tool?.name ?? input?.name ?? "");
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
async function hasReport(cwd) {
|
|
353
|
-
try {
|
|
354
|
-
await fs.access(path.join(cwd, "wiki", "graph", "report.md"));
|
|
355
|
-
return true;
|
|
356
|
-
} catch {
|
|
357
|
-
return false;
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
async function markReportRead(cwd) {
|
|
362
|
-
const state = markerState(cwd);
|
|
363
|
-
await fs.mkdir(state.dir, { recursive: true });
|
|
364
|
-
await fs.writeFile(state.markerPath, "seen\\n", "utf8");
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
async function hasSeenReport(cwd) {
|
|
368
|
-
const state = markerState(cwd);
|
|
369
|
-
try {
|
|
370
|
-
await fs.access(state.markerPath);
|
|
371
|
-
return true;
|
|
372
|
-
} catch {
|
|
373
|
-
return false;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
async function resetSession(cwd) {
|
|
378
|
-
const state = markerState(cwd);
|
|
379
|
-
await fs.rm(state.dir, { recursive: true, force: true });
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
function isBroadSearchTool(toolName) {
|
|
383
|
-
return /grep|glob|search|find/i.test(toolName);
|
|
384
|
-
}
|
|
385
|
-
`;
|
|
386
|
-
}
|
|
387
|
-
function buildGeminiHookScript() {
|
|
388
|
-
return `#!/usr/bin/env node
|
|
389
|
-
import crypto from "node:crypto";
|
|
390
|
-
import fs from "node:fs/promises";
|
|
391
|
-
import os from "node:os";
|
|
392
|
-
import path from "node:path";
|
|
393
|
-
|
|
394
|
-
${markerStateSnippet("gemini").trim()}
|
|
395
|
-
|
|
396
|
-
async function readInput() {
|
|
397
|
-
let body = "";
|
|
398
|
-
for await (const chunk of process.stdin) {
|
|
399
|
-
body += chunk;
|
|
400
|
-
}
|
|
401
|
-
if (!body.trim()) {
|
|
402
|
-
return {};
|
|
403
|
-
}
|
|
404
|
-
try {
|
|
405
|
-
return JSON.parse(body);
|
|
406
|
-
} catch {
|
|
407
|
-
return {};
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
function emit(value) {
|
|
412
|
-
process.stdout.write(\`\${JSON.stringify(value)}\\n\`);
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
const mode = process.argv[2] ?? "";
|
|
416
|
-
const input = await readInput();
|
|
417
|
-
const cwd = resolveInputCwd(input);
|
|
418
|
-
const reportNote = "SwarmVault graph report exists at wiki/graph/report.md. Read it before broad grep/glob searching.";
|
|
419
|
-
|
|
420
|
-
if (!(await hasReport(cwd))) {
|
|
421
|
-
emit({});
|
|
422
|
-
process.exit(0);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
if (mode === "session-start") {
|
|
426
|
-
await resetSession(cwd);
|
|
427
|
-
emit({
|
|
428
|
-
systemMessage: reportNote,
|
|
429
|
-
hookSpecificOutput: {
|
|
430
|
-
hookEventName: "SessionStart",
|
|
431
|
-
additionalContext: "SwarmVault graph report: wiki/graph/report.md"
|
|
432
|
-
}
|
|
433
|
-
});
|
|
434
|
-
process.exit(0);
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
const toolName = resolveToolName(input);
|
|
438
|
-
if (collectCandidatePaths(input).some((value) => isReportPath(value, cwd))) {
|
|
439
|
-
await markReportRead(cwd);
|
|
440
|
-
emit({});
|
|
441
|
-
process.exit(0);
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
if (isBroadSearchTool(toolName) && !(await hasSeenReport(cwd))) {
|
|
445
|
-
emit({ systemMessage: reportNote });
|
|
446
|
-
process.exit(0);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
emit({});
|
|
450
|
-
`;
|
|
451
|
-
}
|
|
452
|
-
function buildCopilotHookScript() {
|
|
453
|
-
return `#!/usr/bin/env node
|
|
454
|
-
import crypto from "node:crypto";
|
|
455
|
-
import fs from "node:fs/promises";
|
|
456
|
-
import os from "node:os";
|
|
457
|
-
import path from "node:path";
|
|
458
|
-
|
|
459
|
-
${markerStateSnippet("copilot").trim()}
|
|
460
|
-
|
|
461
|
-
async function readInput() {
|
|
462
|
-
let body = "";
|
|
463
|
-
for await (const chunk of process.stdin) {
|
|
464
|
-
body += chunk;
|
|
465
|
-
}
|
|
466
|
-
if (!body.trim()) {
|
|
467
|
-
return {};
|
|
468
|
-
}
|
|
469
|
-
try {
|
|
470
|
-
return JSON.parse(body);
|
|
471
|
-
} catch {
|
|
472
|
-
return {};
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
function emit(value) {
|
|
477
|
-
if (value !== undefined) {
|
|
478
|
-
process.stdout.write(\`\${JSON.stringify(value)}\\n\`);
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
const mode = process.argv[2] ?? "";
|
|
483
|
-
const input = await readInput();
|
|
484
|
-
const cwd = resolveInputCwd(input);
|
|
485
|
-
const reportNote = "SwarmVault graph report exists at wiki/graph/report.md. Read it before broad grep/glob searching.";
|
|
486
|
-
|
|
487
|
-
if (!(await hasReport(cwd))) {
|
|
488
|
-
emit({});
|
|
489
|
-
process.exit(0);
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
if (mode === "session-start") {
|
|
493
|
-
await resetSession(cwd);
|
|
494
|
-
emit({});
|
|
495
|
-
process.exit(0);
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
const toolName = resolveToolName(input);
|
|
499
|
-
if (collectCandidatePaths(input).some((value) => isReportPath(value, cwd))) {
|
|
500
|
-
await markReportRead(cwd);
|
|
501
|
-
emit({});
|
|
502
|
-
process.exit(0);
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
if (isBroadSearchTool(toolName) && !(await hasSeenReport(cwd))) {
|
|
506
|
-
emit({
|
|
507
|
-
permissionDecision: "deny",
|
|
508
|
-
permissionDecisionReason: reportNote
|
|
509
|
-
});
|
|
510
|
-
process.exit(0);
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
emit({});
|
|
514
|
-
`;
|
|
515
|
-
}
|
|
516
|
-
function buildOpenCodePlugin() {
|
|
517
|
-
return `import path from "node:path";
|
|
518
|
-
|
|
519
|
-
const reportRelativePath = path.join("wiki", "graph", "report.md");
|
|
520
|
-
|
|
521
|
-
export const name = "swarmvault-graph-first";
|
|
522
|
-
|
|
523
|
-
export default async function swarmvaultGraphFirst({ client }) {
|
|
524
|
-
let reportSeen = false;
|
|
525
|
-
|
|
526
|
-
async function hasReport(cwd) {
|
|
527
|
-
try {
|
|
528
|
-
await Bun.file(path.join(cwd, reportRelativePath)).arrayBuffer();
|
|
529
|
-
return true;
|
|
530
|
-
} catch {
|
|
531
|
-
return false;
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
async function note(message) {
|
|
536
|
-
if (client?.app?.log) {
|
|
537
|
-
await client.app.log({
|
|
538
|
-
level: "info",
|
|
539
|
-
message
|
|
540
|
-
});
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
return {
|
|
545
|
-
async "session.created"(input) {
|
|
546
|
-
reportSeen = false;
|
|
547
|
-
const cwd = input?.session?.cwd ?? process.cwd();
|
|
548
|
-
if (await hasReport(cwd)) {
|
|
549
|
-
await note("SwarmVault graph report exists. Read wiki/graph/report.md before broad workspace searching.");
|
|
550
|
-
}
|
|
551
|
-
},
|
|
552
|
-
async "tool.execute.before"(input) {
|
|
553
|
-
const cwd = input?.session?.cwd ?? process.cwd();
|
|
554
|
-
if (!(await hasReport(cwd))) {
|
|
555
|
-
return;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
const argsText = JSON.stringify(input?.args ?? {});
|
|
559
|
-
if (argsText.includes("wiki/graph/report.md")) {
|
|
560
|
-
reportSeen = true;
|
|
561
|
-
return;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
if (!reportSeen && ["glob", "grep"].includes(String(input?.tool ?? ""))) {
|
|
565
|
-
await note("SwarmVault graph report exists. Read wiki/graph/report.md before broad workspace searching.");
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
};
|
|
569
|
-
}
|
|
570
|
-
`;
|
|
571
|
-
}
|
|
572
252
|
async function installGeminiHook(rootDir) {
|
|
573
253
|
const settingsPath = path.join(rootDir, ".gemini", "settings.json");
|
|
574
254
|
const scriptPath = path.join(rootDir, ".gemini", "hooks", "swarmvault-graph-first.js");
|
|
575
|
-
await writeOwnedFile(scriptPath,
|
|
255
|
+
await writeOwnedFile(scriptPath, await readBuiltHook("gemini.js"), true);
|
|
576
256
|
const { data: settings, warnings } = await readJsonWithWarnings(settingsPath, {}, ".gemini/settings.json");
|
|
577
257
|
if (warnings.length > 0 && await fileExists(settingsPath)) {
|
|
578
258
|
return { paths: [settingsPath, scriptPath], warnings };
|
|
@@ -639,7 +319,7 @@ async function installCopilotHook(rootDir) {
|
|
|
639
319
|
const hooksDir = path.join(rootDir, ".github", "hooks");
|
|
640
320
|
const scriptPath = path.join(hooksDir, "swarmvault-graph-first.js");
|
|
641
321
|
const configPath = path.join(hooksDir, "swarmvault-graph-first.json");
|
|
642
|
-
await writeOwnedFile(scriptPath,
|
|
322
|
+
await writeOwnedFile(scriptPath, await readBuiltHook("copilot.js"), true);
|
|
643
323
|
const config = {
|
|
644
324
|
version: copilotHookVersion,
|
|
645
325
|
hooks: {
|
|
@@ -670,7 +350,7 @@ async function installCopilotHook(rootDir) {
|
|
|
670
350
|
}
|
|
671
351
|
async function installOpenCodeHook(rootDir) {
|
|
672
352
|
const pluginPath = path.join(rootDir, ".opencode", "plugins", "swarmvault-graph-first.js");
|
|
673
|
-
await writeOwnedFile(pluginPath,
|
|
353
|
+
await writeOwnedFile(pluginPath, await readBuiltHook("opencode.js"));
|
|
674
354
|
return { paths: [pluginPath], warnings: [] };
|
|
675
355
|
}
|
|
676
356
|
function stableKeyForAgent(rootDir, agent) {
|
|
@@ -1376,7 +1056,6 @@ function buildBenchmarkArtifact(input) {
|
|
|
1376
1056
|
reductionRatio,
|
|
1377
1057
|
sampleQuestions: input.questions,
|
|
1378
1058
|
perQuestion,
|
|
1379
|
-
questionResults: perQuestion,
|
|
1380
1059
|
summary
|
|
1381
1060
|
};
|
|
1382
1061
|
}
|
|
@@ -1755,6 +1434,7 @@ import path5 from "path";
|
|
|
1755
1434
|
var require2 = createRequire(import.meta.url);
|
|
1756
1435
|
var TREE_SITTER_RUNTIME_PACKAGE = "@vscode/tree-sitter-wasm";
|
|
1757
1436
|
var TREE_SITTER_EXTRA_GRAMMARS_PACKAGE = "tree-sitter-wasms";
|
|
1437
|
+
var SWIFT_TREE_SITTER_OPT_IN_ENV = "SWARMVAULT_ENABLE_SWIFT_TREE_SITTER";
|
|
1758
1438
|
var packageRootCache = /* @__PURE__ */ new Map();
|
|
1759
1439
|
var RATIONALE_MARKERS = ["NOTE:", "IMPORTANT:", "HACK:", "WHY:", "RATIONALE:"];
|
|
1760
1440
|
function stripKnownCommentPrefix(line) {
|
|
@@ -1785,7 +1465,16 @@ var grammarAssetByLanguage = {
|
|
|
1785
1465
|
cpp: { packageName: TREE_SITTER_RUNTIME_PACKAGE, relativePath: "wasm/tree-sitter-cpp.wasm" },
|
|
1786
1466
|
php: { packageName: TREE_SITTER_RUNTIME_PACKAGE, relativePath: "wasm/tree-sitter-php.wasm" },
|
|
1787
1467
|
ruby: { packageName: TREE_SITTER_RUNTIME_PACKAGE, relativePath: "wasm/tree-sitter-ruby.wasm" },
|
|
1788
|
-
powershell: { packageName: TREE_SITTER_RUNTIME_PACKAGE, relativePath: "wasm/tree-sitter-powershell.wasm" }
|
|
1468
|
+
powershell: { packageName: TREE_SITTER_RUNTIME_PACKAGE, relativePath: "wasm/tree-sitter-powershell.wasm" },
|
|
1469
|
+
swift: { packageName: TREE_SITTER_EXTRA_GRAMMARS_PACKAGE, relativePath: "out/tree-sitter-swift.wasm" },
|
|
1470
|
+
elixir: { packageName: TREE_SITTER_EXTRA_GRAMMARS_PACKAGE, relativePath: "out/tree-sitter-elixir.wasm" },
|
|
1471
|
+
ocaml: { packageName: TREE_SITTER_EXTRA_GRAMMARS_PACKAGE, relativePath: "out/tree-sitter-ocaml.wasm" },
|
|
1472
|
+
objc: { packageName: TREE_SITTER_EXTRA_GRAMMARS_PACKAGE, relativePath: "out/tree-sitter-objc.wasm" },
|
|
1473
|
+
rescript: { packageName: TREE_SITTER_EXTRA_GRAMMARS_PACKAGE, relativePath: "out/tree-sitter-rescript.wasm" },
|
|
1474
|
+
solidity: { packageName: TREE_SITTER_EXTRA_GRAMMARS_PACKAGE, relativePath: "out/tree-sitter-solidity.wasm" },
|
|
1475
|
+
html: { packageName: TREE_SITTER_EXTRA_GRAMMARS_PACKAGE, relativePath: "out/tree-sitter-html.wasm" },
|
|
1476
|
+
css: { packageName: TREE_SITTER_EXTRA_GRAMMARS_PACKAGE, relativePath: "out/tree-sitter-css.wasm" },
|
|
1477
|
+
vue: { packageName: TREE_SITTER_EXTRA_GRAMMARS_PACKAGE, relativePath: "out/tree-sitter-vue.wasm" }
|
|
1789
1478
|
};
|
|
1790
1479
|
function resolvePackageRoot(packageName) {
|
|
1791
1480
|
const cached = packageRootCache.get(packageName);
|
|
@@ -1845,7 +1534,7 @@ function normalizeSymbolReference(value) {
|
|
|
1845
1534
|
}
|
|
1846
1535
|
function stripCodeExtension(filePath) {
|
|
1847
1536
|
return filePath.replace(
|
|
1848
|
-
/\.(?:[cm]?jsx?|tsx?|mts|cts|sh|bash|zsh|py|go|rs|java|kt|kts|scala|sc|dart|lua|zig|cs|php|c|cc|cpp|cxx|h|hh|hpp|hxx)$/i,
|
|
1537
|
+
/\.(?:[cm]?jsx?|tsx?|mts|cts|sh|bash|zsh|py|go|rs|java|kt|kts|scala|sc|dart|lua|zig|cs|php|c|cc|cpp|cxx|h|hh|hpp|hxx|swift|exs?|mli?|mm|resi?|sol|html?|css|vue)$/i,
|
|
1849
1538
|
""
|
|
1850
1539
|
);
|
|
1851
1540
|
}
|
|
@@ -2133,6 +1822,72 @@ function descendantTypeNames(node) {
|
|
|
2133
1822
|
function quotedPath(value) {
|
|
2134
1823
|
return value.replace(/^['"<]+|['">]+$/g, "").trim();
|
|
2135
1824
|
}
|
|
1825
|
+
function neutralizePreprocessorDirectives(content) {
|
|
1826
|
+
const lines = content.split("\n");
|
|
1827
|
+
const active = [];
|
|
1828
|
+
const isActive = () => active.every(Boolean);
|
|
1829
|
+
const directiveHead = (line) => {
|
|
1830
|
+
const trimmed = line.trimStart();
|
|
1831
|
+
if (trimmed[0] !== "#") {
|
|
1832
|
+
return void 0;
|
|
1833
|
+
}
|
|
1834
|
+
const rest = trimmed.slice(1).trimStart();
|
|
1835
|
+
const match = rest.match(/^([A-Za-z]+)/);
|
|
1836
|
+
return match?.[1]?.toLowerCase();
|
|
1837
|
+
};
|
|
1838
|
+
const out = [];
|
|
1839
|
+
for (const line of lines) {
|
|
1840
|
+
const head = directiveHead(line);
|
|
1841
|
+
if (head === "if" || head === "ifdef" || head === "ifndef") {
|
|
1842
|
+
active.push(isActive());
|
|
1843
|
+
out.push("");
|
|
1844
|
+
continue;
|
|
1845
|
+
}
|
|
1846
|
+
if (head === "elif") {
|
|
1847
|
+
if (active.length > 0) {
|
|
1848
|
+
active[active.length - 1] = false;
|
|
1849
|
+
}
|
|
1850
|
+
out.push("");
|
|
1851
|
+
continue;
|
|
1852
|
+
}
|
|
1853
|
+
if (head === "else") {
|
|
1854
|
+
if (active.length > 0) {
|
|
1855
|
+
active[active.length - 1] = false;
|
|
1856
|
+
}
|
|
1857
|
+
out.push("");
|
|
1858
|
+
continue;
|
|
1859
|
+
}
|
|
1860
|
+
if (head === "endif") {
|
|
1861
|
+
if (active.length > 0) {
|
|
1862
|
+
active.pop();
|
|
1863
|
+
}
|
|
1864
|
+
out.push("");
|
|
1865
|
+
continue;
|
|
1866
|
+
}
|
|
1867
|
+
if (!isActive()) {
|
|
1868
|
+
out.push("");
|
|
1869
|
+
continue;
|
|
1870
|
+
}
|
|
1871
|
+
out.push(line);
|
|
1872
|
+
}
|
|
1873
|
+
return out.join("\n");
|
|
1874
|
+
}
|
|
1875
|
+
function detectShellDialect(content) {
|
|
1876
|
+
const prefix = content.slice(0, 4096);
|
|
1877
|
+
if (/^#!\s*(?:\/usr\/bin\/env\s+)?zsh\b/m.test(prefix)) {
|
|
1878
|
+
return "zsh";
|
|
1879
|
+
}
|
|
1880
|
+
if (/^\s*#compdef\b/m.test(prefix)) {
|
|
1881
|
+
return "zsh";
|
|
1882
|
+
}
|
|
1883
|
+
if (/\$\{\([fFsq@%]/.test(prefix)) {
|
|
1884
|
+
return "zsh";
|
|
1885
|
+
}
|
|
1886
|
+
if (/\b(?:setopt|unsetopt|zmodload|compinit|autoload\s+-Uz)\b/.test(prefix)) {
|
|
1887
|
+
return "zsh";
|
|
1888
|
+
}
|
|
1889
|
+
return "bash";
|
|
1890
|
+
}
|
|
2136
1891
|
function diagnosticsFromTree(rootNode) {
|
|
2137
1892
|
if (!rootNode.hasError) {
|
|
2138
1893
|
return [];
|
|
@@ -2182,104 +1937,443 @@ function treeSitterCompatibilityDiagnostic(language, error) {
|
|
|
2182
1937
|
column: 1
|
|
2183
1938
|
};
|
|
2184
1939
|
}
|
|
2185
|
-
function
|
|
2186
|
-
|
|
2187
|
-
if (!match) {
|
|
2188
|
-
return [];
|
|
2189
|
-
}
|
|
2190
|
-
return match[1].split(",").map((item) => item.trim()).filter(Boolean).map((item) => {
|
|
2191
|
-
const [specifier, alias] = item.split(/\s+as\s+/i);
|
|
2192
|
-
return {
|
|
2193
|
-
specifier: specifier.trim(),
|
|
2194
|
-
importedSymbols: [],
|
|
2195
|
-
namespaceImport: alias?.trim(),
|
|
2196
|
-
isExternal: !specifier.trim().startsWith("."),
|
|
2197
|
-
reExport: false
|
|
2198
|
-
};
|
|
2199
|
-
});
|
|
2200
|
-
}
|
|
2201
|
-
function parsePythonFromImportStatement(text) {
|
|
2202
|
-
const match = text.trim().match(/^from\s+([.\w]+)\s+import\s+(.+)$/);
|
|
2203
|
-
if (!match) {
|
|
2204
|
-
return [];
|
|
2205
|
-
}
|
|
2206
|
-
return [
|
|
2207
|
-
{
|
|
2208
|
-
specifier: match[1],
|
|
2209
|
-
importedSymbols: match[2].split(",").map((item) => item.trim()).filter(Boolean),
|
|
2210
|
-
isExternal: !match[1].startsWith("."),
|
|
2211
|
-
reExport: false
|
|
2212
|
-
}
|
|
2213
|
-
];
|
|
2214
|
-
}
|
|
2215
|
-
function parseGoImport(text) {
|
|
2216
|
-
const match = text.trim().match(/^(?:([._A-Za-z]\w*)\s+)?"([^"]+)"$/);
|
|
2217
|
-
if (!match) {
|
|
2218
|
-
return void 0;
|
|
2219
|
-
}
|
|
2220
|
-
return {
|
|
2221
|
-
specifier: match[2],
|
|
2222
|
-
importedSymbols: [],
|
|
2223
|
-
namespaceImport: match[1] && ![".", "_"].includes(match[1]) ? match[1] : void 0,
|
|
2224
|
-
isExternal: !match[2].startsWith("."),
|
|
2225
|
-
reExport: false
|
|
2226
|
-
};
|
|
1940
|
+
function swiftTreeSitterEnabled() {
|
|
1941
|
+
return process.env[SWIFT_TREE_SITTER_OPT_IN_ENV] === "1";
|
|
2227
1942
|
}
|
|
2228
|
-
function
|
|
2229
|
-
const cleaned = text.replace(/^pub\s+/, "").replace(/^use\s+/, "").replace(/;$/, "").trim();
|
|
2230
|
-
const aliasMatch = cleaned.match(/\s+as\s+([A-Za-z_]\w*)$/);
|
|
2231
|
-
const withoutAlias = aliasMatch ? cleaned.slice(0, aliasMatch.index).trim() : cleaned;
|
|
2232
|
-
const braceMatch = withoutAlias.match(/^(.*)::\{(.+)\}$/);
|
|
2233
|
-
const importedSymbols = braceMatch ? braceMatch[2].split(",").map((item) => item.trim()).filter(Boolean) : [aliasMatch ? `${normalizeSymbolReference(withoutAlias)} as ${aliasMatch[1]}` : normalizeSymbolReference(withoutAlias)].filter(
|
|
2234
|
-
Boolean
|
|
2235
|
-
);
|
|
2236
|
-
const specifier = braceMatch ? braceMatch[1].trim() : withoutAlias;
|
|
1943
|
+
function swiftTreeSitterDisabledDiagnostic() {
|
|
2237
1944
|
return {
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
1945
|
+
code: 9012,
|
|
1946
|
+
category: "warning",
|
|
1947
|
+
message: `Swift parser-backed analysis is disabled by default because the packaged tree-sitter grammar can trigger Node/V8 out-of-memory crashes during WASM compilation. Set ${SWIFT_TREE_SITTER_OPT_IN_ENV}=1 to opt in anyway.`,
|
|
1948
|
+
line: 1,
|
|
1949
|
+
column: 1
|
|
2242
1950
|
};
|
|
2243
1951
|
}
|
|
2244
|
-
function
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
importedSymbols: symbolName ? [symbolName] : [],
|
|
2250
|
-
isExternal: true,
|
|
2251
|
-
reExport: false
|
|
2252
|
-
};
|
|
1952
|
+
function flattenPythonDottedName(node) {
|
|
1953
|
+
if (!node) {
|
|
1954
|
+
return "";
|
|
1955
|
+
}
|
|
1956
|
+
return node.namedChildren.filter((child) => child?.type === "identifier").map((child) => child.text.trim()).filter(Boolean).join(".");
|
|
2253
1957
|
}
|
|
2254
|
-
function
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
return void 0;
|
|
1958
|
+
function flattenPythonRelativeImport(node) {
|
|
1959
|
+
if (!node) {
|
|
1960
|
+
return "";
|
|
2258
1961
|
}
|
|
2259
|
-
const
|
|
2260
|
-
const
|
|
2261
|
-
|
|
2262
|
-
|
|
1962
|
+
const prefixNode = node.namedChildren.find((child) => child?.type === "import_prefix") ?? null;
|
|
1963
|
+
const prefix = prefixNode ? prefixNode.text.trim() : "";
|
|
1964
|
+
const moduleNode = node.namedChildren.find((child) => child?.type === "dotted_name") ?? null;
|
|
1965
|
+
const module = flattenPythonDottedName(moduleNode);
|
|
1966
|
+
return prefix + module;
|
|
1967
|
+
}
|
|
1968
|
+
function parsePythonImportStatement(node) {
|
|
1969
|
+
const imports = [];
|
|
1970
|
+
for (const child of node.namedChildren) {
|
|
1971
|
+
if (!child) {
|
|
1972
|
+
continue;
|
|
1973
|
+
}
|
|
1974
|
+
if (child.type === "dotted_name") {
|
|
1975
|
+
const specifier = flattenPythonDottedName(child);
|
|
1976
|
+
if (!specifier) {
|
|
1977
|
+
continue;
|
|
1978
|
+
}
|
|
1979
|
+
imports.push({
|
|
1980
|
+
specifier,
|
|
1981
|
+
importedSymbols: [],
|
|
1982
|
+
isExternal: !specifier.startsWith("."),
|
|
1983
|
+
reExport: false
|
|
1984
|
+
});
|
|
1985
|
+
} else if (child.type === "aliased_import") {
|
|
1986
|
+
const moduleNode = child.namedChildren.find((inner) => inner?.type === "dotted_name") ?? null;
|
|
1987
|
+
const aliasNode = child.namedChildren.find((inner) => inner?.type === "identifier") ?? null;
|
|
1988
|
+
const specifier = flattenPythonDottedName(moduleNode);
|
|
1989
|
+
if (!specifier) {
|
|
1990
|
+
continue;
|
|
1991
|
+
}
|
|
1992
|
+
imports.push({
|
|
1993
|
+
specifier,
|
|
1994
|
+
importedSymbols: [],
|
|
1995
|
+
namespaceImport: aliasNode?.text.trim(),
|
|
1996
|
+
isExternal: !specifier.startsWith("."),
|
|
1997
|
+
reExport: false
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2263
2000
|
}
|
|
2264
|
-
return
|
|
2265
|
-
specifier,
|
|
2266
|
-
importedSymbols: [],
|
|
2267
|
-
namespaceImport: aliasMatch?.[2],
|
|
2268
|
-
isExternal: !specifier.startsWith("."),
|
|
2269
|
-
reExport: false
|
|
2270
|
-
};
|
|
2001
|
+
return imports;
|
|
2271
2002
|
}
|
|
2272
|
-
function
|
|
2273
|
-
const
|
|
2274
|
-
if (
|
|
2003
|
+
function parsePythonFromImportStatement(node) {
|
|
2004
|
+
const children = node.namedChildren.filter((child) => child !== null);
|
|
2005
|
+
if (children.length === 0) {
|
|
2275
2006
|
return [];
|
|
2276
2007
|
}
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2008
|
+
const [moduleNode, ...rest] = children;
|
|
2009
|
+
if (!moduleNode) {
|
|
2010
|
+
return [];
|
|
2011
|
+
}
|
|
2012
|
+
let specifier;
|
|
2013
|
+
if (moduleNode.type === "relative_import") {
|
|
2014
|
+
specifier = flattenPythonRelativeImport(moduleNode);
|
|
2015
|
+
} else if (moduleNode.type === "dotted_name") {
|
|
2016
|
+
specifier = flattenPythonDottedName(moduleNode);
|
|
2017
|
+
} else {
|
|
2018
|
+
return [];
|
|
2019
|
+
}
|
|
2020
|
+
if (!specifier) {
|
|
2021
|
+
return [];
|
|
2022
|
+
}
|
|
2023
|
+
const symbols = [];
|
|
2024
|
+
let hasWildcard = false;
|
|
2025
|
+
for (const entry of rest) {
|
|
2026
|
+
if (entry.type === "wildcard_import") {
|
|
2027
|
+
hasWildcard = true;
|
|
2028
|
+
continue;
|
|
2029
|
+
}
|
|
2030
|
+
if (entry.type === "dotted_name") {
|
|
2031
|
+
const name = flattenPythonDottedName(entry);
|
|
2032
|
+
if (name) {
|
|
2033
|
+
symbols.push(name);
|
|
2034
|
+
}
|
|
2035
|
+
continue;
|
|
2036
|
+
}
|
|
2037
|
+
if (entry.type === "aliased_import") {
|
|
2038
|
+
const moduleChild = entry.namedChildren.find((inner) => inner?.type === "dotted_name") ?? null;
|
|
2039
|
+
const aliasChild = entry.namedChildren.find((inner) => inner?.type === "identifier") ?? null;
|
|
2040
|
+
const baseName = flattenPythonDottedName(moduleChild);
|
|
2041
|
+
const aliasName = aliasChild?.text.trim();
|
|
2042
|
+
if (baseName) {
|
|
2043
|
+
symbols.push(aliasName ? `${baseName} as ${aliasName}` : baseName);
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
if (hasWildcard) {
|
|
2048
|
+
symbols.push("*");
|
|
2049
|
+
}
|
|
2050
|
+
return [
|
|
2051
|
+
{
|
|
2052
|
+
specifier,
|
|
2053
|
+
importedSymbols: symbols,
|
|
2054
|
+
isExternal: !specifier.startsWith("."),
|
|
2055
|
+
reExport: false
|
|
2056
|
+
}
|
|
2057
|
+
];
|
|
2058
|
+
}
|
|
2059
|
+
function parseGoImport(spec) {
|
|
2060
|
+
let alias;
|
|
2061
|
+
let dotImport = false;
|
|
2062
|
+
let blankImport = false;
|
|
2063
|
+
let specifier;
|
|
2064
|
+
for (const child of spec.namedChildren) {
|
|
2065
|
+
if (!child) {
|
|
2066
|
+
continue;
|
|
2067
|
+
}
|
|
2068
|
+
switch (child.type) {
|
|
2069
|
+
case "package_identifier":
|
|
2070
|
+
alias = child.text.trim();
|
|
2071
|
+
break;
|
|
2072
|
+
case "dot":
|
|
2073
|
+
dotImport = true;
|
|
2074
|
+
break;
|
|
2075
|
+
case "blank_identifier":
|
|
2076
|
+
blankImport = true;
|
|
2077
|
+
break;
|
|
2078
|
+
case "interpreted_string_literal":
|
|
2079
|
+
case "raw_string_literal": {
|
|
2080
|
+
const content = child.namedChildren.find(
|
|
2081
|
+
(inner) => inner?.type === "interpreted_string_literal_content" || inner?.type === "raw_string_literal_content"
|
|
2082
|
+
) ?? null;
|
|
2083
|
+
specifier = content ? content.text : child.text.replace(/^[`"]|[`"]$/g, "");
|
|
2084
|
+
break;
|
|
2085
|
+
}
|
|
2086
|
+
default:
|
|
2087
|
+
break;
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
if (!specifier) {
|
|
2091
|
+
return void 0;
|
|
2092
|
+
}
|
|
2093
|
+
return {
|
|
2094
|
+
specifier,
|
|
2095
|
+
importedSymbols: [],
|
|
2096
|
+
namespaceImport: !dotImport && !blankImport ? alias : void 0,
|
|
2097
|
+
isExternal: !specifier.startsWith("."),
|
|
2098
|
+
reExport: false
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2101
|
+
function flattenRustPath(node) {
|
|
2102
|
+
if (!node) {
|
|
2103
|
+
return [];
|
|
2104
|
+
}
|
|
2105
|
+
if (node.type === "crate" || node.type === "self" || node.type === "super") {
|
|
2106
|
+
return [node.type];
|
|
2107
|
+
}
|
|
2108
|
+
if (node.type === "identifier") {
|
|
2109
|
+
return [node.text.trim()].filter(Boolean);
|
|
2110
|
+
}
|
|
2111
|
+
if (node.type === "scoped_identifier") {
|
|
2112
|
+
const segments = [];
|
|
2113
|
+
for (const child of node.namedChildren) {
|
|
2114
|
+
if (!child) {
|
|
2115
|
+
continue;
|
|
2116
|
+
}
|
|
2117
|
+
segments.push(...flattenRustPath(child));
|
|
2118
|
+
}
|
|
2119
|
+
return segments;
|
|
2120
|
+
}
|
|
2121
|
+
return node.namedChildren.filter((child) => child !== null).flatMap((child) => flattenRustPath(child));
|
|
2122
|
+
}
|
|
2123
|
+
function collectRustUseLeaves(node, prefix, leaves) {
|
|
2124
|
+
if (!node) {
|
|
2125
|
+
return;
|
|
2126
|
+
}
|
|
2127
|
+
switch (node.type) {
|
|
2128
|
+
case "scoped_identifier": {
|
|
2129
|
+
const segments = flattenRustPath(node);
|
|
2130
|
+
if (segments.length === 0) {
|
|
2131
|
+
return;
|
|
2132
|
+
}
|
|
2133
|
+
leaves.push({
|
|
2134
|
+
segments: [...prefix, ...segments],
|
|
2135
|
+
symbol: segments[segments.length - 1] ?? null,
|
|
2136
|
+
wildcard: false
|
|
2137
|
+
});
|
|
2138
|
+
return;
|
|
2139
|
+
}
|
|
2140
|
+
case "identifier":
|
|
2141
|
+
case "crate":
|
|
2142
|
+
case "self":
|
|
2143
|
+
case "super": {
|
|
2144
|
+
const combined = [...prefix];
|
|
2145
|
+
if (node.type === "self" && prefix.length > 0) {
|
|
2146
|
+
leaves.push({ segments: combined, symbol: null, wildcard: false });
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2149
|
+
combined.push(node.type === "identifier" ? node.text.trim() : node.type);
|
|
2150
|
+
leaves.push({
|
|
2151
|
+
segments: combined,
|
|
2152
|
+
symbol: combined[combined.length - 1] ?? null,
|
|
2153
|
+
wildcard: false
|
|
2154
|
+
});
|
|
2155
|
+
return;
|
|
2156
|
+
}
|
|
2157
|
+
case "scoped_use_list": {
|
|
2158
|
+
const pathNode = node.namedChildren[0] ?? null;
|
|
2159
|
+
const listNode = node.namedChildren[1] ?? null;
|
|
2160
|
+
const nextPrefix = [...prefix, ...flattenRustPath(pathNode)];
|
|
2161
|
+
collectRustUseLeaves(listNode, nextPrefix, leaves);
|
|
2162
|
+
return;
|
|
2163
|
+
}
|
|
2164
|
+
case "use_list": {
|
|
2165
|
+
for (const child of node.namedChildren) {
|
|
2166
|
+
collectRustUseLeaves(child, prefix, leaves);
|
|
2167
|
+
}
|
|
2168
|
+
return;
|
|
2169
|
+
}
|
|
2170
|
+
case "use_wildcard": {
|
|
2171
|
+
const pathNode = node.namedChildren[0] ?? null;
|
|
2172
|
+
const pathSegments = pathNode ? flattenRustPath(pathNode) : [];
|
|
2173
|
+
leaves.push({
|
|
2174
|
+
segments: [...prefix, ...pathSegments],
|
|
2175
|
+
symbol: null,
|
|
2176
|
+
wildcard: true
|
|
2177
|
+
});
|
|
2178
|
+
return;
|
|
2179
|
+
}
|
|
2180
|
+
case "use_as_clause": {
|
|
2181
|
+
const pathNode = node.childForFieldName("path") ?? node.namedChildren[0] ?? null;
|
|
2182
|
+
const aliasNode = node.childForFieldName("alias") ?? node.namedChildren[1] ?? null;
|
|
2183
|
+
const before = leaves.length;
|
|
2184
|
+
collectRustUseLeaves(pathNode, prefix, leaves);
|
|
2185
|
+
const alias = aliasNode?.text.trim();
|
|
2186
|
+
if (alias) {
|
|
2187
|
+
for (let index = before; index < leaves.length; index += 1) {
|
|
2188
|
+
const leaf = leaves[index];
|
|
2189
|
+
if (leaf) {
|
|
2190
|
+
leaf.alias = alias;
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
return;
|
|
2195
|
+
}
|
|
2196
|
+
default: {
|
|
2197
|
+
for (const child of node.namedChildren) {
|
|
2198
|
+
collectRustUseLeaves(child, prefix, leaves);
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
function isRustPubUse(useNode) {
|
|
2204
|
+
for (const child of useNode.children) {
|
|
2205
|
+
if (!child) {
|
|
2206
|
+
continue;
|
|
2207
|
+
}
|
|
2208
|
+
if (child.type === "visibility_modifier") {
|
|
2209
|
+
return true;
|
|
2210
|
+
}
|
|
2211
|
+
if (child.type === "use") {
|
|
2212
|
+
return false;
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
return false;
|
|
2216
|
+
}
|
|
2217
|
+
function parseRustUseDeclaration(useNode) {
|
|
2218
|
+
const inner = useNode.namedChildren.find((child) => child !== null) ?? null;
|
|
2219
|
+
if (!inner) {
|
|
2220
|
+
return [];
|
|
2221
|
+
}
|
|
2222
|
+
const leaves = [];
|
|
2223
|
+
collectRustUseLeaves(inner, [], leaves);
|
|
2224
|
+
if (leaves.length === 0) {
|
|
2225
|
+
return [];
|
|
2226
|
+
}
|
|
2227
|
+
const reExport = isRustPubUse(useNode);
|
|
2228
|
+
return leaves.map((leaf) => {
|
|
2229
|
+
const specifier = leaf.segments.join("::");
|
|
2230
|
+
const importedSymbols = leaf.wildcard ? ["*"] : leaf.alias && leaf.symbol ? [`${leaf.symbol} as ${leaf.alias}`] : leaf.symbol ? [leaf.symbol] : [];
|
|
2231
|
+
return {
|
|
2232
|
+
specifier,
|
|
2233
|
+
importedSymbols,
|
|
2234
|
+
isExternal: !/^(?:crate|self|super)(?:$|::)/.test(specifier),
|
|
2235
|
+
reExport
|
|
2236
|
+
};
|
|
2237
|
+
});
|
|
2238
|
+
}
|
|
2239
|
+
function flattenJavaScopedIdentifier(node) {
|
|
2240
|
+
if (!node) {
|
|
2241
|
+
return "";
|
|
2242
|
+
}
|
|
2243
|
+
if (node.type === "identifier") {
|
|
2244
|
+
return node.text.trim();
|
|
2245
|
+
}
|
|
2246
|
+
if (node.type === "scoped_identifier") {
|
|
2247
|
+
const head = node.namedChildren[0] ?? null;
|
|
2248
|
+
const tail = node.namedChildren[node.namedChildren.length - 1] ?? null;
|
|
2249
|
+
const headText = flattenJavaScopedIdentifier(head);
|
|
2250
|
+
const tailText = tail && tail !== head && tail.type === "identifier" ? tail.text.trim() : "";
|
|
2251
|
+
return headText && tailText ? `${headText}.${tailText}` : headText || tailText;
|
|
2252
|
+
}
|
|
2253
|
+
return node.text.trim();
|
|
2254
|
+
}
|
|
2255
|
+
function parseJavaImport(node) {
|
|
2256
|
+
const pathNode = node.namedChildren.find((child) => child?.type === "scoped_identifier") ?? null;
|
|
2257
|
+
const hasAsterisk = node.namedChildren.some((child) => child?.type === "asterisk");
|
|
2258
|
+
const pathText = flattenJavaScopedIdentifier(pathNode);
|
|
2259
|
+
const specifier = hasAsterisk ? `${pathText}.*` : pathText;
|
|
2260
|
+
const symbolName = hasAsterisk ? "" : (pathText.split(".").pop() ?? "").trim();
|
|
2261
|
+
return {
|
|
2262
|
+
specifier,
|
|
2263
|
+
importedSymbols: symbolName ? [symbolName] : [],
|
|
2264
|
+
isExternal: true,
|
|
2265
|
+
reExport: false
|
|
2266
|
+
};
|
|
2267
|
+
}
|
|
2268
|
+
function flattenKotlinIdentifier(node) {
|
|
2269
|
+
if (!node) {
|
|
2270
|
+
return "";
|
|
2271
|
+
}
|
|
2272
|
+
if (node.type === "simple_identifier") {
|
|
2273
|
+
return node.text.trim();
|
|
2274
|
+
}
|
|
2275
|
+
return node.namedChildren.filter((child) => child?.type === "simple_identifier").map((child) => child.text.trim()).filter(Boolean).join(".");
|
|
2276
|
+
}
|
|
2277
|
+
function parseKotlinImport(header) {
|
|
2278
|
+
const identifierNode = header.namedChildren.find((child) => child?.type === "identifier") ?? null;
|
|
2279
|
+
const specifier = flattenKotlinIdentifier(identifierNode);
|
|
2280
|
+
if (!specifier) {
|
|
2281
|
+
return void 0;
|
|
2282
|
+
}
|
|
2283
|
+
const hasWildcard = header.descendantsOfType("wildcard_import").some((child) => child !== null);
|
|
2284
|
+
const aliasNode = header.namedChildren.find((child) => child?.type === "import_alias") ?? null;
|
|
2285
|
+
const aliasName = aliasNode ? flattenKotlinIdentifier(aliasNode.namedChildren.find((child) => child?.type === "type_identifier") ?? null) || aliasNode.text.replace(/^as\s+/, "").trim() : void 0;
|
|
2286
|
+
return {
|
|
2287
|
+
specifier: hasWildcard ? `${specifier}.*` : specifier,
|
|
2288
|
+
importedSymbols: hasWildcard ? ["*"] : [],
|
|
2289
|
+
namespaceImport: aliasName || void 0,
|
|
2290
|
+
isExternal: true,
|
|
2291
|
+
reExport: false
|
|
2292
|
+
};
|
|
2293
|
+
}
|
|
2294
|
+
function flattenScalaStableIdentifier(node) {
|
|
2295
|
+
if (!node) {
|
|
2296
|
+
return "";
|
|
2297
|
+
}
|
|
2298
|
+
if (node.type === "identifier") {
|
|
2299
|
+
return node.text.trim();
|
|
2300
|
+
}
|
|
2301
|
+
if (node.type === "stable_identifier") {
|
|
2302
|
+
return node.namedChildren.filter((child) => child !== null).map((child) => flattenScalaStableIdentifier(child)).filter(Boolean).join(".");
|
|
2303
|
+
}
|
|
2304
|
+
return node.text.trim();
|
|
2305
|
+
}
|
|
2306
|
+
function parseScalaImport(node) {
|
|
2307
|
+
const pathNode = node.namedChildren.find((child) => child?.type === "stable_identifier") ?? node.namedChildren.find((child) => child?.type === "identifier") ?? null;
|
|
2308
|
+
const basePath = flattenScalaStableIdentifier(pathNode);
|
|
2309
|
+
if (!basePath) {
|
|
2310
|
+
return [];
|
|
2311
|
+
}
|
|
2312
|
+
const selectorsNode = node.namedChildren.find((child) => child?.type === "import_selectors") ?? null;
|
|
2313
|
+
const wildcardNode = node.namedChildren.find((child) => child?.type === "wildcard") ?? null;
|
|
2314
|
+
if (selectorsNode) {
|
|
2315
|
+
const results = [];
|
|
2316
|
+
for (const selector of selectorsNode.namedChildren) {
|
|
2317
|
+
if (!selector) {
|
|
2318
|
+
continue;
|
|
2319
|
+
}
|
|
2320
|
+
if (selector.type === "identifier") {
|
|
2321
|
+
const symbol2 = selector.text.trim();
|
|
2322
|
+
if (symbol2) {
|
|
2323
|
+
results.push({
|
|
2324
|
+
specifier: basePath,
|
|
2325
|
+
importedSymbols: [symbol2],
|
|
2326
|
+
isExternal: !basePath.startsWith("."),
|
|
2327
|
+
reExport: false
|
|
2328
|
+
});
|
|
2329
|
+
}
|
|
2330
|
+
continue;
|
|
2331
|
+
}
|
|
2332
|
+
if (selector.type === "renamed_identifier") {
|
|
2333
|
+
const idChildren = selector.namedChildren.filter((child) => child?.type === "identifier");
|
|
2334
|
+
const [original, alias] = [idChildren[0]?.text.trim(), idChildren[1]?.text.trim()];
|
|
2335
|
+
if (original) {
|
|
2336
|
+
results.push({
|
|
2337
|
+
specifier: basePath,
|
|
2338
|
+
importedSymbols: [alias ? `${original} as ${alias}` : original],
|
|
2339
|
+
isExternal: !basePath.startsWith("."),
|
|
2340
|
+
reExport: false
|
|
2341
|
+
});
|
|
2342
|
+
}
|
|
2343
|
+
continue;
|
|
2344
|
+
}
|
|
2345
|
+
if (selector.type === "wildcard") {
|
|
2346
|
+
results.push({
|
|
2347
|
+
specifier: basePath,
|
|
2348
|
+
importedSymbols: ["*"],
|
|
2349
|
+
isExternal: !basePath.startsWith("."),
|
|
2350
|
+
reExport: false
|
|
2351
|
+
});
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
return results;
|
|
2355
|
+
}
|
|
2356
|
+
if (wildcardNode) {
|
|
2357
|
+
return [
|
|
2358
|
+
{
|
|
2359
|
+
specifier: basePath,
|
|
2360
|
+
importedSymbols: ["*"],
|
|
2361
|
+
isExternal: !basePath.startsWith("."),
|
|
2362
|
+
reExport: false
|
|
2363
|
+
}
|
|
2364
|
+
];
|
|
2365
|
+
}
|
|
2366
|
+
const segments = basePath.split(".");
|
|
2367
|
+
const symbol = segments.pop() ?? basePath;
|
|
2368
|
+
const parent = segments.join(".");
|
|
2369
|
+
return [
|
|
2370
|
+
{
|
|
2371
|
+
specifier: parent || basePath,
|
|
2372
|
+
importedSymbols: [symbol],
|
|
2373
|
+
isExternal: !basePath.startsWith("."),
|
|
2374
|
+
reExport: false
|
|
2375
|
+
}
|
|
2376
|
+
];
|
|
2283
2377
|
}
|
|
2284
2378
|
function bashCommandName(commandNode) {
|
|
2285
2379
|
if (!commandNode) {
|
|
@@ -2401,55 +2495,165 @@ function parseZigImport(node) {
|
|
|
2401
2495
|
reExport: false
|
|
2402
2496
|
};
|
|
2403
2497
|
}
|
|
2404
|
-
function
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
return {
|
|
2408
|
-
specifier: aliasMatch[2].trim(),
|
|
2409
|
-
importedSymbols: [],
|
|
2410
|
-
namespaceImport: aliasMatch[1],
|
|
2411
|
-
isExternal: !aliasMatch[2].trim().startsWith("."),
|
|
2412
|
-
reExport: false
|
|
2413
|
-
};
|
|
2498
|
+
function flattenCSharpQualifiedName(node) {
|
|
2499
|
+
if (!node) {
|
|
2500
|
+
return "";
|
|
2414
2501
|
}
|
|
2415
|
-
|
|
2416
|
-
|
|
2502
|
+
if (node.type === "identifier") {
|
|
2503
|
+
return node.text.trim();
|
|
2504
|
+
}
|
|
2505
|
+
if (node.type === "qualified_name") {
|
|
2506
|
+
const [head, tail] = [node.namedChildren[0] ?? null, node.namedChildren[1] ?? null];
|
|
2507
|
+
const headText = flattenCSharpQualifiedName(head);
|
|
2508
|
+
const tailText = tail?.type === "identifier" ? tail.text.trim() : flattenCSharpQualifiedName(tail);
|
|
2509
|
+
return headText && tailText ? `${headText}.${tailText}` : headText || tailText;
|
|
2510
|
+
}
|
|
2511
|
+
return node.text.trim();
|
|
2512
|
+
}
|
|
2513
|
+
function parseCSharpUsing(node) {
|
|
2514
|
+
const namedChildren = node.namedChildren.filter((child) => child !== null);
|
|
2515
|
+
if (namedChildren.length === 0) {
|
|
2516
|
+
return void 0;
|
|
2517
|
+
}
|
|
2518
|
+
let aliasName;
|
|
2519
|
+
let pathNode = null;
|
|
2520
|
+
if (namedChildren.length >= 2 && namedChildren[0]?.type === "identifier" && namedChildren[1]) {
|
|
2521
|
+
aliasName = namedChildren[0].text.trim();
|
|
2522
|
+
pathNode = namedChildren[1];
|
|
2523
|
+
} else {
|
|
2524
|
+
pathNode = namedChildren[0] ?? null;
|
|
2525
|
+
}
|
|
2526
|
+
const specifier = flattenCSharpQualifiedName(pathNode);
|
|
2527
|
+
if (!specifier) {
|
|
2417
2528
|
return void 0;
|
|
2418
2529
|
}
|
|
2419
2530
|
return {
|
|
2420
|
-
specifier
|
|
2531
|
+
specifier,
|
|
2421
2532
|
importedSymbols: [],
|
|
2422
|
-
|
|
2533
|
+
namespaceImport: aliasName,
|
|
2534
|
+
isExternal: !specifier.startsWith("."),
|
|
2423
2535
|
reExport: false
|
|
2424
2536
|
};
|
|
2425
2537
|
}
|
|
2426
|
-
function
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
return
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2538
|
+
function flattenPhpQualifiedName(node) {
|
|
2539
|
+
if (!node) {
|
|
2540
|
+
return "";
|
|
2541
|
+
}
|
|
2542
|
+
if (node.type === "name") {
|
|
2543
|
+
return node.text.trim();
|
|
2544
|
+
}
|
|
2545
|
+
if (node.type === "namespace_name") {
|
|
2546
|
+
return node.namedChildren.filter((child) => child?.type === "name").map((child) => child.text.trim()).filter(Boolean).join("\\");
|
|
2547
|
+
}
|
|
2548
|
+
if (node.type === "qualified_name") {
|
|
2549
|
+
const parts = [];
|
|
2550
|
+
for (const child of node.namedChildren) {
|
|
2551
|
+
if (!child) {
|
|
2552
|
+
continue;
|
|
2553
|
+
}
|
|
2554
|
+
if (child.type === "namespace_name") {
|
|
2555
|
+
parts.push(flattenPhpQualifiedName(child));
|
|
2556
|
+
} else if (child.type === "name") {
|
|
2557
|
+
parts.push(child.text.trim());
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
return parts.filter(Boolean).join("\\");
|
|
2561
|
+
}
|
|
2562
|
+
return node.text.trim();
|
|
2439
2563
|
}
|
|
2440
|
-
function
|
|
2441
|
-
const
|
|
2442
|
-
|
|
2564
|
+
function parsePhpUseClause(clause, prefix) {
|
|
2565
|
+
const names = clause.namedChildren.filter((child) => child?.type === "name");
|
|
2566
|
+
const qualified = clause.namedChildren.find((child) => child?.type === "qualified_name") ?? null;
|
|
2567
|
+
let specifier;
|
|
2568
|
+
let aliasName;
|
|
2569
|
+
if (qualified) {
|
|
2570
|
+
specifier = flattenPhpQualifiedName(qualified);
|
|
2571
|
+
if (names.length >= 1 && names[0]) {
|
|
2572
|
+
aliasName = names[0].text.trim();
|
|
2573
|
+
}
|
|
2574
|
+
} else if (names.length >= 1 && names[0]) {
|
|
2575
|
+
specifier = names[0].text.trim();
|
|
2576
|
+
if (names.length >= 2 && names[1]) {
|
|
2577
|
+
aliasName = names[1].text.trim();
|
|
2578
|
+
}
|
|
2579
|
+
} else {
|
|
2580
|
+
return void 0;
|
|
2581
|
+
}
|
|
2582
|
+
if (prefix && specifier) {
|
|
2583
|
+
specifier = `${prefix}\\${specifier}`;
|
|
2584
|
+
}
|
|
2585
|
+
if (!specifier) {
|
|
2443
2586
|
return void 0;
|
|
2444
2587
|
}
|
|
2445
|
-
const specifier = quotedPath(match[1]);
|
|
2446
2588
|
return {
|
|
2447
2589
|
specifier,
|
|
2448
2590
|
importedSymbols: [],
|
|
2449
|
-
|
|
2591
|
+
namespaceImport: aliasName,
|
|
2592
|
+
isExternal: true,
|
|
2450
2593
|
reExport: false
|
|
2451
2594
|
};
|
|
2452
2595
|
}
|
|
2596
|
+
function parsePhpUse(node) {
|
|
2597
|
+
const results = [];
|
|
2598
|
+
const groupNode = node.namedChildren.find((child) => child?.type === "namespace_use_group") ?? null;
|
|
2599
|
+
if (groupNode) {
|
|
2600
|
+
const prefixNode = node.namedChildren.find((child) => child?.type === "namespace_name") ?? null;
|
|
2601
|
+
const prefix = flattenPhpQualifiedName(prefixNode);
|
|
2602
|
+
for (const clause of groupNode.namedChildren) {
|
|
2603
|
+
if (!clause || clause.type !== "namespace_use_clause") {
|
|
2604
|
+
continue;
|
|
2605
|
+
}
|
|
2606
|
+
const parsed = parsePhpUseClause(clause, prefix);
|
|
2607
|
+
if (parsed) {
|
|
2608
|
+
results.push(parsed);
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
return results;
|
|
2612
|
+
}
|
|
2613
|
+
for (const child of node.namedChildren) {
|
|
2614
|
+
if (!child || child.type !== "namespace_use_clause") {
|
|
2615
|
+
continue;
|
|
2616
|
+
}
|
|
2617
|
+
const parsed = parsePhpUseClause(child, "");
|
|
2618
|
+
if (parsed) {
|
|
2619
|
+
results.push(parsed);
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
return results;
|
|
2623
|
+
}
|
|
2624
|
+
function parseCppInclude(node) {
|
|
2625
|
+
for (const child of node.namedChildren) {
|
|
2626
|
+
if (!child) {
|
|
2627
|
+
continue;
|
|
2628
|
+
}
|
|
2629
|
+
if (child.type === "system_lib_string") {
|
|
2630
|
+
const specifier = child.text.replace(/^</, "").replace(/>$/, "").trim();
|
|
2631
|
+
if (!specifier) {
|
|
2632
|
+
return void 0;
|
|
2633
|
+
}
|
|
2634
|
+
return {
|
|
2635
|
+
specifier,
|
|
2636
|
+
importedSymbols: [],
|
|
2637
|
+
isExternal: true,
|
|
2638
|
+
reExport: false
|
|
2639
|
+
};
|
|
2640
|
+
}
|
|
2641
|
+
if (child.type === "string_literal") {
|
|
2642
|
+
const contentNode = child.namedChildren.find((inner) => inner?.type === "string_content") ?? null;
|
|
2643
|
+
const specifier = (contentNode?.text ?? child.text.replace(/^"|"$/g, "")).trim();
|
|
2644
|
+
if (!specifier) {
|
|
2645
|
+
return void 0;
|
|
2646
|
+
}
|
|
2647
|
+
return {
|
|
2648
|
+
specifier,
|
|
2649
|
+
importedSymbols: [],
|
|
2650
|
+
isExternal: false,
|
|
2651
|
+
reExport: false
|
|
2652
|
+
};
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
return void 0;
|
|
2656
|
+
}
|
|
2453
2657
|
function rubyStringContent(node) {
|
|
2454
2658
|
if (!node) {
|
|
2455
2659
|
return void 0;
|
|
@@ -2459,7 +2663,8 @@ function rubyStringContent(node) {
|
|
|
2459
2663
|
}
|
|
2460
2664
|
function normalizePowerShellDotSourceSpecifier(raw) {
|
|
2461
2665
|
const unquoted = raw.replace(/^['"]+|['"]+$/g, "").trim();
|
|
2462
|
-
|
|
2666
|
+
const withoutScriptRoot = unquoted.replace(/^\$PSScriptRoot(?:[\\/]+|$)/i, "./");
|
|
2667
|
+
return withoutScriptRoot.replace(/\\/g, "/");
|
|
2463
2668
|
}
|
|
2464
2669
|
function parsePowerShellImport(commandNode) {
|
|
2465
2670
|
const commandName = commandNode.descendantsOfType(["command_name", "command_name_expr"]).find((item) => item !== null)?.text.trim();
|
|
@@ -2574,24 +2779,20 @@ function zigDeclarationKind(node) {
|
|
|
2574
2779
|
}
|
|
2575
2780
|
return void 0;
|
|
2576
2781
|
}
|
|
2577
|
-
function bashCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
2782
|
+
function bashCodeAnalysis(manifest, rootNode, diagnostics, rawContent) {
|
|
2578
2783
|
const imports = [];
|
|
2579
2784
|
const draftSymbols = [];
|
|
2580
2785
|
const exportLabels = [];
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
const parsed = parseBashImport(child);
|
|
2587
|
-
if (parsed) {
|
|
2588
|
-
imports.push(parsed);
|
|
2589
|
-
}
|
|
2590
|
-
continue;
|
|
2591
|
-
}
|
|
2592
|
-
if (child.type !== "function_definition") {
|
|
2593
|
-
continue;
|
|
2786
|
+
const commandNodes = rootNode.descendantsOfType("command").filter((node) => node !== null);
|
|
2787
|
+
for (const command of commandNodes) {
|
|
2788
|
+
const parsed = parseBashImport(command);
|
|
2789
|
+
if (parsed) {
|
|
2790
|
+
imports.push(parsed);
|
|
2594
2791
|
}
|
|
2792
|
+
}
|
|
2793
|
+
const functionNodes = rootNode.descendantsOfType("function_definition").filter((node) => node !== null);
|
|
2794
|
+
const functionByName = /* @__PURE__ */ new Map();
|
|
2795
|
+
for (const child of functionNodes) {
|
|
2595
2796
|
const name = nodeText(child.childForFieldName("name") ?? child.namedChildren.at(0) ?? null).trim();
|
|
2596
2797
|
if (!name) {
|
|
2597
2798
|
continue;
|
|
@@ -2607,16 +2808,44 @@ function bashCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
|
2607
2808
|
bodyText: nodeText(child.childForFieldName("body") ?? findNamedChild(child, "compound_statement"))
|
|
2608
2809
|
});
|
|
2609
2810
|
exportLabels.push(name);
|
|
2811
|
+
if (!functionByName.has(name)) {
|
|
2812
|
+
functionByName.set(name, child);
|
|
2813
|
+
}
|
|
2610
2814
|
}
|
|
2611
2815
|
for (let index = 0; index < draftSymbols.length; index += 1) {
|
|
2612
|
-
const
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
draftSymbols[index].callNames = bashCallNamesFromBody(
|
|
2816
|
+
const symbol = draftSymbols[index];
|
|
2817
|
+
const functionNode = functionByName.get(symbol.name);
|
|
2818
|
+
symbol.callNames = bashCallNamesFromBody(
|
|
2616
2819
|
functionNode?.childForFieldName("body") ?? findNamedChild(functionNode, "compound_statement"),
|
|
2617
|
-
|
|
2820
|
+
symbol.name
|
|
2618
2821
|
);
|
|
2619
2822
|
}
|
|
2823
|
+
if (draftSymbols.length === 0 && rawContent) {
|
|
2824
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2825
|
+
for (const line of rawContent.split("\n")) {
|
|
2826
|
+
const trimmed = line.trimStart();
|
|
2827
|
+
let match = trimmed.match(/^function\s+([A-Za-z_][\w-]*)\s*(?:\(\))?/);
|
|
2828
|
+
if (!match) {
|
|
2829
|
+
match = trimmed.match(/^([A-Za-z_][\w-]*)\s*\(\)/);
|
|
2830
|
+
}
|
|
2831
|
+
const name = match?.[1];
|
|
2832
|
+
if (!name || seen.has(name)) {
|
|
2833
|
+
continue;
|
|
2834
|
+
}
|
|
2835
|
+
seen.add(name);
|
|
2836
|
+
draftSymbols.push({
|
|
2837
|
+
name,
|
|
2838
|
+
kind: "function",
|
|
2839
|
+
signature: singleLineSignature(trimmed),
|
|
2840
|
+
exported: true,
|
|
2841
|
+
callNames: [],
|
|
2842
|
+
extendsNames: [],
|
|
2843
|
+
implementsNames: [],
|
|
2844
|
+
bodyText: ""
|
|
2845
|
+
});
|
|
2846
|
+
exportLabels.push(name);
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2620
2849
|
return finalizeCodeAnalysis(manifest, "bash", imports, draftSymbols, exportLabels, diagnostics);
|
|
2621
2850
|
}
|
|
2622
2851
|
function dartCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
@@ -2813,11 +3042,11 @@ function pythonCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
|
2813
3042
|
continue;
|
|
2814
3043
|
}
|
|
2815
3044
|
if (child.type === "import_statement") {
|
|
2816
|
-
imports.push(...parsePythonImportStatement(child
|
|
3045
|
+
imports.push(...parsePythonImportStatement(child));
|
|
2817
3046
|
continue;
|
|
2818
3047
|
}
|
|
2819
3048
|
if (child.type === "import_from_statement") {
|
|
2820
|
-
imports.push(...parsePythonFromImportStatement(child
|
|
3049
|
+
imports.push(...parsePythonFromImportStatement(child));
|
|
2821
3050
|
continue;
|
|
2822
3051
|
}
|
|
2823
3052
|
if (child.type === "class_definition") {
|
|
@@ -2872,7 +3101,7 @@ function goCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
|
2872
3101
|
}
|
|
2873
3102
|
if (child.type === "import_declaration") {
|
|
2874
3103
|
for (const spec of child.descendantsOfType("import_spec")) {
|
|
2875
|
-
const parsed = spec ? parseGoImport(spec
|
|
3104
|
+
const parsed = spec ? parseGoImport(spec) : void 0;
|
|
2876
3105
|
if (parsed) {
|
|
2877
3106
|
imports.push(parsed);
|
|
2878
3107
|
}
|
|
@@ -2946,7 +3175,7 @@ function rustCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
|
2946
3175
|
continue;
|
|
2947
3176
|
}
|
|
2948
3177
|
if (child.type === "use_declaration") {
|
|
2949
|
-
imports.push(
|
|
3178
|
+
imports.push(...parseRustUseDeclaration(child));
|
|
2950
3179
|
continue;
|
|
2951
3180
|
}
|
|
2952
3181
|
if (child.type === "mod_item") {
|
|
@@ -3025,11 +3254,15 @@ function javaCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
|
3025
3254
|
continue;
|
|
3026
3255
|
}
|
|
3027
3256
|
if (child.type === "package_declaration") {
|
|
3028
|
-
|
|
3257
|
+
const pathNode = child.namedChildren.find((inner) => inner?.type === "scoped_identifier" || inner?.type === "identifier") ?? null;
|
|
3258
|
+
const flattened = flattenJavaScopedIdentifier(pathNode);
|
|
3259
|
+
if (flattened) {
|
|
3260
|
+
packageName = flattened;
|
|
3261
|
+
}
|
|
3029
3262
|
continue;
|
|
3030
3263
|
}
|
|
3031
3264
|
if (child.type === "import_declaration") {
|
|
3032
|
-
imports.push(parseJavaImport(child
|
|
3265
|
+
imports.push(parseJavaImport(child));
|
|
3033
3266
|
continue;
|
|
3034
3267
|
}
|
|
3035
3268
|
const name = extractIdentifier(child.childForFieldName("name"));
|
|
@@ -3117,7 +3350,7 @@ function kotlinCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
|
3117
3350
|
}
|
|
3118
3351
|
if (child.type === "import_list") {
|
|
3119
3352
|
for (const importNode of child.descendantsOfType("import_header").filter((item) => item !== null)) {
|
|
3120
|
-
const parsed = parseKotlinImport(importNode
|
|
3353
|
+
const parsed = parseKotlinImport(importNode);
|
|
3121
3354
|
if (parsed) {
|
|
3122
3355
|
imports.push(parsed);
|
|
3123
3356
|
}
|
|
@@ -3207,7 +3440,7 @@ function scalaCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
|
3207
3440
|
continue;
|
|
3208
3441
|
}
|
|
3209
3442
|
if (child.type === "import_declaration") {
|
|
3210
|
-
imports.push(...parseScalaImport(child
|
|
3443
|
+
imports.push(...parseScalaImport(child));
|
|
3211
3444
|
continue;
|
|
3212
3445
|
}
|
|
3213
3446
|
if (child.type === "function_definition") {
|
|
@@ -3388,7 +3621,7 @@ function csharpCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
|
3388
3621
|
continue;
|
|
3389
3622
|
}
|
|
3390
3623
|
if (child.type === "using_directive") {
|
|
3391
|
-
const parsed = parseCSharpUsing(child
|
|
3624
|
+
const parsed = parseCSharpUsing(child);
|
|
3392
3625
|
if (parsed) {
|
|
3393
3626
|
imports.push(parsed);
|
|
3394
3627
|
}
|
|
@@ -3397,7 +3630,23 @@ function csharpCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
|
3397
3630
|
if (child.type === "file_scoped_namespace_declaration" || child.type === "namespace_declaration") {
|
|
3398
3631
|
namespaceName = nodeText(child.childForFieldName("name")) || namespaceName;
|
|
3399
3632
|
if (child.type === "namespace_declaration") {
|
|
3400
|
-
|
|
3633
|
+
const nameNode = child.childForFieldName("name");
|
|
3634
|
+
const namespaceMembers = [];
|
|
3635
|
+
for (const directChild of child.namedChildren) {
|
|
3636
|
+
if (!directChild || directChild === nameNode) {
|
|
3637
|
+
continue;
|
|
3638
|
+
}
|
|
3639
|
+
if (directChild.type === "declaration_list") {
|
|
3640
|
+
for (const inner of directChild.namedChildren) {
|
|
3641
|
+
if (inner) {
|
|
3642
|
+
namespaceMembers.push(inner);
|
|
3643
|
+
}
|
|
3644
|
+
}
|
|
3645
|
+
continue;
|
|
3646
|
+
}
|
|
3647
|
+
namespaceMembers.push(directChild);
|
|
3648
|
+
}
|
|
3649
|
+
for (const nested of namespaceMembers) {
|
|
3401
3650
|
if (nested && nested !== child.childForFieldName("name")) {
|
|
3402
3651
|
if (["class_declaration", "interface_declaration", "enum_declaration", "struct_declaration", "record_declaration"].includes(
|
|
3403
3652
|
nested.type
|
|
@@ -3480,7 +3729,7 @@ function phpCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
|
3480
3729
|
continue;
|
|
3481
3730
|
}
|
|
3482
3731
|
if (child.type === "namespace_use_declaration") {
|
|
3483
|
-
imports.push(...parsePhpUse(child
|
|
3732
|
+
imports.push(...parsePhpUse(child));
|
|
3484
3733
|
continue;
|
|
3485
3734
|
}
|
|
3486
3735
|
const name = extractIdentifier(child.childForFieldName("name"));
|
|
@@ -3610,80 +3859,1234 @@ function rubyCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
|
3610
3859
|
exportLabels.push(symbolName);
|
|
3611
3860
|
}
|
|
3612
3861
|
}
|
|
3613
|
-
};
|
|
3614
|
-
visitStatements(rootNode, void 0, []);
|
|
3615
|
-
return finalizeCodeAnalysis(manifest, "ruby", imports, draftSymbols, exportLabels, diagnostics, {
|
|
3616
|
-
namespace: namespaceName
|
|
3617
|
-
});
|
|
3862
|
+
};
|
|
3863
|
+
visitStatements(rootNode, void 0, []);
|
|
3864
|
+
return finalizeCodeAnalysis(manifest, "ruby", imports, draftSymbols, exportLabels, diagnostics, {
|
|
3865
|
+
namespace: namespaceName
|
|
3866
|
+
});
|
|
3867
|
+
}
|
|
3868
|
+
function powershellCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
3869
|
+
const imports = [];
|
|
3870
|
+
const draftSymbols = [];
|
|
3871
|
+
const exportLabels = [];
|
|
3872
|
+
for (const child of rootNode.descendantsOfType(["command", "class_statement", "function_statement"]).filter((item) => item !== null)) {
|
|
3873
|
+
if (child.type === "command") {
|
|
3874
|
+
const parsed = parsePowerShellImport(child);
|
|
3875
|
+
if (parsed) {
|
|
3876
|
+
imports.push(parsed);
|
|
3877
|
+
}
|
|
3878
|
+
continue;
|
|
3879
|
+
}
|
|
3880
|
+
if (child.type === "class_statement") {
|
|
3881
|
+
const names = child.namedChildren.filter((item) => item !== null && item.type === "simple_name").map((item) => item.text.trim());
|
|
3882
|
+
const className = names[0];
|
|
3883
|
+
if (!className) {
|
|
3884
|
+
continue;
|
|
3885
|
+
}
|
|
3886
|
+
draftSymbols.push({
|
|
3887
|
+
name: className,
|
|
3888
|
+
kind: "class",
|
|
3889
|
+
signature: singleLineSignature(child.text),
|
|
3890
|
+
exported: true,
|
|
3891
|
+
callNames: [],
|
|
3892
|
+
extendsNames: names.slice(1, 2),
|
|
3893
|
+
implementsNames: [],
|
|
3894
|
+
bodyText: nodeText(child.childForFieldName("body")) || child.text
|
|
3895
|
+
});
|
|
3896
|
+
exportLabels.push(className);
|
|
3897
|
+
for (const methodNode of child.descendantsOfType("class_method_definition").filter((item) => item !== null)) {
|
|
3898
|
+
const methodName = methodNode.descendantsOfType("simple_name").filter((item) => item !== null).map((item) => item.text.trim())[0];
|
|
3899
|
+
if (!methodName) {
|
|
3900
|
+
continue;
|
|
3901
|
+
}
|
|
3902
|
+
const symbolName = `${className}.${methodName}`;
|
|
3903
|
+
draftSymbols.push({
|
|
3904
|
+
name: symbolName,
|
|
3905
|
+
kind: "function",
|
|
3906
|
+
signature: singleLineSignature(methodNode.text),
|
|
3907
|
+
exported: true,
|
|
3908
|
+
callNames: [],
|
|
3909
|
+
extendsNames: [],
|
|
3910
|
+
implementsNames: [],
|
|
3911
|
+
bodyText: nodeText(findNamedChild(methodNode, "script_block") ?? methodNode.childForFieldName("body")) || methodNode.text
|
|
3912
|
+
});
|
|
3913
|
+
exportLabels.push(symbolName);
|
|
3914
|
+
}
|
|
3915
|
+
continue;
|
|
3916
|
+
}
|
|
3917
|
+
if (child.type === "function_statement") {
|
|
3918
|
+
const functionName = extractIdentifier(findNamedChild(child, "function_name") ?? child.childForFieldName("name"));
|
|
3919
|
+
if (!functionName) {
|
|
3920
|
+
continue;
|
|
3921
|
+
}
|
|
3922
|
+
draftSymbols.push({
|
|
3923
|
+
name: functionName,
|
|
3924
|
+
kind: "function",
|
|
3925
|
+
signature: singleLineSignature(child.text),
|
|
3926
|
+
exported: true,
|
|
3927
|
+
callNames: [],
|
|
3928
|
+
extendsNames: [],
|
|
3929
|
+
implementsNames: [],
|
|
3930
|
+
bodyText: nodeText(findNamedChild(child, "script_block") ?? child.childForFieldName("body")) || child.text
|
|
3931
|
+
});
|
|
3932
|
+
exportLabels.push(functionName);
|
|
3933
|
+
}
|
|
3934
|
+
}
|
|
3935
|
+
return finalizeCodeAnalysis(manifest, "powershell", imports, draftSymbols, exportLabels, diagnostics);
|
|
3936
|
+
}
|
|
3937
|
+
function parseSwiftImport(node) {
|
|
3938
|
+
const identifierNode = findNamedChild(node, "identifier");
|
|
3939
|
+
if (!identifierNode) {
|
|
3940
|
+
return void 0;
|
|
3941
|
+
}
|
|
3942
|
+
const specifier = identifierNode.text.trim();
|
|
3943
|
+
if (!specifier) {
|
|
3944
|
+
return void 0;
|
|
3945
|
+
}
|
|
3946
|
+
return {
|
|
3947
|
+
specifier,
|
|
3948
|
+
importedSymbols: [],
|
|
3949
|
+
// Swift does not have file-local relative imports; every `import` references
|
|
3950
|
+
// an external module (Foundation, UIKit, a SwiftPM package product, or the
|
|
3951
|
+
// current target's own module). Mark them all as external so the dependency
|
|
3952
|
+
// aggregator groups them with other package-level graph edges.
|
|
3953
|
+
isExternal: true,
|
|
3954
|
+
reExport: false
|
|
3955
|
+
};
|
|
3956
|
+
}
|
|
3957
|
+
function swiftDeclarationKindFromKeyword(node) {
|
|
3958
|
+
for (const child of node.children) {
|
|
3959
|
+
if (!child) {
|
|
3960
|
+
continue;
|
|
3961
|
+
}
|
|
3962
|
+
if (child.type === "struct") {
|
|
3963
|
+
return "struct";
|
|
3964
|
+
}
|
|
3965
|
+
if (child.type === "enum") {
|
|
3966
|
+
return "enum";
|
|
3967
|
+
}
|
|
3968
|
+
if (child.type === "class") {
|
|
3969
|
+
return "class";
|
|
3970
|
+
}
|
|
3971
|
+
}
|
|
3972
|
+
return "class";
|
|
3973
|
+
}
|
|
3974
|
+
function swiftVisibilityKeyword(node) {
|
|
3975
|
+
const modifiers = findNamedChild(node, "modifiers");
|
|
3976
|
+
if (!modifiers) {
|
|
3977
|
+
return void 0;
|
|
3978
|
+
}
|
|
3979
|
+
const visibility = findNamedChild(modifiers, "visibility_modifier");
|
|
3980
|
+
if (!visibility) {
|
|
3981
|
+
return void 0;
|
|
3982
|
+
}
|
|
3983
|
+
for (const kw of visibility.children) {
|
|
3984
|
+
if (!kw) {
|
|
3985
|
+
continue;
|
|
3986
|
+
}
|
|
3987
|
+
if (kw.type === "public" || kw.type === "private" || kw.type === "fileprivate" || kw.type === "internal" || kw.type === "open") {
|
|
3988
|
+
return kw.type;
|
|
3989
|
+
}
|
|
3990
|
+
}
|
|
3991
|
+
return void 0;
|
|
3992
|
+
}
|
|
3993
|
+
function swiftExported(node) {
|
|
3994
|
+
const visibility = swiftVisibilityKeyword(node);
|
|
3995
|
+
return visibility !== "private" && visibility !== "fileprivate";
|
|
3996
|
+
}
|
|
3997
|
+
function swiftCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
3998
|
+
const imports = [];
|
|
3999
|
+
const draftSymbols = [];
|
|
4000
|
+
const exportLabels = [];
|
|
4001
|
+
const recordParentTypes = (declaration) => {
|
|
4002
|
+
const specifiers = declaration.namedChildren.filter((item) => item?.type === "inheritance_specifier");
|
|
4003
|
+
if (specifiers.length === 0) {
|
|
4004
|
+
return [];
|
|
4005
|
+
}
|
|
4006
|
+
const ordered = [];
|
|
4007
|
+
for (const specifier of specifiers) {
|
|
4008
|
+
const primary = findNamedChild(specifier, "user_type") ?? findNamedChild(specifier, "type_identifier") ?? specifier.namedChildren.find((item) => item !== null) ?? null;
|
|
4009
|
+
if (!primary) {
|
|
4010
|
+
continue;
|
|
4011
|
+
}
|
|
4012
|
+
const name = normalizeSymbolReference(primary.text);
|
|
4013
|
+
if (name) {
|
|
4014
|
+
ordered.push(name);
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
4017
|
+
return uniqueBy(ordered, (item) => item);
|
|
4018
|
+
};
|
|
4019
|
+
for (const child of rootNode.namedChildren) {
|
|
4020
|
+
if (!child) {
|
|
4021
|
+
continue;
|
|
4022
|
+
}
|
|
4023
|
+
if (child.type === "import_declaration") {
|
|
4024
|
+
const parsed = parseSwiftImport(child);
|
|
4025
|
+
if (parsed) {
|
|
4026
|
+
imports.push(parsed);
|
|
4027
|
+
}
|
|
4028
|
+
continue;
|
|
4029
|
+
}
|
|
4030
|
+
if (child.type === "protocol_declaration") {
|
|
4031
|
+
const name = extractIdentifier(findNamedChild(child, "type_identifier"));
|
|
4032
|
+
if (!name) {
|
|
4033
|
+
continue;
|
|
4034
|
+
}
|
|
4035
|
+
const parents = recordParentTypes(child);
|
|
4036
|
+
const exported = swiftExported(child);
|
|
4037
|
+
draftSymbols.push({
|
|
4038
|
+
name,
|
|
4039
|
+
kind: "interface",
|
|
4040
|
+
signature: singleLineSignature(child.text),
|
|
4041
|
+
exported,
|
|
4042
|
+
callNames: [],
|
|
4043
|
+
extendsNames: parents,
|
|
4044
|
+
implementsNames: [],
|
|
4045
|
+
bodyText: nodeText(findNamedChild(child, "protocol_body")) || child.text
|
|
4046
|
+
});
|
|
4047
|
+
if (exported) {
|
|
4048
|
+
exportLabels.push(name);
|
|
4049
|
+
}
|
|
4050
|
+
continue;
|
|
4051
|
+
}
|
|
4052
|
+
if (child.type === "class_declaration") {
|
|
4053
|
+
const name = extractIdentifier(findNamedChild(child, "type_identifier"));
|
|
4054
|
+
if (!name) {
|
|
4055
|
+
continue;
|
|
4056
|
+
}
|
|
4057
|
+
const kind = swiftDeclarationKindFromKeyword(child);
|
|
4058
|
+
const parentTypes = recordParentTypes(child);
|
|
4059
|
+
const extendsNames = kind === "class" && parentTypes.length > 0 ? [parentTypes[0]] : [];
|
|
4060
|
+
const implementsNames = kind === "class" ? parentTypes.slice(1) : parentTypes;
|
|
4061
|
+
const exported = swiftExported(child);
|
|
4062
|
+
const body = findNamedChild(child, "class_body") ?? findNamedChild(child, "enum_class_body");
|
|
4063
|
+
draftSymbols.push({
|
|
4064
|
+
name,
|
|
4065
|
+
kind,
|
|
4066
|
+
signature: singleLineSignature(child.text),
|
|
4067
|
+
exported,
|
|
4068
|
+
callNames: [],
|
|
4069
|
+
extendsNames,
|
|
4070
|
+
implementsNames,
|
|
4071
|
+
bodyText: nodeText(body) || child.text
|
|
4072
|
+
});
|
|
4073
|
+
if (exported) {
|
|
4074
|
+
exportLabels.push(name);
|
|
4075
|
+
}
|
|
4076
|
+
continue;
|
|
4077
|
+
}
|
|
4078
|
+
if (child.type === "typealias_declaration") {
|
|
4079
|
+
const name = extractIdentifier(findNamedChild(child, "type_identifier"));
|
|
4080
|
+
if (!name) {
|
|
4081
|
+
continue;
|
|
4082
|
+
}
|
|
4083
|
+
const exported = swiftExported(child);
|
|
4084
|
+
draftSymbols.push({
|
|
4085
|
+
name,
|
|
4086
|
+
kind: "type_alias",
|
|
4087
|
+
signature: singleLineSignature(child.text),
|
|
4088
|
+
exported,
|
|
4089
|
+
callNames: [],
|
|
4090
|
+
extendsNames: [],
|
|
4091
|
+
implementsNames: [],
|
|
4092
|
+
bodyText: child.text
|
|
4093
|
+
});
|
|
4094
|
+
if (exported) {
|
|
4095
|
+
exportLabels.push(name);
|
|
4096
|
+
}
|
|
4097
|
+
continue;
|
|
4098
|
+
}
|
|
4099
|
+
if (child.type === "function_declaration") {
|
|
4100
|
+
const name = extractIdentifier(findNamedChild(child, "simple_identifier") ?? findNamedChild(child, "identifier"));
|
|
4101
|
+
if (!name) {
|
|
4102
|
+
continue;
|
|
4103
|
+
}
|
|
4104
|
+
const exported = swiftExported(child);
|
|
4105
|
+
draftSymbols.push({
|
|
4106
|
+
name,
|
|
4107
|
+
kind: "function",
|
|
4108
|
+
signature: singleLineSignature(child.text),
|
|
4109
|
+
exported,
|
|
4110
|
+
callNames: [],
|
|
4111
|
+
extendsNames: [],
|
|
4112
|
+
implementsNames: [],
|
|
4113
|
+
bodyText: nodeText(findNamedChild(child, "function_body")) || child.text
|
|
4114
|
+
});
|
|
4115
|
+
if (exported) {
|
|
4116
|
+
exportLabels.push(name);
|
|
4117
|
+
}
|
|
4118
|
+
continue;
|
|
4119
|
+
}
|
|
4120
|
+
if (child.type === "property_declaration") {
|
|
4121
|
+
const exported = swiftExported(child);
|
|
4122
|
+
const patterns = child.namedChildren.filter((item) => item?.type === "pattern");
|
|
4123
|
+
for (const pattern of patterns) {
|
|
4124
|
+
const name = extractIdentifier(findNamedChild(pattern, "simple_identifier") ?? pattern.namedChildren[0] ?? null);
|
|
4125
|
+
if (!name) {
|
|
4126
|
+
continue;
|
|
4127
|
+
}
|
|
4128
|
+
draftSymbols.push({
|
|
4129
|
+
name,
|
|
4130
|
+
kind: "variable",
|
|
4131
|
+
signature: singleLineSignature(child.text),
|
|
4132
|
+
exported,
|
|
4133
|
+
callNames: [],
|
|
4134
|
+
extendsNames: [],
|
|
4135
|
+
implementsNames: [],
|
|
4136
|
+
bodyText: child.text
|
|
4137
|
+
});
|
|
4138
|
+
if (exported) {
|
|
4139
|
+
exportLabels.push(name);
|
|
4140
|
+
}
|
|
4141
|
+
}
|
|
4142
|
+
}
|
|
4143
|
+
}
|
|
4144
|
+
return finalizeCodeAnalysis(manifest, "swift", imports, draftSymbols, exportLabels, diagnostics);
|
|
4145
|
+
}
|
|
4146
|
+
function elixirCallIdentifier(callNode) {
|
|
4147
|
+
return findNamedChild(callNode, "identifier")?.text.trim() || void 0;
|
|
4148
|
+
}
|
|
4149
|
+
function elixirFirstModulePath(argumentsNode) {
|
|
4150
|
+
if (!argumentsNode) {
|
|
4151
|
+
return void 0;
|
|
4152
|
+
}
|
|
4153
|
+
for (const child of argumentsNode.namedChildren) {
|
|
4154
|
+
if (!child) {
|
|
4155
|
+
continue;
|
|
4156
|
+
}
|
|
4157
|
+
if (child.type === "alias" || child.type === "identifier") {
|
|
4158
|
+
const text = child.text.trim();
|
|
4159
|
+
if (text) {
|
|
4160
|
+
return text;
|
|
4161
|
+
}
|
|
4162
|
+
}
|
|
4163
|
+
}
|
|
4164
|
+
return void 0;
|
|
4165
|
+
}
|
|
4166
|
+
function elixirFunctionNameFromArguments(argumentsNode) {
|
|
4167
|
+
if (!argumentsNode) {
|
|
4168
|
+
return void 0;
|
|
4169
|
+
}
|
|
4170
|
+
const first = argumentsNode.namedChildren.find((item) => item !== null);
|
|
4171
|
+
if (!first) {
|
|
4172
|
+
return void 0;
|
|
4173
|
+
}
|
|
4174
|
+
if (first.type === "call") {
|
|
4175
|
+
const inner = findNamedChild(first, "identifier");
|
|
4176
|
+
return inner?.text.trim() || void 0;
|
|
4177
|
+
}
|
|
4178
|
+
if (first.type === "identifier") {
|
|
4179
|
+
return first.text.trim() || void 0;
|
|
4180
|
+
}
|
|
4181
|
+
return void 0;
|
|
4182
|
+
}
|
|
4183
|
+
var ELIXIR_IMPORT_MACROS = /* @__PURE__ */ new Set(["alias", "import", "require", "use"]);
|
|
4184
|
+
var ELIXIR_PUBLIC_DEF_MACROS = /* @__PURE__ */ new Set(["def", "defmacro"]);
|
|
4185
|
+
var ELIXIR_PRIVATE_DEF_MACROS = /* @__PURE__ */ new Set(["defp", "defmacrop"]);
|
|
4186
|
+
function elixirCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
4187
|
+
const imports = [];
|
|
4188
|
+
const draftSymbols = [];
|
|
4189
|
+
const exportLabels = [];
|
|
4190
|
+
let primaryModuleName;
|
|
4191
|
+
for (const topCall of rootNode.namedChildren) {
|
|
4192
|
+
if (!topCall || topCall.type !== "call") {
|
|
4193
|
+
continue;
|
|
4194
|
+
}
|
|
4195
|
+
const macroName = elixirCallIdentifier(topCall);
|
|
4196
|
+
if (macroName !== "defmodule" && macroName !== "defprotocol") {
|
|
4197
|
+
continue;
|
|
4198
|
+
}
|
|
4199
|
+
const moduleArgs = findNamedChild(topCall, "arguments");
|
|
4200
|
+
const moduleName = elixirFirstModulePath(moduleArgs);
|
|
4201
|
+
if (!moduleName) {
|
|
4202
|
+
continue;
|
|
4203
|
+
}
|
|
4204
|
+
const moduleKind = macroName === "defprotocol" ? "interface" : "class";
|
|
4205
|
+
const moduleHeaderLine = topCall.text.split("\n")[0] ?? topCall.text;
|
|
4206
|
+
if (primaryModuleName === void 0) {
|
|
4207
|
+
primaryModuleName = moduleName;
|
|
4208
|
+
}
|
|
4209
|
+
draftSymbols.push({
|
|
4210
|
+
name: moduleName,
|
|
4211
|
+
kind: moduleKind,
|
|
4212
|
+
signature: singleLineSignature(moduleHeaderLine),
|
|
4213
|
+
// Modules and protocols are always module-level public in Elixir.
|
|
4214
|
+
exported: true,
|
|
4215
|
+
callNames: [],
|
|
4216
|
+
extendsNames: [],
|
|
4217
|
+
implementsNames: [],
|
|
4218
|
+
bodyText: topCall.text
|
|
4219
|
+
});
|
|
4220
|
+
exportLabels.push(moduleName);
|
|
4221
|
+
const doBlock = findNamedChild(topCall, "do_block");
|
|
4222
|
+
if (!doBlock) {
|
|
4223
|
+
continue;
|
|
4224
|
+
}
|
|
4225
|
+
for (const innerNode of doBlock.namedChildren) {
|
|
4226
|
+
if (!innerNode || innerNode.type !== "call") {
|
|
4227
|
+
continue;
|
|
4228
|
+
}
|
|
4229
|
+
const innerMacro = elixirCallIdentifier(innerNode);
|
|
4230
|
+
if (!innerMacro) {
|
|
4231
|
+
continue;
|
|
4232
|
+
}
|
|
4233
|
+
if (ELIXIR_IMPORT_MACROS.has(innerMacro)) {
|
|
4234
|
+
const importArgs = findNamedChild(innerNode, "arguments");
|
|
4235
|
+
const modulePath = elixirFirstModulePath(importArgs);
|
|
4236
|
+
if (!modulePath) {
|
|
4237
|
+
continue;
|
|
4238
|
+
}
|
|
4239
|
+
imports.push({
|
|
4240
|
+
specifier: modulePath,
|
|
4241
|
+
importedSymbols: [],
|
|
4242
|
+
// Elixir imports always target a compiled BEAM module; there is no
|
|
4243
|
+
// notion of "file-local" relative imports the way Python or JS use them.
|
|
4244
|
+
// Treat every entry as external.
|
|
4245
|
+
isExternal: true,
|
|
4246
|
+
reExport: false
|
|
4247
|
+
});
|
|
4248
|
+
continue;
|
|
4249
|
+
}
|
|
4250
|
+
if (ELIXIR_PUBLIC_DEF_MACROS.has(innerMacro) || ELIXIR_PRIVATE_DEF_MACROS.has(innerMacro)) {
|
|
4251
|
+
const innerArgs = findNamedChild(innerNode, "arguments");
|
|
4252
|
+
const fnName = elixirFunctionNameFromArguments(innerArgs);
|
|
4253
|
+
if (!fnName) {
|
|
4254
|
+
continue;
|
|
4255
|
+
}
|
|
4256
|
+
const qualifiedName = `${moduleName}.${fnName}`;
|
|
4257
|
+
const exported = ELIXIR_PUBLIC_DEF_MACROS.has(innerMacro);
|
|
4258
|
+
const headerLine = innerNode.text.split("\n")[0] ?? innerNode.text;
|
|
4259
|
+
draftSymbols.push({
|
|
4260
|
+
name: qualifiedName,
|
|
4261
|
+
kind: "function",
|
|
4262
|
+
signature: singleLineSignature(headerLine),
|
|
4263
|
+
exported,
|
|
4264
|
+
callNames: [],
|
|
4265
|
+
extendsNames: [],
|
|
4266
|
+
implementsNames: [],
|
|
4267
|
+
bodyText: nodeText(findNamedChild(innerNode, "do_block")) || innerNode.text
|
|
4268
|
+
});
|
|
4269
|
+
if (exported) {
|
|
4270
|
+
exportLabels.push(qualifiedName);
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
}
|
|
4274
|
+
}
|
|
4275
|
+
return finalizeCodeAnalysis(manifest, "elixir", imports, draftSymbols, exportLabels, diagnostics, {
|
|
4276
|
+
moduleName: primaryModuleName
|
|
4277
|
+
});
|
|
4278
|
+
}
|
|
4279
|
+
function parseOCamlOpen(node) {
|
|
4280
|
+
const modulePath = findNamedChild(node, "module_path");
|
|
4281
|
+
if (!modulePath) {
|
|
4282
|
+
return void 0;
|
|
4283
|
+
}
|
|
4284
|
+
const specifier = modulePath.text.trim();
|
|
4285
|
+
if (!specifier) {
|
|
4286
|
+
return void 0;
|
|
4287
|
+
}
|
|
4288
|
+
return {
|
|
4289
|
+
specifier,
|
|
4290
|
+
importedSymbols: [],
|
|
4291
|
+
// Every OCaml `open` references a compiled module; there is no file-local
|
|
4292
|
+
// "./sibling" form. Classify as external and let resolveCodeImport's single-
|
|
4293
|
+
// candidate short-circuit promote it to local when an alias matches.
|
|
4294
|
+
isExternal: true,
|
|
4295
|
+
reExport: false
|
|
4296
|
+
};
|
|
4297
|
+
}
|
|
4298
|
+
function ocamlValueBindingKind(letBinding) {
|
|
4299
|
+
if (!letBinding) {
|
|
4300
|
+
return void 0;
|
|
4301
|
+
}
|
|
4302
|
+
const hasParameter = letBinding.namedChildren.some((child) => child?.type === "parameter");
|
|
4303
|
+
return hasParameter ? "function" : "variable";
|
|
4304
|
+
}
|
|
4305
|
+
function ocamlTypeKind(typeBinding) {
|
|
4306
|
+
if (!typeBinding) {
|
|
4307
|
+
return "type_alias";
|
|
4308
|
+
}
|
|
4309
|
+
for (const child of typeBinding.namedChildren) {
|
|
4310
|
+
if (!child) {
|
|
4311
|
+
continue;
|
|
4312
|
+
}
|
|
4313
|
+
if (child.type === "record_declaration") {
|
|
4314
|
+
return "struct";
|
|
4315
|
+
}
|
|
4316
|
+
if (child.type === "variant_declaration") {
|
|
4317
|
+
return "enum";
|
|
4318
|
+
}
|
|
4319
|
+
}
|
|
4320
|
+
return "type_alias";
|
|
4321
|
+
}
|
|
4322
|
+
function ocamlCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
4323
|
+
const imports = [];
|
|
4324
|
+
const draftSymbols = [];
|
|
4325
|
+
const exportLabels = [];
|
|
4326
|
+
for (const child of rootNode.namedChildren) {
|
|
4327
|
+
if (!child) {
|
|
4328
|
+
continue;
|
|
4329
|
+
}
|
|
4330
|
+
if (child.type === "open_module") {
|
|
4331
|
+
const parsed = parseOCamlOpen(child);
|
|
4332
|
+
if (parsed) {
|
|
4333
|
+
imports.push(parsed);
|
|
4334
|
+
}
|
|
4335
|
+
continue;
|
|
4336
|
+
}
|
|
4337
|
+
if (child.type === "module_definition") {
|
|
4338
|
+
const binding = findNamedChild(child, "module_binding");
|
|
4339
|
+
const moduleNameNode = binding ? findNamedChild(binding, "module_name") : null;
|
|
4340
|
+
const name = moduleNameNode?.text.trim();
|
|
4341
|
+
if (!name) {
|
|
4342
|
+
continue;
|
|
4343
|
+
}
|
|
4344
|
+
draftSymbols.push({
|
|
4345
|
+
name,
|
|
4346
|
+
kind: "class",
|
|
4347
|
+
signature: singleLineSignature(child.text.split("\n")[0] ?? child.text),
|
|
4348
|
+
// OCaml's `let`/`module` bindings are exported from the containing
|
|
4349
|
+
// compilation unit unless an explicit `.mli` interface hides them.
|
|
4350
|
+
// Treat everything defined in a `.ml` file as exported; consumers who
|
|
4351
|
+
// want hiding should rely on the downstream interface-file merge.
|
|
4352
|
+
exported: true,
|
|
4353
|
+
callNames: [],
|
|
4354
|
+
extendsNames: [],
|
|
4355
|
+
implementsNames: [],
|
|
4356
|
+
bodyText: nodeText(findNamedChild(binding, "structure")) || child.text
|
|
4357
|
+
});
|
|
4358
|
+
exportLabels.push(name);
|
|
4359
|
+
continue;
|
|
4360
|
+
}
|
|
4361
|
+
if (child.type === "module_type_definition") {
|
|
4362
|
+
const nameNode = findNamedChild(child, "module_type_name");
|
|
4363
|
+
const name = nameNode?.text.trim();
|
|
4364
|
+
if (!name) {
|
|
4365
|
+
continue;
|
|
4366
|
+
}
|
|
4367
|
+
draftSymbols.push({
|
|
4368
|
+
name,
|
|
4369
|
+
kind: "interface",
|
|
4370
|
+
signature: singleLineSignature(child.text.split("\n")[0] ?? child.text),
|
|
4371
|
+
exported: true,
|
|
4372
|
+
callNames: [],
|
|
4373
|
+
extendsNames: [],
|
|
4374
|
+
implementsNames: [],
|
|
4375
|
+
bodyText: nodeText(findNamedChild(child, "signature")) || child.text
|
|
4376
|
+
});
|
|
4377
|
+
exportLabels.push(name);
|
|
4378
|
+
continue;
|
|
4379
|
+
}
|
|
4380
|
+
if (child.type === "type_definition") {
|
|
4381
|
+
const binding = findNamedChild(child, "type_binding");
|
|
4382
|
+
const typeConstructorNode = binding ? findNamedChild(binding, "type_constructor") : null;
|
|
4383
|
+
const name = typeConstructorNode?.text.trim();
|
|
4384
|
+
if (!name) {
|
|
4385
|
+
continue;
|
|
4386
|
+
}
|
|
4387
|
+
const kind = ocamlTypeKind(binding);
|
|
4388
|
+
draftSymbols.push({
|
|
4389
|
+
name,
|
|
4390
|
+
kind,
|
|
4391
|
+
signature: singleLineSignature(child.text.split("\n")[0] ?? child.text),
|
|
4392
|
+
exported: true,
|
|
4393
|
+
callNames: [],
|
|
4394
|
+
extendsNames: [],
|
|
4395
|
+
implementsNames: [],
|
|
4396
|
+
bodyText: child.text
|
|
4397
|
+
});
|
|
4398
|
+
exportLabels.push(name);
|
|
4399
|
+
continue;
|
|
4400
|
+
}
|
|
4401
|
+
if (child.type === "value_definition") {
|
|
4402
|
+
const binding = findNamedChild(child, "let_binding");
|
|
4403
|
+
if (!binding) {
|
|
4404
|
+
continue;
|
|
4405
|
+
}
|
|
4406
|
+
const valueNameNode = findNamedChild(binding, "value_name");
|
|
4407
|
+
const name = valueNameNode?.text.trim();
|
|
4408
|
+
if (!name) {
|
|
4409
|
+
continue;
|
|
4410
|
+
}
|
|
4411
|
+
const kind = ocamlValueBindingKind(binding) ?? "function";
|
|
4412
|
+
draftSymbols.push({
|
|
4413
|
+
name,
|
|
4414
|
+
kind,
|
|
4415
|
+
signature: singleLineSignature(child.text.split("\n")[0] ?? child.text),
|
|
4416
|
+
exported: true,
|
|
4417
|
+
callNames: [],
|
|
4418
|
+
extendsNames: [],
|
|
4419
|
+
implementsNames: [],
|
|
4420
|
+
bodyText: child.text
|
|
4421
|
+
});
|
|
4422
|
+
exportLabels.push(name);
|
|
4423
|
+
}
|
|
4424
|
+
}
|
|
4425
|
+
return finalizeCodeAnalysis(manifest, "ocaml", imports, draftSymbols, exportLabels, diagnostics);
|
|
4426
|
+
}
|
|
4427
|
+
function objcCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
4428
|
+
const imports = [];
|
|
4429
|
+
const draftSymbols = [];
|
|
4430
|
+
const exportLabels = [];
|
|
4431
|
+
const declaredClassNames = /* @__PURE__ */ new Set();
|
|
4432
|
+
const functionNameFromDeclarator = (node) => {
|
|
4433
|
+
if (!node) {
|
|
4434
|
+
return void 0;
|
|
4435
|
+
}
|
|
4436
|
+
const declarator = node.childForFieldName("declarator");
|
|
4437
|
+
if (declarator) {
|
|
4438
|
+
return functionNameFromDeclarator(declarator);
|
|
4439
|
+
}
|
|
4440
|
+
return extractIdentifier(node);
|
|
4441
|
+
};
|
|
4442
|
+
for (const child of rootNode.namedChildren) {
|
|
4443
|
+
if (!child) {
|
|
4444
|
+
continue;
|
|
4445
|
+
}
|
|
4446
|
+
if (child.type === "preproc_include") {
|
|
4447
|
+
const parsed = parseCppInclude(child);
|
|
4448
|
+
if (parsed) {
|
|
4449
|
+
imports.push(parsed);
|
|
4450
|
+
}
|
|
4451
|
+
continue;
|
|
4452
|
+
}
|
|
4453
|
+
if (child.type === "protocol_declaration") {
|
|
4454
|
+
const nameNode = findNamedChild(child, "identifier");
|
|
4455
|
+
const name = nameNode?.text.trim();
|
|
4456
|
+
if (!name) {
|
|
4457
|
+
continue;
|
|
4458
|
+
}
|
|
4459
|
+
const refList = findNamedChild(child, "protocol_reference_list");
|
|
4460
|
+
const parents = refList ? uniqueBy(
|
|
4461
|
+
refList.namedChildren.filter((item) => item?.type === "identifier").map((item) => item.text.trim()).filter(Boolean),
|
|
4462
|
+
(item) => item
|
|
4463
|
+
) : [];
|
|
4464
|
+
draftSymbols.push({
|
|
4465
|
+
name,
|
|
4466
|
+
kind: "interface",
|
|
4467
|
+
signature: singleLineSignature(child.text.split("\n")[0] ?? child.text),
|
|
4468
|
+
exported: true,
|
|
4469
|
+
callNames: [],
|
|
4470
|
+
extendsNames: parents,
|
|
4471
|
+
implementsNames: [],
|
|
4472
|
+
bodyText: child.text
|
|
4473
|
+
});
|
|
4474
|
+
exportLabels.push(name);
|
|
4475
|
+
continue;
|
|
4476
|
+
}
|
|
4477
|
+
if (child.type === "class_interface") {
|
|
4478
|
+
const identifierChildren = child.namedChildren.filter((item) => item?.type === "identifier");
|
|
4479
|
+
const name = identifierChildren[0]?.text.trim();
|
|
4480
|
+
if (!name) {
|
|
4481
|
+
continue;
|
|
4482
|
+
}
|
|
4483
|
+
const superclass = identifierChildren[1]?.text.trim();
|
|
4484
|
+
const parameterized = findNamedChild(child, "parameterized_arguments");
|
|
4485
|
+
const protocols = parameterized ? uniqueBy(
|
|
4486
|
+
parameterized.namedChildren.filter((item) => item?.type === "type_name" || item?.type === "identifier").map((item) => item.text.trim()).filter(Boolean),
|
|
4487
|
+
(item) => item
|
|
4488
|
+
) : [];
|
|
4489
|
+
declaredClassNames.add(name);
|
|
4490
|
+
draftSymbols.push({
|
|
4491
|
+
name,
|
|
4492
|
+
kind: "class",
|
|
4493
|
+
signature: singleLineSignature(child.text.split("\n")[0] ?? child.text),
|
|
4494
|
+
exported: true,
|
|
4495
|
+
callNames: [],
|
|
4496
|
+
extendsNames: superclass ? [superclass] : [],
|
|
4497
|
+
implementsNames: protocols,
|
|
4498
|
+
bodyText: child.text
|
|
4499
|
+
});
|
|
4500
|
+
exportLabels.push(name);
|
|
4501
|
+
continue;
|
|
4502
|
+
}
|
|
4503
|
+
if (child.type === "class_implementation") {
|
|
4504
|
+
const nameNode = findNamedChild(child, "identifier");
|
|
4505
|
+
const name = nameNode?.text.trim();
|
|
4506
|
+
if (!name) {
|
|
4507
|
+
continue;
|
|
4508
|
+
}
|
|
4509
|
+
if (declaredClassNames.has(name)) {
|
|
4510
|
+
continue;
|
|
4511
|
+
}
|
|
4512
|
+
declaredClassNames.add(name);
|
|
4513
|
+
draftSymbols.push({
|
|
4514
|
+
name,
|
|
4515
|
+
kind: "class",
|
|
4516
|
+
signature: singleLineSignature(child.text.split("\n")[0] ?? child.text),
|
|
4517
|
+
exported: true,
|
|
4518
|
+
callNames: [],
|
|
4519
|
+
extendsNames: [],
|
|
4520
|
+
implementsNames: [],
|
|
4521
|
+
bodyText: child.text
|
|
4522
|
+
});
|
|
4523
|
+
exportLabels.push(name);
|
|
4524
|
+
continue;
|
|
4525
|
+
}
|
|
4526
|
+
if (child.type === "function_definition") {
|
|
4527
|
+
const name = functionNameFromDeclarator(child.childForFieldName("declarator"));
|
|
4528
|
+
if (!name) {
|
|
4529
|
+
continue;
|
|
4530
|
+
}
|
|
4531
|
+
draftSymbols.push({
|
|
4532
|
+
name,
|
|
4533
|
+
kind: "function",
|
|
4534
|
+
signature: singleLineSignature(child.text.split("\n")[0] ?? child.text),
|
|
4535
|
+
exported: true,
|
|
4536
|
+
callNames: [],
|
|
4537
|
+
extendsNames: [],
|
|
4538
|
+
implementsNames: [],
|
|
4539
|
+
bodyText: nodeText(child.childForFieldName("body")) || child.text
|
|
4540
|
+
});
|
|
4541
|
+
exportLabels.push(name);
|
|
4542
|
+
}
|
|
4543
|
+
}
|
|
4544
|
+
return finalizeCodeAnalysis(manifest, "objc", imports, draftSymbols, exportLabels, diagnostics);
|
|
4545
|
+
}
|
|
4546
|
+
function rescriptCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
4547
|
+
const imports = [];
|
|
4548
|
+
const draftSymbols = [];
|
|
4549
|
+
const exportLabels = [];
|
|
4550
|
+
const rescriptTypeKind = (typeBinding) => {
|
|
4551
|
+
if (!typeBinding) {
|
|
4552
|
+
return "type_alias";
|
|
4553
|
+
}
|
|
4554
|
+
for (const child of typeBinding.namedChildren) {
|
|
4555
|
+
if (!child) {
|
|
4556
|
+
continue;
|
|
4557
|
+
}
|
|
4558
|
+
if (child.type === "variant_type") {
|
|
4559
|
+
return "enum";
|
|
4560
|
+
}
|
|
4561
|
+
if (child.type === "record_type") {
|
|
4562
|
+
return "struct";
|
|
4563
|
+
}
|
|
4564
|
+
}
|
|
4565
|
+
return "type_alias";
|
|
4566
|
+
};
|
|
4567
|
+
const rescriptLetBindingKind = (letBinding) => {
|
|
4568
|
+
if (!letBinding) {
|
|
4569
|
+
return "variable";
|
|
4570
|
+
}
|
|
4571
|
+
for (const child of letBinding.namedChildren) {
|
|
4572
|
+
if (child?.type === "function") {
|
|
4573
|
+
return "function";
|
|
4574
|
+
}
|
|
4575
|
+
}
|
|
4576
|
+
return "variable";
|
|
4577
|
+
};
|
|
4578
|
+
for (const child of rootNode.namedChildren) {
|
|
4579
|
+
if (!child) {
|
|
4580
|
+
continue;
|
|
4581
|
+
}
|
|
4582
|
+
if (child.type === "open_statement") {
|
|
4583
|
+
const identNode = findNamedChild(child, "module_identifier");
|
|
4584
|
+
const specifier = identNode?.text.trim();
|
|
4585
|
+
if (!specifier) {
|
|
4586
|
+
continue;
|
|
4587
|
+
}
|
|
4588
|
+
imports.push({
|
|
4589
|
+
specifier,
|
|
4590
|
+
importedSymbols: [],
|
|
4591
|
+
// ReScript modules resolve through the build system's own module graph;
|
|
4592
|
+
// they are never file-local in the Python "./relative" sense.
|
|
4593
|
+
isExternal: true,
|
|
4594
|
+
reExport: false
|
|
4595
|
+
});
|
|
4596
|
+
continue;
|
|
4597
|
+
}
|
|
4598
|
+
if (child.type === "module_declaration") {
|
|
4599
|
+
const binding = findNamedChild(child, "module_binding");
|
|
4600
|
+
const nameNode = binding ? findNamedChild(binding, "module_identifier") : null;
|
|
4601
|
+
const name = nameNode?.text.trim();
|
|
4602
|
+
if (!name) {
|
|
4603
|
+
continue;
|
|
4604
|
+
}
|
|
4605
|
+
draftSymbols.push({
|
|
4606
|
+
name,
|
|
4607
|
+
kind: "class",
|
|
4608
|
+
signature: singleLineSignature(child.text.split("\n")[0] ?? child.text),
|
|
4609
|
+
exported: true,
|
|
4610
|
+
callNames: [],
|
|
4611
|
+
extendsNames: [],
|
|
4612
|
+
implementsNames: [],
|
|
4613
|
+
bodyText: nodeText(findNamedChild(binding, "block")) || child.text
|
|
4614
|
+
});
|
|
4615
|
+
exportLabels.push(name);
|
|
4616
|
+
continue;
|
|
4617
|
+
}
|
|
4618
|
+
if (child.type === "type_declaration") {
|
|
4619
|
+
const binding = findNamedChild(child, "type_binding");
|
|
4620
|
+
const nameNode = binding ? findNamedChild(binding, "type_identifier") : null;
|
|
4621
|
+
const name = nameNode?.text.trim();
|
|
4622
|
+
if (!name) {
|
|
4623
|
+
continue;
|
|
4624
|
+
}
|
|
4625
|
+
const kind = rescriptTypeKind(binding);
|
|
4626
|
+
draftSymbols.push({
|
|
4627
|
+
name,
|
|
4628
|
+
kind,
|
|
4629
|
+
signature: singleLineSignature(child.text.split("\n")[0] ?? child.text),
|
|
4630
|
+
exported: true,
|
|
4631
|
+
callNames: [],
|
|
4632
|
+
extendsNames: [],
|
|
4633
|
+
implementsNames: [],
|
|
4634
|
+
bodyText: child.text
|
|
4635
|
+
});
|
|
4636
|
+
exportLabels.push(name);
|
|
4637
|
+
continue;
|
|
4638
|
+
}
|
|
4639
|
+
if (child.type === "let_declaration") {
|
|
4640
|
+
const binding = findNamedChild(child, "let_binding");
|
|
4641
|
+
const nameNode = binding ? findNamedChild(binding, "value_identifier") : null;
|
|
4642
|
+
const name = nameNode?.text.trim();
|
|
4643
|
+
if (!name) {
|
|
4644
|
+
continue;
|
|
4645
|
+
}
|
|
4646
|
+
const kind = rescriptLetBindingKind(binding);
|
|
4647
|
+
draftSymbols.push({
|
|
4648
|
+
name,
|
|
4649
|
+
kind,
|
|
4650
|
+
signature: singleLineSignature(child.text.split("\n")[0] ?? child.text),
|
|
4651
|
+
exported: true,
|
|
4652
|
+
callNames: [],
|
|
4653
|
+
extendsNames: [],
|
|
4654
|
+
implementsNames: [],
|
|
4655
|
+
bodyText: child.text
|
|
4656
|
+
});
|
|
4657
|
+
exportLabels.push(name);
|
|
4658
|
+
}
|
|
4659
|
+
}
|
|
4660
|
+
return finalizeCodeAnalysis(manifest, "rescript", imports, draftSymbols, exportLabels, diagnostics);
|
|
4661
|
+
}
|
|
4662
|
+
function parseSolidityImport(node) {
|
|
4663
|
+
const stringNode = node.namedChildren.find((item) => item?.type === "string");
|
|
4664
|
+
if (!stringNode) {
|
|
4665
|
+
return [];
|
|
4666
|
+
}
|
|
4667
|
+
const specifier = quotedPath(stringNode.text);
|
|
4668
|
+
if (!specifier) {
|
|
4669
|
+
return [];
|
|
4670
|
+
}
|
|
4671
|
+
const importedSymbols = uniqueBy(
|
|
4672
|
+
node.namedChildren.filter((item) => item?.type === "identifier").map((item) => item.text.trim()).filter(Boolean),
|
|
4673
|
+
(item) => item
|
|
4674
|
+
);
|
|
4675
|
+
const isLocal = specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith("/");
|
|
4676
|
+
return [
|
|
4677
|
+
{
|
|
4678
|
+
specifier,
|
|
4679
|
+
importedSymbols,
|
|
4680
|
+
isExternal: !isLocal,
|
|
4681
|
+
reExport: false
|
|
4682
|
+
}
|
|
4683
|
+
];
|
|
4684
|
+
}
|
|
4685
|
+
function solidityCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
4686
|
+
const imports = [];
|
|
4687
|
+
const draftSymbols = [];
|
|
4688
|
+
const exportLabels = [];
|
|
4689
|
+
const collectParents = (declaration) => {
|
|
4690
|
+
const specifiers = declaration.namedChildren.filter((item) => item?.type === "inheritance_specifier");
|
|
4691
|
+
const names = [];
|
|
4692
|
+
for (const specifier of specifiers) {
|
|
4693
|
+
for (const node of specifier.namedChildren) {
|
|
4694
|
+
if (node && (node.type === "user_defined_type" || node.type === "identifier")) {
|
|
4695
|
+
const text = normalizeSymbolReference(node.text);
|
|
4696
|
+
if (text) {
|
|
4697
|
+
names.push(text);
|
|
4698
|
+
}
|
|
4699
|
+
}
|
|
4700
|
+
}
|
|
4701
|
+
}
|
|
4702
|
+
return uniqueBy(names, (item) => item);
|
|
4703
|
+
};
|
|
4704
|
+
for (const child of rootNode.namedChildren) {
|
|
4705
|
+
if (!child) {
|
|
4706
|
+
continue;
|
|
4707
|
+
}
|
|
4708
|
+
if (child.type === "import_directive") {
|
|
4709
|
+
for (const parsed of parseSolidityImport(child)) {
|
|
4710
|
+
imports.push(parsed);
|
|
4711
|
+
}
|
|
4712
|
+
continue;
|
|
4713
|
+
}
|
|
4714
|
+
if (child.type === "interface_declaration") {
|
|
4715
|
+
const nameNode = findNamedChild(child, "identifier");
|
|
4716
|
+
const name = nameNode?.text.trim();
|
|
4717
|
+
if (!name) {
|
|
4718
|
+
continue;
|
|
4719
|
+
}
|
|
4720
|
+
const parents = collectParents(child);
|
|
4721
|
+
draftSymbols.push({
|
|
4722
|
+
name,
|
|
4723
|
+
kind: "interface",
|
|
4724
|
+
signature: singleLineSignature(child.text.split("\n")[0] ?? child.text),
|
|
4725
|
+
exported: true,
|
|
4726
|
+
callNames: [],
|
|
4727
|
+
extendsNames: parents,
|
|
4728
|
+
implementsNames: [],
|
|
4729
|
+
bodyText: nodeText(findNamedChild(child, "contract_body")) || child.text
|
|
4730
|
+
});
|
|
4731
|
+
exportLabels.push(name);
|
|
4732
|
+
continue;
|
|
4733
|
+
}
|
|
4734
|
+
if (child.type === "library_declaration" || child.type === "contract_declaration") {
|
|
4735
|
+
const nameNode = findNamedChild(child, "identifier");
|
|
4736
|
+
const name = nameNode?.text.trim();
|
|
4737
|
+
if (!name) {
|
|
4738
|
+
continue;
|
|
4739
|
+
}
|
|
4740
|
+
const parents = child.type === "contract_declaration" ? collectParents(child) : [];
|
|
4741
|
+
draftSymbols.push({
|
|
4742
|
+
name,
|
|
4743
|
+
kind: "class",
|
|
4744
|
+
signature: singleLineSignature(child.text.split("\n")[0] ?? child.text),
|
|
4745
|
+
exported: true,
|
|
4746
|
+
callNames: [],
|
|
4747
|
+
extendsNames: [],
|
|
4748
|
+
// Solidity supports multiple inheritance; list every parent contract
|
|
4749
|
+
// as a `implements` edge rather than arbitrarily promoting one to
|
|
4750
|
+
// `extends`.
|
|
4751
|
+
implementsNames: parents,
|
|
4752
|
+
bodyText: nodeText(findNamedChild(child, "contract_body")) || child.text
|
|
4753
|
+
});
|
|
4754
|
+
exportLabels.push(name);
|
|
4755
|
+
continue;
|
|
4756
|
+
}
|
|
4757
|
+
if (child.type === "struct_declaration") {
|
|
4758
|
+
const nameNode = findNamedChild(child, "identifier");
|
|
4759
|
+
const name = nameNode?.text.trim();
|
|
4760
|
+
if (!name) {
|
|
4761
|
+
continue;
|
|
4762
|
+
}
|
|
4763
|
+
draftSymbols.push({
|
|
4764
|
+
name,
|
|
4765
|
+
kind: "struct",
|
|
4766
|
+
signature: singleLineSignature(child.text.split("\n")[0] ?? child.text),
|
|
4767
|
+
exported: true,
|
|
4768
|
+
callNames: [],
|
|
4769
|
+
extendsNames: [],
|
|
4770
|
+
implementsNames: [],
|
|
4771
|
+
bodyText: child.text
|
|
4772
|
+
});
|
|
4773
|
+
exportLabels.push(name);
|
|
4774
|
+
continue;
|
|
4775
|
+
}
|
|
4776
|
+
if (child.type === "enum_declaration") {
|
|
4777
|
+
const nameNode = findNamedChild(child, "identifier");
|
|
4778
|
+
const name = nameNode?.text.trim();
|
|
4779
|
+
if (!name) {
|
|
4780
|
+
continue;
|
|
4781
|
+
}
|
|
4782
|
+
draftSymbols.push({
|
|
4783
|
+
name,
|
|
4784
|
+
kind: "enum",
|
|
4785
|
+
signature: singleLineSignature(child.text.split("\n")[0] ?? child.text),
|
|
4786
|
+
exported: true,
|
|
4787
|
+
callNames: [],
|
|
4788
|
+
extendsNames: [],
|
|
4789
|
+
implementsNames: [],
|
|
4790
|
+
bodyText: child.text
|
|
4791
|
+
});
|
|
4792
|
+
exportLabels.push(name);
|
|
4793
|
+
continue;
|
|
4794
|
+
}
|
|
4795
|
+
if (child.type === "function_definition") {
|
|
4796
|
+
const nameNode = findNamedChild(child, "identifier");
|
|
4797
|
+
const name = nameNode?.text.trim();
|
|
4798
|
+
if (!name) {
|
|
4799
|
+
continue;
|
|
4800
|
+
}
|
|
4801
|
+
draftSymbols.push({
|
|
4802
|
+
name,
|
|
4803
|
+
kind: "function",
|
|
4804
|
+
signature: singleLineSignature(child.text.split("\n")[0] ?? child.text),
|
|
4805
|
+
exported: true,
|
|
4806
|
+
callNames: [],
|
|
4807
|
+
extendsNames: [],
|
|
4808
|
+
implementsNames: [],
|
|
4809
|
+
bodyText: nodeText(findNamedChild(child, "function_body")) || child.text
|
|
4810
|
+
});
|
|
4811
|
+
exportLabels.push(name);
|
|
4812
|
+
}
|
|
4813
|
+
}
|
|
4814
|
+
return finalizeCodeAnalysis(manifest, "solidity", imports, draftSymbols, exportLabels, diagnostics);
|
|
4815
|
+
}
|
|
4816
|
+
function htmlAttributeValue(attribute) {
|
|
4817
|
+
const quoted = attribute.namedChildren.find((c) => c?.type === "quoted_attribute_value");
|
|
4818
|
+
if (quoted) {
|
|
4819
|
+
const inner = quoted.namedChildren.find((c) => c?.type === "attribute_value");
|
|
4820
|
+
if (inner) {
|
|
4821
|
+
return inner.text.trim();
|
|
4822
|
+
}
|
|
4823
|
+
const raw = quoted.text;
|
|
4824
|
+
if (raw.length >= 2 && (raw[0] === '"' || raw[0] === "'")) {
|
|
4825
|
+
return raw.slice(1, -1).trim();
|
|
4826
|
+
}
|
|
4827
|
+
return raw.trim();
|
|
4828
|
+
}
|
|
4829
|
+
const bare = attribute.namedChildren.find((c) => c?.type === "attribute_value");
|
|
4830
|
+
return bare?.text.trim();
|
|
4831
|
+
}
|
|
4832
|
+
function htmlAttributesOf(element) {
|
|
4833
|
+
const out = /* @__PURE__ */ new Map();
|
|
4834
|
+
const startTag = findNamedChild(element, "start_tag") ?? findNamedChild(element, "self_closing_tag");
|
|
4835
|
+
if (!startTag) {
|
|
4836
|
+
return out;
|
|
4837
|
+
}
|
|
4838
|
+
for (const child of startTag.namedChildren) {
|
|
4839
|
+
if (!child || child.type !== "attribute") {
|
|
4840
|
+
continue;
|
|
4841
|
+
}
|
|
4842
|
+
const nameNode = findNamedChild(child, "attribute_name");
|
|
4843
|
+
const name = nameNode?.text.trim().toLowerCase();
|
|
4844
|
+
if (!name) {
|
|
4845
|
+
continue;
|
|
4846
|
+
}
|
|
4847
|
+
const value = htmlAttributeValue(child);
|
|
4848
|
+
if (value !== void 0) {
|
|
4849
|
+
out.set(name, value);
|
|
4850
|
+
}
|
|
4851
|
+
}
|
|
4852
|
+
return out;
|
|
4853
|
+
}
|
|
4854
|
+
function htmlTagName(element) {
|
|
4855
|
+
const startTag = findNamedChild(element, "start_tag") ?? findNamedChild(element, "self_closing_tag") ?? null;
|
|
4856
|
+
if (!startTag) {
|
|
4857
|
+
return void 0;
|
|
4858
|
+
}
|
|
4859
|
+
return findNamedChild(startTag, "tag_name")?.text.trim().toLowerCase();
|
|
4860
|
+
}
|
|
4861
|
+
function htmlCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
4862
|
+
const imports = [];
|
|
4863
|
+
const draftSymbols = [];
|
|
4864
|
+
const exportLabels = [];
|
|
4865
|
+
const seenSymbolNames = /* @__PURE__ */ new Set();
|
|
4866
|
+
const isLocalAssetSpecifier = (specifier) => {
|
|
4867
|
+
if (!specifier) {
|
|
4868
|
+
return false;
|
|
4869
|
+
}
|
|
4870
|
+
if (specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith("/")) {
|
|
4871
|
+
return true;
|
|
4872
|
+
}
|
|
4873
|
+
if (specifier.startsWith("http://") || specifier.startsWith("https://") || specifier.startsWith("//")) {
|
|
4874
|
+
return false;
|
|
4875
|
+
}
|
|
4876
|
+
return !specifier.includes(":");
|
|
4877
|
+
};
|
|
4878
|
+
const elements = rootNode.descendantsOfType(["element", "script_element", "style_element"]).filter((item) => item !== null);
|
|
4879
|
+
for (const element of elements) {
|
|
4880
|
+
const attrs = htmlAttributesOf(element);
|
|
4881
|
+
const tagName = htmlTagName(element);
|
|
4882
|
+
if (tagName === "link") {
|
|
4883
|
+
const rel = attrs.get("rel");
|
|
4884
|
+
const href = attrs.get("href");
|
|
4885
|
+
if (rel === "stylesheet" && href) {
|
|
4886
|
+
imports.push({
|
|
4887
|
+
specifier: href,
|
|
4888
|
+
importedSymbols: [],
|
|
4889
|
+
isExternal: !isLocalAssetSpecifier(href),
|
|
4890
|
+
reExport: false
|
|
4891
|
+
});
|
|
4892
|
+
}
|
|
4893
|
+
continue;
|
|
4894
|
+
}
|
|
4895
|
+
if (element.type === "script_element") {
|
|
4896
|
+
const src = attrs.get("src");
|
|
4897
|
+
if (src) {
|
|
4898
|
+
imports.push({
|
|
4899
|
+
specifier: src,
|
|
4900
|
+
importedSymbols: [],
|
|
4901
|
+
isExternal: !isLocalAssetSpecifier(src),
|
|
4902
|
+
reExport: false
|
|
4903
|
+
});
|
|
4904
|
+
}
|
|
4905
|
+
continue;
|
|
4906
|
+
}
|
|
4907
|
+
if (tagName && tagName.includes("-")) {
|
|
4908
|
+
if (!seenSymbolNames.has(tagName)) {
|
|
4909
|
+
seenSymbolNames.add(tagName);
|
|
4910
|
+
draftSymbols.push({
|
|
4911
|
+
name: tagName,
|
|
4912
|
+
kind: "class",
|
|
4913
|
+
signature: singleLineSignature(element.text.split("\n")[0] ?? element.text),
|
|
4914
|
+
exported: true,
|
|
4915
|
+
callNames: [],
|
|
4916
|
+
extendsNames: [],
|
|
4917
|
+
implementsNames: [],
|
|
4918
|
+
bodyText: element.text
|
|
4919
|
+
});
|
|
4920
|
+
exportLabels.push(tagName);
|
|
4921
|
+
}
|
|
4922
|
+
}
|
|
4923
|
+
const id = attrs.get("id");
|
|
4924
|
+
if (id && !seenSymbolNames.has(id)) {
|
|
4925
|
+
seenSymbolNames.add(id);
|
|
4926
|
+
draftSymbols.push({
|
|
4927
|
+
name: id,
|
|
4928
|
+
kind: "variable",
|
|
4929
|
+
signature: singleLineSignature(element.text.split("\n")[0] ?? element.text),
|
|
4930
|
+
exported: true,
|
|
4931
|
+
callNames: [],
|
|
4932
|
+
extendsNames: [],
|
|
4933
|
+
implementsNames: [],
|
|
4934
|
+
bodyText: element.text
|
|
4935
|
+
});
|
|
4936
|
+
exportLabels.push(id);
|
|
4937
|
+
}
|
|
4938
|
+
}
|
|
4939
|
+
return finalizeCodeAnalysis(manifest, "html", imports, draftSymbols, exportLabels, diagnostics);
|
|
4940
|
+
}
|
|
4941
|
+
function parseCssImport(node) {
|
|
4942
|
+
const directString = node.namedChildren.find((c) => c?.type === "string_value");
|
|
4943
|
+
if (directString) {
|
|
4944
|
+
const specifier = quotedPath(directString.text);
|
|
4945
|
+
if (!specifier) {
|
|
4946
|
+
return void 0;
|
|
4947
|
+
}
|
|
4948
|
+
return {
|
|
4949
|
+
specifier,
|
|
4950
|
+
importedSymbols: [],
|
|
4951
|
+
isExternal: !(specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith("/")),
|
|
4952
|
+
reExport: false
|
|
4953
|
+
};
|
|
4954
|
+
}
|
|
4955
|
+
const call = node.namedChildren.find((c) => c?.type === "call_expression");
|
|
4956
|
+
if (call) {
|
|
4957
|
+
const args = findNamedChild(call, "arguments");
|
|
4958
|
+
const stringNode = args?.namedChildren.find((c) => c?.type === "string_value");
|
|
4959
|
+
if (stringNode) {
|
|
4960
|
+
const specifier = quotedPath(stringNode.text);
|
|
4961
|
+
if (!specifier) {
|
|
4962
|
+
return void 0;
|
|
4963
|
+
}
|
|
4964
|
+
return {
|
|
4965
|
+
specifier,
|
|
4966
|
+
importedSymbols: [],
|
|
4967
|
+
isExternal: !(specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith("/")),
|
|
4968
|
+
reExport: false
|
|
4969
|
+
};
|
|
4970
|
+
}
|
|
4971
|
+
}
|
|
4972
|
+
return void 0;
|
|
3618
4973
|
}
|
|
3619
|
-
function
|
|
4974
|
+
function cssCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
3620
4975
|
const imports = [];
|
|
3621
4976
|
const draftSymbols = [];
|
|
3622
4977
|
const exportLabels = [];
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
4978
|
+
const seenSymbols = /* @__PURE__ */ new Set();
|
|
4979
|
+
const addSelectorSymbol = (name, ruleText) => {
|
|
4980
|
+
const trimmed = name.trim();
|
|
4981
|
+
if (!trimmed || seenSymbols.has(trimmed)) {
|
|
4982
|
+
return;
|
|
4983
|
+
}
|
|
4984
|
+
seenSymbols.add(trimmed);
|
|
4985
|
+
draftSymbols.push({
|
|
4986
|
+
name: trimmed,
|
|
4987
|
+
kind: "class",
|
|
4988
|
+
signature: singleLineSignature(ruleText.split("\n")[0] ?? ruleText),
|
|
4989
|
+
exported: true,
|
|
4990
|
+
callNames: [],
|
|
4991
|
+
extendsNames: [],
|
|
4992
|
+
implementsNames: [],
|
|
4993
|
+
bodyText: ruleText
|
|
4994
|
+
});
|
|
4995
|
+
exportLabels.push(trimmed);
|
|
4996
|
+
};
|
|
4997
|
+
for (const child of rootNode.namedChildren) {
|
|
4998
|
+
if (!child) {
|
|
4999
|
+
continue;
|
|
5000
|
+
}
|
|
5001
|
+
if (child.type === "import_statement") {
|
|
5002
|
+
const parsed = parseCssImport(child);
|
|
3626
5003
|
if (parsed) {
|
|
3627
5004
|
imports.push(parsed);
|
|
3628
5005
|
}
|
|
3629
5006
|
continue;
|
|
3630
5007
|
}
|
|
3631
|
-
if (child.type === "
|
|
3632
|
-
const
|
|
3633
|
-
|
|
3634
|
-
if (!className) {
|
|
5008
|
+
if (child.type === "rule_set") {
|
|
5009
|
+
const selectors = findNamedChild(child, "selectors");
|
|
5010
|
+
if (!selectors) {
|
|
3635
5011
|
continue;
|
|
3636
5012
|
}
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
}
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
5013
|
+
const selectorText = normalizeWhitespace(selectors.text);
|
|
5014
|
+
addSelectorSymbol(selectorText, child.text);
|
|
5015
|
+
continue;
|
|
5016
|
+
}
|
|
5017
|
+
if (child.type === "keyframes_statement") {
|
|
5018
|
+
const nameNode = child.namedChildren.find((c) => c?.type === "keyframes_name" || c?.type === "plain_value");
|
|
5019
|
+
const name = nameNode?.text.trim();
|
|
5020
|
+
if (name) {
|
|
5021
|
+
addSelectorSymbol(`@keyframes ${name}`, child.text);
|
|
5022
|
+
}
|
|
5023
|
+
}
|
|
5024
|
+
}
|
|
5025
|
+
return finalizeCodeAnalysis(manifest, "css", imports, draftSymbols, exportLabels, diagnostics);
|
|
5026
|
+
}
|
|
5027
|
+
function vueCodeAnalysis(manifest, rootNode, diagnostics) {
|
|
5028
|
+
const imports = [];
|
|
5029
|
+
const draftSymbols = [];
|
|
5030
|
+
const exportLabels = [];
|
|
5031
|
+
const seenSymbols = /* @__PURE__ */ new Set();
|
|
5032
|
+
const repoPath = manifest.repoRelativePath ?? path5.basename(manifest.originalPath ?? manifest.storedPath);
|
|
5033
|
+
const basename = path5.posix.basename(stripCodeExtension(toPosix(repoPath)));
|
|
5034
|
+
if (basename) {
|
|
5035
|
+
seenSymbols.add(basename);
|
|
5036
|
+
draftSymbols.push({
|
|
5037
|
+
name: basename,
|
|
5038
|
+
kind: "class",
|
|
5039
|
+
signature: `vue component ${basename}`,
|
|
5040
|
+
exported: true,
|
|
5041
|
+
callNames: [],
|
|
5042
|
+
extendsNames: [],
|
|
5043
|
+
implementsNames: [],
|
|
5044
|
+
bodyText: rootNode.text
|
|
5045
|
+
});
|
|
5046
|
+
exportLabels.push(basename);
|
|
5047
|
+
}
|
|
5048
|
+
const templateElement = rootNode.namedChildren.find((c) => c?.type === "template_element");
|
|
5049
|
+
if (templateElement) {
|
|
5050
|
+
const elements = templateElement.descendantsOfType(["element"]).filter((item) => item !== null);
|
|
5051
|
+
for (const element of elements) {
|
|
5052
|
+
const tagName = htmlTagName(element);
|
|
5053
|
+
const attrs = htmlAttributesOf(element);
|
|
5054
|
+
const startTag = findNamedChild(element, "start_tag") ?? findNamedChild(element, "self_closing_tag") ?? null;
|
|
5055
|
+
const rawTagName = startTag ? findNamedChild(startTag, "tag_name")?.text.trim() : void 0;
|
|
5056
|
+
if (rawTagName && /^[A-Z]/.test(rawTagName) && !seenSymbols.has(rawTagName)) {
|
|
5057
|
+
seenSymbols.add(rawTagName);
|
|
3654
5058
|
draftSymbols.push({
|
|
3655
|
-
name:
|
|
3656
|
-
kind: "
|
|
3657
|
-
signature: singleLineSignature(
|
|
5059
|
+
name: rawTagName,
|
|
5060
|
+
kind: "class",
|
|
5061
|
+
signature: singleLineSignature(element.text.split("\n")[0] ?? element.text),
|
|
3658
5062
|
exported: true,
|
|
3659
5063
|
callNames: [],
|
|
3660
5064
|
extendsNames: [],
|
|
3661
5065
|
implementsNames: [],
|
|
3662
|
-
bodyText:
|
|
5066
|
+
bodyText: element.text
|
|
3663
5067
|
});
|
|
3664
|
-
exportLabels.push(
|
|
3665
|
-
}
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
5068
|
+
exportLabels.push(rawTagName);
|
|
5069
|
+
}
|
|
5070
|
+
if (tagName && !tagName.includes("-") && !(rawTagName && /^[A-Z]/.test(rawTagName))) {
|
|
5071
|
+
const id = attrs.get("id");
|
|
5072
|
+
if (id && !seenSymbols.has(id)) {
|
|
5073
|
+
seenSymbols.add(id);
|
|
5074
|
+
draftSymbols.push({
|
|
5075
|
+
name: id,
|
|
5076
|
+
kind: "variable",
|
|
5077
|
+
signature: singleLineSignature(element.text.split("\n")[0] ?? element.text),
|
|
5078
|
+
exported: true,
|
|
5079
|
+
callNames: [],
|
|
5080
|
+
extendsNames: [],
|
|
5081
|
+
implementsNames: [],
|
|
5082
|
+
bodyText: element.text
|
|
5083
|
+
});
|
|
5084
|
+
exportLabels.push(id);
|
|
5085
|
+
}
|
|
3672
5086
|
}
|
|
3673
|
-
draftSymbols.push({
|
|
3674
|
-
name: functionName,
|
|
3675
|
-
kind: "function",
|
|
3676
|
-
signature: singleLineSignature(child.text),
|
|
3677
|
-
exported: true,
|
|
3678
|
-
callNames: [],
|
|
3679
|
-
extendsNames: [],
|
|
3680
|
-
implementsNames: [],
|
|
3681
|
-
bodyText: nodeText(findNamedChild(child, "script_block") ?? child.childForFieldName("body")) || child.text
|
|
3682
|
-
});
|
|
3683
|
-
exportLabels.push(functionName);
|
|
3684
5087
|
}
|
|
3685
5088
|
}
|
|
3686
|
-
return finalizeCodeAnalysis(manifest, "
|
|
5089
|
+
return finalizeCodeAnalysis(manifest, "vue", imports, draftSymbols, exportLabels, diagnostics);
|
|
3687
5090
|
}
|
|
3688
5091
|
function cFamilyCodeAnalysis(manifest, language, rootNode, diagnostics) {
|
|
3689
5092
|
const imports = [];
|
|
@@ -3704,7 +5107,7 @@ function cFamilyCodeAnalysis(manifest, language, rootNode, diagnostics) {
|
|
|
3704
5107
|
continue;
|
|
3705
5108
|
}
|
|
3706
5109
|
if (child.type === "preproc_include") {
|
|
3707
|
-
const parsed = parseCppInclude(child
|
|
5110
|
+
const parsed = parseCppInclude(child);
|
|
3708
5111
|
if (parsed) {
|
|
3709
5112
|
imports.push(parsed);
|
|
3710
5113
|
}
|
|
@@ -3761,16 +5164,27 @@ function cFamilyCodeAnalysis(manifest, language, rootNode, diagnostics) {
|
|
|
3761
5164
|
return finalizeCodeAnalysis(manifest, language, imports, draftSymbols, exportLabels, diagnostics);
|
|
3762
5165
|
}
|
|
3763
5166
|
async function analyzeTreeSitterCode(manifest, content, language) {
|
|
5167
|
+
if (language === "swift" && !swiftTreeSitterEnabled()) {
|
|
5168
|
+
return {
|
|
5169
|
+
code: finalizeCodeAnalysis(manifest, language, [], [], [], [swiftTreeSitterDisabledDiagnostic()]),
|
|
5170
|
+
rationales: []
|
|
5171
|
+
};
|
|
5172
|
+
}
|
|
5173
|
+
const parseInput = language === "c" || language === "cpp" || language === "csharp" ? neutralizePreprocessorDirectives(content) : content;
|
|
3764
5174
|
let tree = null;
|
|
3765
5175
|
try {
|
|
3766
5176
|
const module = await getTreeSitterModule();
|
|
3767
5177
|
await ensureTreeSitterInit(module);
|
|
3768
5178
|
const parser = new module.Parser();
|
|
3769
5179
|
parser.setLanguage(await loadLanguage(language));
|
|
3770
|
-
tree = parser.parse(
|
|
5180
|
+
tree = parser.parse(parseInput);
|
|
3771
5181
|
} catch (error) {
|
|
5182
|
+
const diagnostic = treeSitterCompatibilityDiagnostic(language, error);
|
|
5183
|
+
if (language === "bash" && typeof diagnostic.message === "string" && diagnostic.message.includes("resolved is not a function")) {
|
|
5184
|
+
diagnostic.category = "warning";
|
|
5185
|
+
}
|
|
3772
5186
|
return {
|
|
3773
|
-
code: finalizeCodeAnalysis(manifest, language, [], [], [], [
|
|
5187
|
+
code: finalizeCodeAnalysis(manifest, language, [], [], [], [diagnostic]),
|
|
3774
5188
|
rationales: []
|
|
3775
5189
|
};
|
|
3776
5190
|
}
|
|
@@ -3796,11 +5210,14 @@ async function analyzeTreeSitterCode(manifest, content, language) {
|
|
|
3796
5210
|
};
|
|
3797
5211
|
}
|
|
3798
5212
|
try {
|
|
3799
|
-
const
|
|
5213
|
+
const suppressDiagnostics = language === "lua" || language === "bash" && detectShellDialect(content) === "zsh";
|
|
5214
|
+
const rawDiagnostics = suppressDiagnostics ? [] : diagnosticsFromTree(tree.rootNode);
|
|
5215
|
+
const grammarGappedLanguages = /* @__PURE__ */ new Set(["c", "cpp", "csharp", "bash"]);
|
|
5216
|
+
const diagnostics = grammarGappedLanguages.has(language) ? rawDiagnostics.map((d) => d.category === "error" ? { ...d, category: "warning" } : d) : rawDiagnostics;
|
|
3800
5217
|
const rationales = extractTreeSitterRationales(manifest, language, tree.rootNode);
|
|
3801
5218
|
switch (language) {
|
|
3802
5219
|
case "bash":
|
|
3803
|
-
return { code: bashCodeAnalysis(manifest, tree.rootNode, diagnostics), rationales };
|
|
5220
|
+
return { code: bashCodeAnalysis(manifest, tree.rootNode, diagnostics, content), rationales };
|
|
3804
5221
|
case "python":
|
|
3805
5222
|
return { code: pythonCodeAnalysis(manifest, tree.rootNode, diagnostics), rationales };
|
|
3806
5223
|
case "go":
|
|
@@ -3827,6 +5244,24 @@ async function analyzeTreeSitterCode(manifest, content, language) {
|
|
|
3827
5244
|
return { code: rubyCodeAnalysis(manifest, tree.rootNode, diagnostics), rationales };
|
|
3828
5245
|
case "powershell":
|
|
3829
5246
|
return { code: powershellCodeAnalysis(manifest, tree.rootNode, diagnostics), rationales };
|
|
5247
|
+
case "swift":
|
|
5248
|
+
return { code: swiftCodeAnalysis(manifest, tree.rootNode, diagnostics), rationales };
|
|
5249
|
+
case "elixir":
|
|
5250
|
+
return { code: elixirCodeAnalysis(manifest, tree.rootNode, diagnostics), rationales };
|
|
5251
|
+
case "ocaml":
|
|
5252
|
+
return { code: ocamlCodeAnalysis(manifest, tree.rootNode, diagnostics), rationales };
|
|
5253
|
+
case "objc":
|
|
5254
|
+
return { code: objcCodeAnalysis(manifest, tree.rootNode, diagnostics), rationales };
|
|
5255
|
+
case "rescript":
|
|
5256
|
+
return { code: rescriptCodeAnalysis(manifest, tree.rootNode, diagnostics), rationales };
|
|
5257
|
+
case "solidity":
|
|
5258
|
+
return { code: solidityCodeAnalysis(manifest, tree.rootNode, diagnostics), rationales };
|
|
5259
|
+
case "html":
|
|
5260
|
+
return { code: htmlCodeAnalysis(manifest, tree.rootNode, diagnostics), rationales };
|
|
5261
|
+
case "css":
|
|
5262
|
+
return { code: cssCodeAnalysis(manifest, tree.rootNode, diagnostics), rationales };
|
|
5263
|
+
case "vue":
|
|
5264
|
+
return { code: vueCodeAnalysis(manifest, tree.rootNode, diagnostics), rationales };
|
|
3830
5265
|
case "c":
|
|
3831
5266
|
case "cpp":
|
|
3832
5267
|
return { code: cFamilyCodeAnalysis(manifest, language, tree.rootNode, diagnostics), rationales };
|
|
@@ -4520,6 +5955,33 @@ function inferCodeLanguage(filePath, mimeType = "", options = {}) {
|
|
|
4520
5955
|
if (extension === ".ps1" || extension === ".psm1" || extension === ".psd1") {
|
|
4521
5956
|
return "powershell";
|
|
4522
5957
|
}
|
|
5958
|
+
if (extension === ".swift") {
|
|
5959
|
+
return "swift";
|
|
5960
|
+
}
|
|
5961
|
+
if (extension === ".ex" || extension === ".exs") {
|
|
5962
|
+
return "elixir";
|
|
5963
|
+
}
|
|
5964
|
+
if (extension === ".ml" || extension === ".mli") {
|
|
5965
|
+
return "ocaml";
|
|
5966
|
+
}
|
|
5967
|
+
if (extension === ".m" || extension === ".mm") {
|
|
5968
|
+
return "objc";
|
|
5969
|
+
}
|
|
5970
|
+
if (extension === ".res" || extension === ".resi") {
|
|
5971
|
+
return "rescript";
|
|
5972
|
+
}
|
|
5973
|
+
if (extension === ".sol") {
|
|
5974
|
+
return "solidity";
|
|
5975
|
+
}
|
|
5976
|
+
if (extension === ".html" || extension === ".htm") {
|
|
5977
|
+
return "html";
|
|
5978
|
+
}
|
|
5979
|
+
if (extension === ".css") {
|
|
5980
|
+
return "css";
|
|
5981
|
+
}
|
|
5982
|
+
if (extension === ".vue") {
|
|
5983
|
+
return "vue";
|
|
5984
|
+
}
|
|
4523
5985
|
if (extension === ".c") {
|
|
4524
5986
|
return "c";
|
|
4525
5987
|
}
|
|
@@ -4638,15 +6100,36 @@ async function readNearestGoModulePath(startPath, cache) {
|
|
|
4638
6100
|
current = parent;
|
|
4639
6101
|
}
|
|
4640
6102
|
}
|
|
4641
|
-
function
|
|
4642
|
-
const withoutExt = stripCodeExtension2(normalizeAlias(repoRelativePath));
|
|
6103
|
+
function rustModuleAliases(repoRelativePath) {
|
|
6104
|
+
const withoutExt = stripCodeExtension2(normalizeAlias(repoRelativePath)).replace(/\/mod$/i, "");
|
|
6105
|
+
if (!withoutExt) {
|
|
6106
|
+
return [];
|
|
6107
|
+
}
|
|
6108
|
+
const result = [];
|
|
6109
|
+
const push = (moduleTail) => {
|
|
6110
|
+
const trimmed = moduleTail.replace(/^\/+|\/+$/g, "");
|
|
6111
|
+
if (!trimmed || trimmed === "lib" || trimmed === "main") {
|
|
6112
|
+
result.push("crate");
|
|
6113
|
+
return;
|
|
6114
|
+
}
|
|
6115
|
+
const rootStripped = trimmed.replace(/\/(?:lib|main)$/i, "");
|
|
6116
|
+
if (rootStripped !== trimmed && rootStripped) {
|
|
6117
|
+
result.push(`crate::${rootStripped.replace(/\//g, "::")}`);
|
|
6118
|
+
}
|
|
6119
|
+
result.push(`crate::${trimmed.replace(/\//g, "::")}`);
|
|
6120
|
+
};
|
|
4643
6121
|
const srcIdx = withoutExt.lastIndexOf("/src/");
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
6122
|
+
if (srcIdx >= 0) {
|
|
6123
|
+
push(withoutExt.slice(srcIdx + "/src/".length));
|
|
6124
|
+
}
|
|
6125
|
+
if (withoutExt.startsWith("src/")) {
|
|
6126
|
+
push(withoutExt.slice("src/".length));
|
|
6127
|
+
}
|
|
6128
|
+
const segments = withoutExt.split("/").filter(Boolean);
|
|
6129
|
+
for (let start = 0; start < segments.length; start += 1) {
|
|
6130
|
+
push(segments.slice(start).join("/"));
|
|
4648
6131
|
}
|
|
4649
|
-
return
|
|
6132
|
+
return uniqueBy(result.filter(Boolean), (item) => item);
|
|
4650
6133
|
}
|
|
4651
6134
|
function candidateExtensionsFor(language) {
|
|
4652
6135
|
switch (language) {
|
|
@@ -4687,6 +6170,24 @@ function candidateExtensionsFor(language) {
|
|
|
4687
6170
|
return [".c", ".h"];
|
|
4688
6171
|
case "cpp":
|
|
4689
6172
|
return [".cc", ".cpp", ".cxx", ".h", ".hh", ".hpp", ".hxx"];
|
|
6173
|
+
case "swift":
|
|
6174
|
+
return [".swift"];
|
|
6175
|
+
case "elixir":
|
|
6176
|
+
return [".ex", ".exs"];
|
|
6177
|
+
case "ocaml":
|
|
6178
|
+
return [".ml", ".mli"];
|
|
6179
|
+
case "objc":
|
|
6180
|
+
return [".m", ".mm", ".h"];
|
|
6181
|
+
case "rescript":
|
|
6182
|
+
return [".res", ".resi"];
|
|
6183
|
+
case "solidity":
|
|
6184
|
+
return [".sol"];
|
|
6185
|
+
case "html":
|
|
6186
|
+
return [".css", ".js", ".mjs", ".cjs", ".html", ".htm"];
|
|
6187
|
+
case "css":
|
|
6188
|
+
return [".css"];
|
|
6189
|
+
default:
|
|
6190
|
+
return [];
|
|
4690
6191
|
}
|
|
4691
6192
|
}
|
|
4692
6193
|
async function buildCodeIndex(rootDir, manifests, analyses) {
|
|
@@ -4722,7 +6223,9 @@ async function buildCodeIndex(rootDir, manifests, analyses) {
|
|
|
4722
6223
|
break;
|
|
4723
6224
|
case "rust":
|
|
4724
6225
|
if (repoRelativePath) {
|
|
4725
|
-
|
|
6226
|
+
for (const alias of rustModuleAliases(repoRelativePath)) {
|
|
6227
|
+
recordAlias(aliases, alias);
|
|
6228
|
+
}
|
|
4726
6229
|
}
|
|
4727
6230
|
break;
|
|
4728
6231
|
case "go": {
|
|
@@ -4788,6 +6291,39 @@ async function buildCodeIndex(rootDir, manifests, analyses) {
|
|
|
4788
6291
|
case "powershell":
|
|
4789
6292
|
recordAlias(aliases, basename);
|
|
4790
6293
|
break;
|
|
6294
|
+
case "elixir":
|
|
6295
|
+
for (const symbol of analysis.code.symbols) {
|
|
6296
|
+
if (symbol.kind === "class" || symbol.kind === "interface") {
|
|
6297
|
+
recordAlias(aliases, symbol.name);
|
|
6298
|
+
}
|
|
6299
|
+
}
|
|
6300
|
+
break;
|
|
6301
|
+
case "ocaml": {
|
|
6302
|
+
if (basename) {
|
|
6303
|
+
const capitalized = basename.charAt(0).toUpperCase() + basename.slice(1);
|
|
6304
|
+
recordAlias(aliases, capitalized);
|
|
6305
|
+
recordAlias(aliases, basename);
|
|
6306
|
+
}
|
|
6307
|
+
for (const symbol of analysis.code.symbols) {
|
|
6308
|
+
if (symbol.kind === "class" || symbol.kind === "interface") {
|
|
6309
|
+
recordAlias(aliases, symbol.name);
|
|
6310
|
+
}
|
|
6311
|
+
}
|
|
6312
|
+
break;
|
|
6313
|
+
}
|
|
6314
|
+
case "rescript": {
|
|
6315
|
+
if (basename) {
|
|
6316
|
+
const capitalized = basename.charAt(0).toUpperCase() + basename.slice(1);
|
|
6317
|
+
recordAlias(aliases, capitalized);
|
|
6318
|
+
recordAlias(aliases, basename);
|
|
6319
|
+
}
|
|
6320
|
+
for (const symbol of analysis.code.symbols) {
|
|
6321
|
+
if (symbol.kind === "class") {
|
|
6322
|
+
recordAlias(aliases, symbol.name);
|
|
6323
|
+
}
|
|
6324
|
+
}
|
|
6325
|
+
break;
|
|
6326
|
+
}
|
|
4791
6327
|
default:
|
|
4792
6328
|
break;
|
|
4793
6329
|
}
|
|
@@ -4833,6 +6369,9 @@ function aliasMatches(lookup, ...aliases) {
|
|
|
4833
6369
|
(entry) => entry.sourceId
|
|
4834
6370
|
);
|
|
4835
6371
|
}
|
|
6372
|
+
function aliasMatchesExact(lookup, alias) {
|
|
6373
|
+
return lookup.byAlias.get(normalizeAlias(alias)) ?? [];
|
|
6374
|
+
}
|
|
4836
6375
|
function repoPathMatches(lookup, ...repoPaths) {
|
|
4837
6376
|
return uniqueBy(
|
|
4838
6377
|
repoPaths.map((repoPath) => lookup.byRepoPath.get(normalizeAlias(repoPath))).filter((entry) => Boolean(entry)),
|
|
@@ -4850,30 +6389,119 @@ function resolvePythonRelativeAliases(repoRelativePath, specifier) {
|
|
|
4850
6389
|
}
|
|
4851
6390
|
function resolveRustAliases(manifest, specifier) {
|
|
4852
6391
|
const repoRelativePath = manifest.repoRelativePath ? normalizeAlias(manifest.repoRelativePath) : "";
|
|
4853
|
-
|
|
4854
|
-
if (!specifier.startsWith("self::") && !specifier.startsWith("super::")) {
|
|
6392
|
+
if (!specifier.startsWith("self::") && !specifier.startsWith("super::") && specifier !== "self" && specifier !== "super") {
|
|
4855
6393
|
return [specifier];
|
|
4856
6394
|
}
|
|
4857
|
-
|
|
6395
|
+
const candidateAliases = repoRelativePath ? rustModuleAliases(repoRelativePath) : [];
|
|
6396
|
+
if (candidateAliases.length === 0) {
|
|
4858
6397
|
return [];
|
|
4859
6398
|
}
|
|
4860
|
-
const
|
|
4861
|
-
|
|
4862
|
-
|
|
6399
|
+
const tailAfter = specifier.startsWith("self::") ? specifier.slice("self::".length) : specifier.startsWith("super::") ? specifier.slice("super::".length) : "";
|
|
6400
|
+
const superRelative = specifier.startsWith("super");
|
|
6401
|
+
const expansions = [];
|
|
6402
|
+
for (const currentAlias of candidateAliases) {
|
|
6403
|
+
const currentParts = currentAlias.replace(/^crate(?:::)?/, "").split("::").filter(Boolean);
|
|
6404
|
+
if (superRelative) {
|
|
6405
|
+
if (currentParts.length > 0) {
|
|
6406
|
+
const parentParts = currentParts.slice(0, -1);
|
|
6407
|
+
const expanded2 = `crate${parentParts.length ? `::${parentParts.join("::")}` : ""}${tailAfter ? `::${tailAfter}` : ""}`.replace(/::+/g, "::").replace(/::$/, "");
|
|
6408
|
+
expansions.push(expanded2);
|
|
6409
|
+
}
|
|
6410
|
+
continue;
|
|
6411
|
+
}
|
|
6412
|
+
const expanded = `crate${currentParts.length ? `::${currentParts.join("::")}` : ""}${tailAfter ? `::${tailAfter}` : ""}`.replace(/::+/g, "::").replace(/::$/, "");
|
|
6413
|
+
expansions.push(expanded);
|
|
6414
|
+
}
|
|
6415
|
+
return uniqueBy(expansions, (item) => item);
|
|
6416
|
+
}
|
|
6417
|
+
function rustCrateRootPrefix(repoRelativePath) {
|
|
6418
|
+
if (!repoRelativePath) {
|
|
6419
|
+
return void 0;
|
|
6420
|
+
}
|
|
6421
|
+
const normalized = normalizeAlias(repoRelativePath);
|
|
6422
|
+
const idx = normalized.lastIndexOf("/src/");
|
|
6423
|
+
if (idx >= 0) {
|
|
6424
|
+
return normalized.slice(0, idx + "/src/".length);
|
|
4863
6425
|
}
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
6426
|
+
if (normalized.startsWith("src/")) {
|
|
6427
|
+
return "src/";
|
|
6428
|
+
}
|
|
6429
|
+
return void 0;
|
|
6430
|
+
}
|
|
6431
|
+
function filterRustCandidatesToSameCrate(candidates, consumerPath) {
|
|
6432
|
+
const normalizedConsumer = consumerPath ? normalizeAlias(consumerPath) : "";
|
|
6433
|
+
const withoutSelf = normalizedConsumer ? candidates.filter((entry) => normalizeAlias(entry.repoRelativePath ?? "") !== normalizedConsumer) : candidates;
|
|
6434
|
+
if (withoutSelf.length <= 1) {
|
|
6435
|
+
return withoutSelf;
|
|
6436
|
+
}
|
|
6437
|
+
const cratePrefix = rustCrateRootPrefix(consumerPath);
|
|
6438
|
+
if (cratePrefix) {
|
|
6439
|
+
const sameCrate = withoutSelf.filter((entry) => normalizeAlias(entry.repoRelativePath ?? "").startsWith(cratePrefix));
|
|
6440
|
+
if (sameCrate.length > 0) {
|
|
6441
|
+
return sameCrate;
|
|
6442
|
+
}
|
|
6443
|
+
}
|
|
6444
|
+
if (normalizedConsumer) {
|
|
6445
|
+
let dir = path6.posix.dirname(normalizedConsumer);
|
|
6446
|
+
while (dir && dir !== "." && dir !== "/") {
|
|
6447
|
+
const prefix = `${dir}/`;
|
|
6448
|
+
const sameTree = withoutSelf.filter((entry) => normalizeAlias(entry.repoRelativePath ?? "").startsWith(prefix));
|
|
6449
|
+
if (sameTree.length > 0) {
|
|
6450
|
+
return sameTree;
|
|
6451
|
+
}
|
|
6452
|
+
const parent = path6.posix.dirname(dir);
|
|
6453
|
+
if (parent === dir) {
|
|
6454
|
+
break;
|
|
6455
|
+
}
|
|
6456
|
+
dir = parent;
|
|
6457
|
+
}
|
|
6458
|
+
}
|
|
6459
|
+
return withoutSelf;
|
|
6460
|
+
}
|
|
6461
|
+
function resolveRustAliasWithStripping(alias, lookup, consumerPath) {
|
|
6462
|
+
const segments = alias.split("::");
|
|
6463
|
+
while (segments.length > 0) {
|
|
6464
|
+
const candidate = segments.join("::");
|
|
6465
|
+
const matches = aliasMatchesExact(lookup, candidate);
|
|
6466
|
+
const filtered = matches.length > 0 ? filterRustCandidatesToSameCrate(matches, consumerPath) : [];
|
|
6467
|
+
if (filtered.length > 0) {
|
|
6468
|
+
return filtered;
|
|
6469
|
+
}
|
|
6470
|
+
if (candidate === "crate" || candidate === "self" || candidate === "super") {
|
|
6471
|
+
break;
|
|
6472
|
+
}
|
|
6473
|
+
segments.pop();
|
|
6474
|
+
}
|
|
6475
|
+
return [];
|
|
4867
6476
|
}
|
|
4868
6477
|
function luaSpecifierLooksLocal(specifier) {
|
|
4869
6478
|
return /^[A-Za-z_][A-Za-z0-9_]*(?:[./][A-Za-z_][A-Za-z0-9_]*)*$/.test(specifier);
|
|
4870
6479
|
}
|
|
4871
|
-
function resolveLuaModuleCandidates(specifier) {
|
|
6480
|
+
function resolveLuaModuleCandidates(specifier, repoRelativePath) {
|
|
4872
6481
|
const normalized = normalizeAlias(specifier.replace(/\./g, "/"));
|
|
4873
6482
|
if (!normalized) {
|
|
4874
6483
|
return [];
|
|
4875
6484
|
}
|
|
4876
|
-
|
|
6485
|
+
const bases = /* @__PURE__ */ new Set([normalized]);
|
|
6486
|
+
bases.add(`src/${normalized}`);
|
|
6487
|
+
bases.add(`lua/${normalized}`);
|
|
6488
|
+
if (repoRelativePath) {
|
|
6489
|
+
let dir = path6.posix.dirname(repoRelativePath);
|
|
6490
|
+
while (dir && dir !== "." && dir !== "/") {
|
|
6491
|
+
bases.add(`${dir}/${normalized}`);
|
|
6492
|
+
const parent = path6.posix.dirname(dir);
|
|
6493
|
+
if (parent === dir) {
|
|
6494
|
+
break;
|
|
6495
|
+
}
|
|
6496
|
+
dir = parent;
|
|
6497
|
+
}
|
|
6498
|
+
}
|
|
6499
|
+
const candidates = [];
|
|
6500
|
+
for (const base of bases) {
|
|
6501
|
+
candidates.push(`${base}.lua`);
|
|
6502
|
+
candidates.push(path6.posix.join(base, "init.lua"));
|
|
6503
|
+
}
|
|
6504
|
+
return uniqueBy(candidates, (item) => item);
|
|
4877
6505
|
}
|
|
4878
6506
|
function findImportCandidates(manifest, codeImport, lookup) {
|
|
4879
6507
|
const language = manifest.language ?? inferCodeLanguage(manifest.originalPath ?? manifest.storedPath, manifest.mimeType);
|
|
@@ -4897,11 +6525,14 @@ function findImportCandidates(manifest, codeImport, lookup) {
|
|
|
4897
6525
|
case "kotlin":
|
|
4898
6526
|
case "scala":
|
|
4899
6527
|
case "csharp":
|
|
6528
|
+
case "elixir":
|
|
6529
|
+
case "ocaml":
|
|
6530
|
+
case "rescript":
|
|
4900
6531
|
return aliasMatches(lookup, codeImport.specifier);
|
|
4901
6532
|
case "dart":
|
|
4902
6533
|
return repoRelativePath && dartSpecifierLooksLocal2(codeImport.specifier) ? repoPathMatches(lookup, ...importResolutionCandidates(repoRelativePath, codeImport.specifier, candidateExtensionsFor(language))) : aliasMatches(lookup, codeImport.specifier);
|
|
4903
6534
|
case "lua":
|
|
4904
|
-
return luaSpecifierLooksLocal(codeImport.specifier) ? repoPathMatches(lookup, ...resolveLuaModuleCandidates(codeImport.specifier)) : aliasMatches(lookup, codeImport.specifier, codeImport.specifier.replace(/\./g, "/"));
|
|
6535
|
+
return luaSpecifierLooksLocal(codeImport.specifier) ? repoPathMatches(lookup, ...resolveLuaModuleCandidates(codeImport.specifier, repoRelativePath)) : aliasMatches(lookup, codeImport.specifier, codeImport.specifier.replace(/\./g, "/"));
|
|
4905
6536
|
case "zig":
|
|
4906
6537
|
return repoRelativePath && (!codeImport.isExternal || codeImport.specifier.endsWith(".zig")) ? repoPathMatches(lookup, ...importResolutionCandidates(repoRelativePath, codeImport.specifier, candidateExtensionsFor(language))) : aliasMatches(lookup, codeImport.specifier);
|
|
4907
6538
|
case "php":
|
|
@@ -4920,17 +6551,28 @@ function findImportCandidates(manifest, codeImport, lookup) {
|
|
|
4920
6551
|
codeImport.specifier.replace(/\\/g, "/"),
|
|
4921
6552
|
stripCodeExtension2(codeImport.specifier.replace(/\\/g, "/"))
|
|
4922
6553
|
);
|
|
4923
|
-
case "rust":
|
|
4924
|
-
|
|
6554
|
+
case "rust": {
|
|
6555
|
+
for (const alias of [codeImport.specifier, ...resolveRustAliases(manifest, codeImport.specifier)]) {
|
|
6556
|
+
const matches = resolveRustAliasWithStripping(alias, lookup, repoRelativePath);
|
|
6557
|
+
if (matches.length > 0) {
|
|
6558
|
+
return matches;
|
|
6559
|
+
}
|
|
6560
|
+
}
|
|
6561
|
+
return [];
|
|
6562
|
+
}
|
|
4925
6563
|
case "c":
|
|
4926
6564
|
case "cpp":
|
|
6565
|
+
case "objc":
|
|
6566
|
+
case "solidity":
|
|
6567
|
+
case "html":
|
|
6568
|
+
case "css":
|
|
4927
6569
|
return repoRelativePath && !codeImport.isExternal ? repoPathMatches(lookup, ...importResolutionCandidates(repoRelativePath, codeImport.specifier, candidateExtensionsFor(language))) : aliasMatches(lookup, codeImport.specifier);
|
|
4928
6570
|
default:
|
|
4929
6571
|
return [];
|
|
4930
6572
|
}
|
|
4931
6573
|
}
|
|
4932
6574
|
function importLooksLocal(manifest, codeImport, candidates) {
|
|
4933
|
-
if (candidates.length
|
|
6575
|
+
if (candidates.length === 1) {
|
|
4934
6576
|
return true;
|
|
4935
6577
|
}
|
|
4936
6578
|
const language = manifest.language ?? inferCodeLanguage(manifest.originalPath ?? manifest.storedPath, manifest.mimeType);
|
|
@@ -4949,8 +6591,10 @@ function importLooksLocal(manifest, codeImport, candidates) {
|
|
|
4949
6591
|
case "powershell":
|
|
4950
6592
|
case "c":
|
|
4951
6593
|
case "cpp":
|
|
6594
|
+
case "objc":
|
|
4952
6595
|
case "kotlin":
|
|
4953
6596
|
case "scala":
|
|
6597
|
+
case "solidity":
|
|
4954
6598
|
return !codeImport.isExternal;
|
|
4955
6599
|
case "bash":
|
|
4956
6600
|
return bashSpecifierLooksLocal2(codeImport.specifier);
|
|
@@ -5028,6 +6672,43 @@ import { strFromU8, unzipSync } from "fflate";
|
|
|
5028
6672
|
import { JSDOM } from "jsdom";
|
|
5029
6673
|
import TurndownService from "turndown";
|
|
5030
6674
|
import { z } from "zod";
|
|
6675
|
+
|
|
6676
|
+
// src/markdown-ast.ts
|
|
6677
|
+
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
6678
|
+
function parseMarkdownNodes(text) {
|
|
6679
|
+
try {
|
|
6680
|
+
const root = fromMarkdown(text);
|
|
6681
|
+
return Array.isArray(root.children) ? root.children : [];
|
|
6682
|
+
} catch {
|
|
6683
|
+
return [];
|
|
6684
|
+
}
|
|
6685
|
+
}
|
|
6686
|
+
function markdownNodeText(node) {
|
|
6687
|
+
if (node.type === "text" || node.type === "inlineCode" || node.type === "code") {
|
|
6688
|
+
return normalizeWhitespace(node.value ?? "");
|
|
6689
|
+
}
|
|
6690
|
+
if (node.type === "image") {
|
|
6691
|
+
return normalizeWhitespace(node.alt ?? "");
|
|
6692
|
+
}
|
|
6693
|
+
if (node.type === "break" || node.type === "thematicBreak") {
|
|
6694
|
+
return " ";
|
|
6695
|
+
}
|
|
6696
|
+
return normalizeWhitespace((node.children ?? []).map((child) => markdownNodeText(child)).join(" "));
|
|
6697
|
+
}
|
|
6698
|
+
function firstMarkdownHeading(text) {
|
|
6699
|
+
const nodes = parseMarkdownNodes(text);
|
|
6700
|
+
for (const node of nodes) {
|
|
6701
|
+
if (node.type === "heading") {
|
|
6702
|
+
const title = markdownNodeText(node).trim();
|
|
6703
|
+
if (title) {
|
|
6704
|
+
return title;
|
|
6705
|
+
}
|
|
6706
|
+
}
|
|
6707
|
+
}
|
|
6708
|
+
return void 0;
|
|
6709
|
+
}
|
|
6710
|
+
|
|
6711
|
+
// src/extraction.ts
|
|
5031
6712
|
var imageVisionExtractionSchema = z.object({
|
|
5032
6713
|
title: z.string().min(1).nullable().optional(),
|
|
5033
6714
|
summary: z.string().min(1),
|
|
@@ -5427,13 +7108,153 @@ async function extractDocxText(input) {
|
|
|
5427
7108
|
}
|
|
5428
7109
|
return {
|
|
5429
7110
|
extractedText: extractedText || void 0,
|
|
5430
|
-
artifact
|
|
7111
|
+
artifact
|
|
7112
|
+
};
|
|
7113
|
+
} catch (error) {
|
|
7114
|
+
return {
|
|
7115
|
+
artifact: {
|
|
7116
|
+
...extractionMetadata("docx", input.mimeType, "docx_text"),
|
|
7117
|
+
warnings: [`DOCX text extraction failed: ${error instanceof Error ? truncate(error.message, 240) : "unknown error"}`]
|
|
7118
|
+
}
|
|
7119
|
+
};
|
|
7120
|
+
}
|
|
7121
|
+
}
|
|
7122
|
+
function jupyterCellSource(cell) {
|
|
7123
|
+
const source = cell.source;
|
|
7124
|
+
if (Array.isArray(source)) {
|
|
7125
|
+
return source.join("");
|
|
7126
|
+
}
|
|
7127
|
+
if (typeof source === "string") {
|
|
7128
|
+
return source;
|
|
7129
|
+
}
|
|
7130
|
+
return "";
|
|
7131
|
+
}
|
|
7132
|
+
function jupyterOutputSummary(outputs) {
|
|
7133
|
+
if (!Array.isArray(outputs) || outputs.length === 0) {
|
|
7134
|
+
return null;
|
|
7135
|
+
}
|
|
7136
|
+
const parts = [];
|
|
7137
|
+
for (const output of outputs) {
|
|
7138
|
+
const data = output.data;
|
|
7139
|
+
if (data && typeof data === "object") {
|
|
7140
|
+
const text = data["text/plain"] ?? data["text/markdown"];
|
|
7141
|
+
if (typeof text === "string") {
|
|
7142
|
+
parts.push(text.trim());
|
|
7143
|
+
continue;
|
|
7144
|
+
}
|
|
7145
|
+
if (Array.isArray(text)) {
|
|
7146
|
+
parts.push(text.join("").trim());
|
|
7147
|
+
continue;
|
|
7148
|
+
}
|
|
7149
|
+
}
|
|
7150
|
+
const textField = output.text;
|
|
7151
|
+
if (typeof textField === "string") {
|
|
7152
|
+
parts.push(textField.trim());
|
|
7153
|
+
continue;
|
|
7154
|
+
}
|
|
7155
|
+
if (Array.isArray(textField)) {
|
|
7156
|
+
parts.push(textField.join("").trim());
|
|
7157
|
+
}
|
|
7158
|
+
}
|
|
7159
|
+
const joined = parts.filter(Boolean).join("\n").trim();
|
|
7160
|
+
if (!joined) {
|
|
7161
|
+
return `[${outputs.length} non-text output${outputs.length === 1 ? "" : "s"}]`;
|
|
7162
|
+
}
|
|
7163
|
+
return joined.length > 1200 ? `${joined.slice(0, 1200)}
|
|
7164
|
+
[output truncated]` : joined;
|
|
7165
|
+
}
|
|
7166
|
+
async function extractJupyterNotebook(input) {
|
|
7167
|
+
try {
|
|
7168
|
+
const text = decodeTextBytes(input.bytes);
|
|
7169
|
+
const notebook = JSON.parse(text);
|
|
7170
|
+
const cells = Array.isArray(notebook.cells) ? notebook.cells : [];
|
|
7171
|
+
const kernelLanguage = notebook.metadata?.language_info?.name?.trim() || notebook.metadata?.kernelspec?.language?.trim() || "";
|
|
7172
|
+
const kernelDisplay = notebook.metadata?.kernelspec?.display_name?.trim() || "";
|
|
7173
|
+
let notebookTitle = typeof notebook.metadata?.title === "string" ? notebook.metadata.title.trim() : "";
|
|
7174
|
+
if (!notebookTitle) {
|
|
7175
|
+
for (const cell of cells) {
|
|
7176
|
+
if (cell.cell_type === "markdown") {
|
|
7177
|
+
const heading2 = firstMarkdownHeading(jupyterCellSource(cell));
|
|
7178
|
+
if (heading2) {
|
|
7179
|
+
notebookTitle = heading2;
|
|
7180
|
+
break;
|
|
7181
|
+
}
|
|
7182
|
+
}
|
|
7183
|
+
}
|
|
7184
|
+
}
|
|
7185
|
+
if (!notebookTitle && input.fileName) {
|
|
7186
|
+
notebookTitle = path7.basename(input.fileName, path7.extname(input.fileName));
|
|
7187
|
+
}
|
|
7188
|
+
const sections = [];
|
|
7189
|
+
let markdownCellCount = 0;
|
|
7190
|
+
let codeCellCount = 0;
|
|
7191
|
+
let outputCount = 0;
|
|
7192
|
+
for (const cell of cells) {
|
|
7193
|
+
const source = jupyterCellSource(cell).trim();
|
|
7194
|
+
if (!source) {
|
|
7195
|
+
continue;
|
|
7196
|
+
}
|
|
7197
|
+
if (cell.cell_type === "markdown") {
|
|
7198
|
+
markdownCellCount += 1;
|
|
7199
|
+
sections.push(source);
|
|
7200
|
+
sections.push("");
|
|
7201
|
+
continue;
|
|
7202
|
+
}
|
|
7203
|
+
if (cell.cell_type === "code") {
|
|
7204
|
+
codeCellCount += 1;
|
|
7205
|
+
const fence = kernelLanguage || "";
|
|
7206
|
+
sections.push(`\`\`\`${fence}`);
|
|
7207
|
+
sections.push(source);
|
|
7208
|
+
sections.push("```");
|
|
7209
|
+
const outputSummary = jupyterOutputSummary(cell.outputs);
|
|
7210
|
+
if (outputSummary) {
|
|
7211
|
+
outputCount += Array.isArray(cell.outputs) ? cell.outputs.length : 0;
|
|
7212
|
+
sections.push("");
|
|
7213
|
+
sections.push("_Output:_");
|
|
7214
|
+
sections.push("");
|
|
7215
|
+
sections.push(outputSummary);
|
|
7216
|
+
}
|
|
7217
|
+
sections.push("");
|
|
7218
|
+
continue;
|
|
7219
|
+
}
|
|
7220
|
+
sections.push(source);
|
|
7221
|
+
sections.push("");
|
|
7222
|
+
}
|
|
7223
|
+
const heading = notebookTitle ? [`# ${notebookTitle}`, ""] : [];
|
|
7224
|
+
const extractedText = [
|
|
7225
|
+
...heading,
|
|
7226
|
+
`Jupyter Notebook (${cells.length} cell${cells.length === 1 ? "" : "s"}, kernel: ${kernelDisplay || kernelLanguage || "unknown"})`,
|
|
7227
|
+
"",
|
|
7228
|
+
...sections
|
|
7229
|
+
].join("\n").trim();
|
|
7230
|
+
const metadata = {
|
|
7231
|
+
cell_count: String(cells.length),
|
|
7232
|
+
markdown_cells: String(markdownCellCount),
|
|
7233
|
+
code_cells: String(codeCellCount),
|
|
7234
|
+
output_count: String(outputCount)
|
|
7235
|
+
};
|
|
7236
|
+
if (kernelLanguage) {
|
|
7237
|
+
metadata.kernel_language = kernelLanguage;
|
|
7238
|
+
}
|
|
7239
|
+
if (kernelDisplay) {
|
|
7240
|
+
metadata.kernel_display_name = kernelDisplay;
|
|
7241
|
+
}
|
|
7242
|
+
if (notebook.nbformat !== void 0) {
|
|
7243
|
+
metadata.nbformat = `${notebook.nbformat}${notebook.nbformat_minor !== void 0 ? `.${notebook.nbformat_minor}` : ""}`;
|
|
7244
|
+
}
|
|
7245
|
+
return {
|
|
7246
|
+
title: notebookTitle || void 0,
|
|
7247
|
+
extractedText: extractedText || void 0,
|
|
7248
|
+
artifact: {
|
|
7249
|
+
...extractionMetadata("jupyter", input.mimeType, "jupyter_text"),
|
|
7250
|
+
metadata
|
|
7251
|
+
}
|
|
5431
7252
|
};
|
|
5432
7253
|
} catch (error) {
|
|
5433
7254
|
return {
|
|
5434
7255
|
artifact: {
|
|
5435
|
-
...extractionMetadata("
|
|
5436
|
-
warnings: [`
|
|
7256
|
+
...extractionMetadata("jupyter", input.mimeType, "jupyter_text"),
|
|
7257
|
+
warnings: [`Jupyter notebook extraction failed: ${error instanceof Error ? truncate(error.message, 240) : "unknown error"}`]
|
|
5437
7258
|
}
|
|
5438
7259
|
};
|
|
5439
7260
|
}
|
|
@@ -5488,7 +7309,7 @@ async function extractCsvText(input) {
|
|
|
5488
7309
|
};
|
|
5489
7310
|
}
|
|
5490
7311
|
}
|
|
5491
|
-
async function
|
|
7312
|
+
async function extractSpreadsheetWorkbook(input, sourceKind, extractor) {
|
|
5492
7313
|
try {
|
|
5493
7314
|
const XLSX = await import("xlsx");
|
|
5494
7315
|
const workbook = XLSX.read(input.bytes, { type: "buffer", cellFormula: false, cellHTML: false, cellStyles: false });
|
|
@@ -5529,7 +7350,7 @@ async function extractXlsxText(input) {
|
|
|
5529
7350
|
title,
|
|
5530
7351
|
extractedText,
|
|
5531
7352
|
artifact: {
|
|
5532
|
-
...extractionMetadata(
|
|
7353
|
+
...extractionMetadata(sourceKind, input.mimeType, extractor),
|
|
5533
7354
|
metadata,
|
|
5534
7355
|
warnings
|
|
5535
7356
|
}
|
|
@@ -5537,12 +7358,20 @@ async function extractXlsxText(input) {
|
|
|
5537
7358
|
} catch (error) {
|
|
5538
7359
|
return {
|
|
5539
7360
|
artifact: {
|
|
5540
|
-
...extractionMetadata(
|
|
5541
|
-
warnings: [
|
|
7361
|
+
...extractionMetadata(sourceKind, input.mimeType, extractor),
|
|
7362
|
+
warnings: [
|
|
7363
|
+
`${sourceKind.toUpperCase()} extraction failed: ${error instanceof Error ? truncate(error.message, 240) : "unknown error"}`
|
|
7364
|
+
]
|
|
5542
7365
|
}
|
|
5543
7366
|
};
|
|
5544
7367
|
}
|
|
5545
7368
|
}
|
|
7369
|
+
async function extractXlsxText(input) {
|
|
7370
|
+
return extractSpreadsheetWorkbook(input, "xlsx", "xlsx_text");
|
|
7371
|
+
}
|
|
7372
|
+
async function extractOdsText(input) {
|
|
7373
|
+
return extractSpreadsheetWorkbook(input, "ods", "ods_text");
|
|
7374
|
+
}
|
|
5546
7375
|
async function extractPptxText(input) {
|
|
5547
7376
|
try {
|
|
5548
7377
|
const archive = unzipSync(new Uint8Array(input.bytes));
|
|
@@ -5661,7 +7490,7 @@ async function extractEpubChapters(input) {
|
|
|
5661
7490
|
if (!markdown) {
|
|
5662
7491
|
continue;
|
|
5663
7492
|
}
|
|
5664
|
-
const chapterTitle = firstHtmlHeading(html) ||
|
|
7493
|
+
const chapterTitle = firstHtmlHeading(html) || item.href;
|
|
5665
7494
|
const normalizedTitle = normalizeWhitespace(chapterTitle);
|
|
5666
7495
|
if (!normalizedTitle || /^table of contents$/i.test(normalizedTitle)) {
|
|
5667
7496
|
continue;
|
|
@@ -5836,25 +7665,666 @@ function looksLikeSlackEntries(entries) {
|
|
|
5836
7665
|
const hasChannelDayFiles = all.some((entry) => /^[^/]+\/\d{4}-\d{2}-\d{2}\.json$/i.test(entry));
|
|
5837
7666
|
return hasChannelsIndex && hasChannelDayFiles;
|
|
5838
7667
|
}
|
|
5839
|
-
function slackEntriesFromChannelIndex(raw, usersById) {
|
|
5840
|
-
const entries = /* @__PURE__ */ new Map();
|
|
5841
|
-
if (!Array.isArray(raw)) {
|
|
5842
|
-
return entries;
|
|
7668
|
+
function slackEntriesFromChannelIndex(raw, usersById) {
|
|
7669
|
+
const entries = /* @__PURE__ */ new Map();
|
|
7670
|
+
if (!Array.isArray(raw)) {
|
|
7671
|
+
return entries;
|
|
7672
|
+
}
|
|
7673
|
+
for (const item of raw) {
|
|
7674
|
+
if (!item || typeof item !== "object") {
|
|
7675
|
+
continue;
|
|
7676
|
+
}
|
|
7677
|
+
const value = item;
|
|
7678
|
+
const id = normalizeWhitespace(value.id ?? "");
|
|
7679
|
+
const title = normalizeWhitespace(value.name ?? "");
|
|
7680
|
+
if (!title) {
|
|
7681
|
+
continue;
|
|
7682
|
+
}
|
|
7683
|
+
const members = (Array.isArray(value.members) ? value.members : value.user ? [value.user] : []).map((member) => slackFormatSpeakerId(member, usersById)).filter(Boolean);
|
|
7684
|
+
entries.set(title, { id, title, members });
|
|
7685
|
+
}
|
|
7686
|
+
return entries;
|
|
7687
|
+
}
|
|
7688
|
+
function parseOdfMetadata(bytes) {
|
|
7689
|
+
try {
|
|
7690
|
+
const archive = unzipSync(new Uint8Array(bytes));
|
|
7691
|
+
const metaXml = zipEntryText(archive, "meta.xml");
|
|
7692
|
+
if (!metaXml) {
|
|
7693
|
+
return void 0;
|
|
7694
|
+
}
|
|
7695
|
+
const document = parseXmlDocument(metaXml);
|
|
7696
|
+
const valuesByLocalName = /* @__PURE__ */ new Map();
|
|
7697
|
+
for (const node of Array.from(document.getElementsByTagName("*"))) {
|
|
7698
|
+
const localName = node.localName?.trim().toLowerCase();
|
|
7699
|
+
const text = normalizeWhitespace(node.textContent ?? "");
|
|
7700
|
+
if (!localName || !text || valuesByLocalName.has(localName)) {
|
|
7701
|
+
continue;
|
|
7702
|
+
}
|
|
7703
|
+
valuesByLocalName.set(localName, text);
|
|
7704
|
+
}
|
|
7705
|
+
const metadata = {};
|
|
7706
|
+
const mappings = [
|
|
7707
|
+
["title", "title"],
|
|
7708
|
+
["author", "creator"],
|
|
7709
|
+
["subject", "subject"],
|
|
7710
|
+
["description", "description"],
|
|
7711
|
+
["keywords", "keyword"],
|
|
7712
|
+
["initial_creator", "initial-creator"],
|
|
7713
|
+
["created", "creation-date"],
|
|
7714
|
+
["modified", "date"]
|
|
7715
|
+
];
|
|
7716
|
+
for (const [targetKey, sourceKey] of mappings) {
|
|
7717
|
+
const value = valuesByLocalName.get(sourceKey);
|
|
7718
|
+
if (value) {
|
|
7719
|
+
metadata[targetKey] = value;
|
|
7720
|
+
}
|
|
7721
|
+
}
|
|
7722
|
+
return Object.keys(metadata).length ? metadata : void 0;
|
|
7723
|
+
} catch {
|
|
7724
|
+
return void 0;
|
|
7725
|
+
}
|
|
7726
|
+
}
|
|
7727
|
+
function collectOdfTextNodes(contentXml) {
|
|
7728
|
+
const document = parseXmlDocument(contentXml);
|
|
7729
|
+
const nodes = [];
|
|
7730
|
+
for (const node of Array.from(document.getElementsByTagName("*"))) {
|
|
7731
|
+
const localName = node.localName ?? "";
|
|
7732
|
+
if (localName === "h") {
|
|
7733
|
+
const level = Number.parseInt(node.getAttribute("text:outline-level") ?? "1", 10);
|
|
7734
|
+
const text = normalizeWhitespace(node.textContent ?? "");
|
|
7735
|
+
if (text) {
|
|
7736
|
+
nodes.push({ heading: Number.isFinite(level) && level > 0 ? level : 1, text });
|
|
7737
|
+
}
|
|
7738
|
+
continue;
|
|
7739
|
+
}
|
|
7740
|
+
if (localName === "p" || localName === "list-item") {
|
|
7741
|
+
if (node.closest?.("h")) {
|
|
7742
|
+
continue;
|
|
7743
|
+
}
|
|
7744
|
+
const text = normalizeWhitespace(node.textContent ?? "");
|
|
7745
|
+
if (text) {
|
|
7746
|
+
nodes.push({ text });
|
|
7747
|
+
}
|
|
7748
|
+
}
|
|
7749
|
+
}
|
|
7750
|
+
return nodes;
|
|
7751
|
+
}
|
|
7752
|
+
function renderOdfTextNodes(nodes) {
|
|
7753
|
+
const lines = [];
|
|
7754
|
+
for (const node of nodes) {
|
|
7755
|
+
if (node.heading) {
|
|
7756
|
+
lines.push("");
|
|
7757
|
+
lines.push(`${"#".repeat(Math.min(node.heading, 6))} ${node.text}`);
|
|
7758
|
+
lines.push("");
|
|
7759
|
+
continue;
|
|
7760
|
+
}
|
|
7761
|
+
lines.push(node.text);
|
|
7762
|
+
lines.push("");
|
|
7763
|
+
}
|
|
7764
|
+
return lines.join("\n").trim();
|
|
7765
|
+
}
|
|
7766
|
+
async function extractOdtText(input) {
|
|
7767
|
+
try {
|
|
7768
|
+
const archive = unzipSync(new Uint8Array(input.bytes));
|
|
7769
|
+
const contentXml = zipEntryText(archive, "content.xml");
|
|
7770
|
+
if (!contentXml) {
|
|
7771
|
+
throw new Error("Missing content.xml");
|
|
7772
|
+
}
|
|
7773
|
+
const metadata = parseOdfMetadata(input.bytes);
|
|
7774
|
+
const textNodes = collectOdfTextNodes(contentXml);
|
|
7775
|
+
const headingCount = textNodes.filter((node) => node.heading).length;
|
|
7776
|
+
const paragraphCount = textNodes.filter((node) => !node.heading).length;
|
|
7777
|
+
const title = metadata?.title || textNodes.find((node) => node.heading === 1)?.text || (input.fileName ? path7.basename(input.fileName, path7.extname(input.fileName)) : void 0);
|
|
7778
|
+
const body = renderOdfTextNodes(textNodes);
|
|
7779
|
+
const extractedText = [title ? `# ${title}` : null, "", body].filter((item) => item !== null).join("\n").trim();
|
|
7780
|
+
return {
|
|
7781
|
+
title,
|
|
7782
|
+
extractedText: extractedText || void 0,
|
|
7783
|
+
artifact: {
|
|
7784
|
+
...extractionMetadata("odt", input.mimeType, "odt_text"),
|
|
7785
|
+
metadata: {
|
|
7786
|
+
...metadata ?? {},
|
|
7787
|
+
heading_count: String(headingCount),
|
|
7788
|
+
paragraph_count: String(paragraphCount)
|
|
7789
|
+
}
|
|
7790
|
+
}
|
|
7791
|
+
};
|
|
7792
|
+
} catch (error) {
|
|
7793
|
+
return {
|
|
7794
|
+
artifact: {
|
|
7795
|
+
...extractionMetadata("odt", input.mimeType, "odt_text"),
|
|
7796
|
+
warnings: [`ODT extraction failed: ${error instanceof Error ? truncate(error.message, 240) : "unknown error"}`]
|
|
7797
|
+
}
|
|
7798
|
+
};
|
|
7799
|
+
}
|
|
7800
|
+
}
|
|
7801
|
+
async function extractOdpText(input) {
|
|
7802
|
+
try {
|
|
7803
|
+
const archive = unzipSync(new Uint8Array(input.bytes));
|
|
7804
|
+
const contentXml = zipEntryText(archive, "content.xml");
|
|
7805
|
+
if (!contentXml) {
|
|
7806
|
+
throw new Error("Missing content.xml");
|
|
7807
|
+
}
|
|
7808
|
+
const metadata = parseOdfMetadata(input.bytes);
|
|
7809
|
+
const document = parseXmlDocument(contentXml);
|
|
7810
|
+
const pages = Array.from(document.getElementsByTagName("*")).filter((node) => node.localName === "page");
|
|
7811
|
+
const slideSections = [];
|
|
7812
|
+
pages.slice(0, 60).forEach((page, index) => {
|
|
7813
|
+
const slideName = page.getAttribute("draw:name") ?? `Slide ${index + 1}`;
|
|
7814
|
+
const text = normalizeWhitespace(page.textContent ?? "");
|
|
7815
|
+
slideSections.push(`## Slide ${index + 1}: ${slideName}`);
|
|
7816
|
+
if (text) {
|
|
7817
|
+
slideSections.push(text);
|
|
7818
|
+
}
|
|
7819
|
+
slideSections.push("");
|
|
7820
|
+
});
|
|
7821
|
+
const title = metadata?.title || (input.fileName ? path7.basename(input.fileName, path7.extname(input.fileName)) : void 0);
|
|
7822
|
+
const extractedText = [title ? `# ${title}` : null, `Slides: ${pages.length}`, "", ...slideSections].filter((item) => Boolean(item)).join("\n").trim();
|
|
7823
|
+
const warnings = pages.length > 60 ? ["ODP extraction truncated to the first 60 slides."] : void 0;
|
|
7824
|
+
return {
|
|
7825
|
+
title,
|
|
7826
|
+
extractedText: extractedText || void 0,
|
|
7827
|
+
artifact: {
|
|
7828
|
+
...extractionMetadata("odp", input.mimeType, "odp_text"),
|
|
7829
|
+
metadata: {
|
|
7830
|
+
...metadata ?? {},
|
|
7831
|
+
slide_count: String(pages.length)
|
|
7832
|
+
},
|
|
7833
|
+
warnings
|
|
7834
|
+
}
|
|
7835
|
+
};
|
|
7836
|
+
} catch (error) {
|
|
7837
|
+
return {
|
|
7838
|
+
artifact: {
|
|
7839
|
+
...extractionMetadata("odp", input.mimeType, "odp_text"),
|
|
7840
|
+
warnings: [`ODP extraction failed: ${error instanceof Error ? truncate(error.message, 240) : "unknown error"}`]
|
|
7841
|
+
}
|
|
7842
|
+
};
|
|
7843
|
+
}
|
|
7844
|
+
}
|
|
7845
|
+
function inferStructuredFormat(mimeType, fileName) {
|
|
7846
|
+
const lower = (fileName ?? "").toLowerCase();
|
|
7847
|
+
if (lower.endsWith(".jsonc") || lower.endsWith(".json") || lower.endsWith(".json5") || mimeType === "application/json" || mimeType === "application/json5") {
|
|
7848
|
+
return "json";
|
|
7849
|
+
}
|
|
7850
|
+
if (lower.endsWith(".yaml") || lower.endsWith(".yml") || mimeType === "application/yaml" || mimeType === "application/x-yaml") {
|
|
7851
|
+
return "yaml";
|
|
7852
|
+
}
|
|
7853
|
+
if (lower.endsWith(".toml") || mimeType === "application/toml") {
|
|
7854
|
+
return "toml";
|
|
7855
|
+
}
|
|
7856
|
+
if (lower.endsWith(".xml") || mimeType === "application/xml" || mimeType === "text/xml") {
|
|
7857
|
+
return "xml";
|
|
7858
|
+
}
|
|
7859
|
+
if (lower.endsWith(".ini") || lower.endsWith(".conf") || lower.endsWith(".cfg")) {
|
|
7860
|
+
return "ini";
|
|
7861
|
+
}
|
|
7862
|
+
if (lower.endsWith(".env")) {
|
|
7863
|
+
return "env";
|
|
7864
|
+
}
|
|
7865
|
+
if (lower.endsWith(".properties")) {
|
|
7866
|
+
return "properties";
|
|
7867
|
+
}
|
|
7868
|
+
return null;
|
|
7869
|
+
}
|
|
7870
|
+
function parseEnvFile(text) {
|
|
7871
|
+
const result = {};
|
|
7872
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
7873
|
+
const line = rawLine.trim();
|
|
7874
|
+
if (!line || line.startsWith("#")) {
|
|
7875
|
+
continue;
|
|
7876
|
+
}
|
|
7877
|
+
const eqIndex = line.indexOf("=");
|
|
7878
|
+
if (eqIndex <= 0) {
|
|
7879
|
+
continue;
|
|
7880
|
+
}
|
|
7881
|
+
const key = line.slice(0, eqIndex).trim();
|
|
7882
|
+
let value = line.slice(eqIndex + 1).trim();
|
|
7883
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
7884
|
+
value = value.slice(1, -1);
|
|
7885
|
+
}
|
|
7886
|
+
result[key] = value;
|
|
7887
|
+
}
|
|
7888
|
+
return result;
|
|
7889
|
+
}
|
|
7890
|
+
function parsePropertiesFile(text) {
|
|
7891
|
+
const result = {};
|
|
7892
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
7893
|
+
const line = rawLine.trim();
|
|
7894
|
+
if (!line || line.startsWith("#") || line.startsWith("!")) {
|
|
7895
|
+
continue;
|
|
7896
|
+
}
|
|
7897
|
+
let sep = line.indexOf("=");
|
|
7898
|
+
if (sep < 0) {
|
|
7899
|
+
sep = line.indexOf(":");
|
|
7900
|
+
}
|
|
7901
|
+
if (sep <= 0) {
|
|
7902
|
+
continue;
|
|
7903
|
+
}
|
|
7904
|
+
const key = line.slice(0, sep).trim();
|
|
7905
|
+
const value = line.slice(sep + 1).trim();
|
|
7906
|
+
result[key] = value;
|
|
7907
|
+
}
|
|
7908
|
+
return result;
|
|
7909
|
+
}
|
|
7910
|
+
function parseXmlToSchema(text) {
|
|
7911
|
+
const document = parseXmlDocument(text);
|
|
7912
|
+
const root = document.documentElement;
|
|
7913
|
+
if (!root) {
|
|
7914
|
+
return {};
|
|
7915
|
+
}
|
|
7916
|
+
const childCounts = /* @__PURE__ */ new Map();
|
|
7917
|
+
for (const child of Array.from(root.children)) {
|
|
7918
|
+
const name = child.tagName || child.localName || "";
|
|
7919
|
+
if (!name) {
|
|
7920
|
+
continue;
|
|
7921
|
+
}
|
|
7922
|
+
childCounts.set(name, (childCounts.get(name) ?? 0) + 1);
|
|
7923
|
+
}
|
|
7924
|
+
const result = {};
|
|
7925
|
+
for (const [name, count] of childCounts.entries()) {
|
|
7926
|
+
result[name] = { count };
|
|
7927
|
+
}
|
|
7928
|
+
return { [root.tagName || "root"]: result };
|
|
7929
|
+
}
|
|
7930
|
+
function describeJsonShape(value) {
|
|
7931
|
+
if (value === null) {
|
|
7932
|
+
return { type: "null", size: 0, depth: 0 };
|
|
7933
|
+
}
|
|
7934
|
+
if (Array.isArray(value)) {
|
|
7935
|
+
const depths = value.map((entry) => describeJsonShape(entry).depth);
|
|
7936
|
+
return { type: "array", size: value.length, depth: 1 + (depths.length ? Math.max(...depths) : 0) };
|
|
7937
|
+
}
|
|
7938
|
+
if (typeof value === "object") {
|
|
7939
|
+
const entries = Object.entries(value);
|
|
7940
|
+
const depths = entries.map(([, v]) => describeJsonShape(v).depth);
|
|
7941
|
+
return { type: "object", size: entries.length, depth: 1 + (depths.length ? Math.max(...depths) : 0) };
|
|
7942
|
+
}
|
|
7943
|
+
return { type: typeof value, size: 0, depth: 0 };
|
|
7944
|
+
}
|
|
7945
|
+
function describeTopLevelSchema(value) {
|
|
7946
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
7947
|
+
const shape = describeJsonShape(value);
|
|
7948
|
+
return [`(root) ${shape.type}${shape.size ? ` (${shape.size})` : ""}`];
|
|
7949
|
+
}
|
|
7950
|
+
const entries = Object.entries(value);
|
|
7951
|
+
return entries.slice(0, 20).map(([key, child]) => {
|
|
7952
|
+
const shape = describeJsonShape(child);
|
|
7953
|
+
const sizeHint = shape.type === "array" ? ` (${shape.size} items)` : shape.type === "object" ? ` (${shape.size} keys)` : "";
|
|
7954
|
+
return `${key}: ${shape.type}${sizeHint}`;
|
|
7955
|
+
});
|
|
7956
|
+
}
|
|
7957
|
+
async function parseStructuredPayload(bytes, format) {
|
|
7958
|
+
const text = decodeTextBytes(bytes);
|
|
7959
|
+
if (format === "json") {
|
|
7960
|
+
const cleaned = text.replace(/^\uFEFF/, "");
|
|
7961
|
+
return { format, value: JSON.parse(cleaned) };
|
|
7962
|
+
}
|
|
7963
|
+
if (format === "yaml") {
|
|
7964
|
+
const yamlModule = await import("yaml");
|
|
7965
|
+
return { format, value: yamlModule.parse(text) };
|
|
7966
|
+
}
|
|
7967
|
+
if (format === "toml") {
|
|
7968
|
+
const tomlModule = await import("smol-toml");
|
|
7969
|
+
return { format, value: tomlModule.parse(text) };
|
|
7970
|
+
}
|
|
7971
|
+
if (format === "xml") {
|
|
7972
|
+
return { format, value: parseXmlToSchema(text) };
|
|
7973
|
+
}
|
|
7974
|
+
if (format === "ini") {
|
|
7975
|
+
try {
|
|
7976
|
+
const tomlModule = await import("smol-toml");
|
|
7977
|
+
return { format, value: tomlModule.parse(text) };
|
|
7978
|
+
} catch {
|
|
7979
|
+
return { format, value: parsePropertiesFile(text) };
|
|
7980
|
+
}
|
|
7981
|
+
}
|
|
7982
|
+
if (format === "env") {
|
|
7983
|
+
return { format, value: parseEnvFile(text) };
|
|
7984
|
+
}
|
|
7985
|
+
return { format, value: parsePropertiesFile(text) };
|
|
7986
|
+
}
|
|
7987
|
+
async function extractStructuredData(input) {
|
|
7988
|
+
const format = inferStructuredFormat(input.mimeType, input.fileName);
|
|
7989
|
+
if (!format) {
|
|
7990
|
+
return {
|
|
7991
|
+
artifact: {
|
|
7992
|
+
...extractionMetadata("data", input.mimeType, "structured_data"),
|
|
7993
|
+
warnings: ["Structured data extraction skipped: format not recognized."]
|
|
7994
|
+
}
|
|
7995
|
+
};
|
|
7996
|
+
}
|
|
7997
|
+
try {
|
|
7998
|
+
const { value } = await parseStructuredPayload(input.bytes, format);
|
|
7999
|
+
const shape = describeJsonShape(value);
|
|
8000
|
+
const schemaLines = describeTopLevelSchema(value);
|
|
8001
|
+
const previewText = decodeTextBytes(input.bytes);
|
|
8002
|
+
const previewLines = previewText.split(/\r?\n/).slice(0, 40);
|
|
8003
|
+
const truncated = previewText.split(/\r?\n/).length > previewLines.length;
|
|
8004
|
+
const title = input.fileName ? path7.basename(input.fileName, path7.extname(input.fileName)) : void 0;
|
|
8005
|
+
const extractedText = [
|
|
8006
|
+
title ? `# ${title}` : null,
|
|
8007
|
+
`Format: ${format.toUpperCase()}`,
|
|
8008
|
+
`Top-level: ${shape.type}`,
|
|
8009
|
+
shape.type === "object" || shape.type === "array" ? `Size: ${shape.size}` : null,
|
|
8010
|
+
`Nested depth: ${shape.depth}`,
|
|
8011
|
+
"",
|
|
8012
|
+
"## Schema",
|
|
8013
|
+
"",
|
|
8014
|
+
...schemaLines.map((entry) => `- ${entry}`),
|
|
8015
|
+
"",
|
|
8016
|
+
"## Preview",
|
|
8017
|
+
"",
|
|
8018
|
+
`\`\`\`${format}`,
|
|
8019
|
+
...previewLines,
|
|
8020
|
+
truncated ? "\u2026" : null,
|
|
8021
|
+
"```"
|
|
8022
|
+
].filter((item) => item !== null).join("\n").trim();
|
|
8023
|
+
return {
|
|
8024
|
+
title,
|
|
8025
|
+
extractedText,
|
|
8026
|
+
artifact: {
|
|
8027
|
+
...extractionMetadata("data", input.mimeType, "structured_data"),
|
|
8028
|
+
metadata: {
|
|
8029
|
+
format,
|
|
8030
|
+
top_level_type: shape.type,
|
|
8031
|
+
top_level_size: String(shape.size),
|
|
8032
|
+
nested_depth: String(shape.depth)
|
|
8033
|
+
}
|
|
8034
|
+
}
|
|
8035
|
+
};
|
|
8036
|
+
} catch (error) {
|
|
8037
|
+
return {
|
|
8038
|
+
artifact: {
|
|
8039
|
+
...extractionMetadata("data", input.mimeType, "structured_data"),
|
|
8040
|
+
warnings: [`Structured data extraction failed: ${error instanceof Error ? truncate(error.message, 240) : "unknown error"}`]
|
|
8041
|
+
}
|
|
8042
|
+
};
|
|
8043
|
+
}
|
|
8044
|
+
}
|
|
8045
|
+
function formatBibCreator(creator) {
|
|
8046
|
+
if (creator.name) {
|
|
8047
|
+
return creator.name;
|
|
8048
|
+
}
|
|
8049
|
+
const parts = [creator.prefix, creator.firstName, creator.lastName, creator.suffix].filter(Boolean);
|
|
8050
|
+
return parts.join(" ");
|
|
8051
|
+
}
|
|
8052
|
+
function bibFieldString(value) {
|
|
8053
|
+
if (value == null) {
|
|
8054
|
+
return "";
|
|
8055
|
+
}
|
|
8056
|
+
if (typeof value === "string") {
|
|
8057
|
+
return value.trim();
|
|
8058
|
+
}
|
|
8059
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
8060
|
+
return String(value);
|
|
8061
|
+
}
|
|
8062
|
+
if (Array.isArray(value)) {
|
|
8063
|
+
return value.map((item) => bibFieldString(item)).filter(Boolean).join(", ");
|
|
8064
|
+
}
|
|
8065
|
+
if (typeof value === "object") {
|
|
8066
|
+
return bibFieldString(value.name ?? "");
|
|
8067
|
+
}
|
|
8068
|
+
return String(value);
|
|
8069
|
+
}
|
|
8070
|
+
async function extractBibTeXText(input) {
|
|
8071
|
+
try {
|
|
8072
|
+
const bibtex = await import("@retorquere/bibtex-parser");
|
|
8073
|
+
const text = decodeTextBytes(input.bytes);
|
|
8074
|
+
const library = bibtex.parse(text);
|
|
8075
|
+
const entries = Array.isArray(library.entries) ? library.entries : [];
|
|
8076
|
+
const citationTypes = /* @__PURE__ */ new Map();
|
|
8077
|
+
for (const entry of entries) {
|
|
8078
|
+
const type = (entry.type ?? "misc").toLowerCase();
|
|
8079
|
+
citationTypes.set(type, (citationTypes.get(type) ?? 0) + 1);
|
|
8080
|
+
}
|
|
8081
|
+
const entrySections = [];
|
|
8082
|
+
for (const entry of entries.slice(0, 200)) {
|
|
8083
|
+
const fields = entry.fields ?? {};
|
|
8084
|
+
const title2 = bibFieldString(fields.title);
|
|
8085
|
+
const authorList = Array.isArray(fields.author) ? fields.author.map((creator) => formatBibCreator(creator)).filter(Boolean) : bibFieldString(fields.author).split(/\s+and\s+/i).filter(Boolean);
|
|
8086
|
+
const editorList = Array.isArray(fields.editor) ? fields.editor.map((creator) => formatBibCreator(creator)).filter(Boolean) : [];
|
|
8087
|
+
const year = bibFieldString(fields.year ?? fields.date ?? "");
|
|
8088
|
+
const journal = bibFieldString(fields.journal ?? fields.booktitle ?? fields.publisher ?? "");
|
|
8089
|
+
const doi = bibFieldString(fields.doi);
|
|
8090
|
+
const url = bibFieldString(fields.url);
|
|
8091
|
+
const credit = authorList.length ? authorList.join(", ") : editorList.length ? `${editorList.join(", ")} (eds.)` : "Unknown";
|
|
8092
|
+
const descriptorParts = [credit];
|
|
8093
|
+
if (year) {
|
|
8094
|
+
descriptorParts.push(year);
|
|
8095
|
+
}
|
|
8096
|
+
const descriptor = descriptorParts.join(", ");
|
|
8097
|
+
const trailing = [];
|
|
8098
|
+
if (journal) {
|
|
8099
|
+
trailing.push(journal);
|
|
8100
|
+
}
|
|
8101
|
+
if (doi) {
|
|
8102
|
+
trailing.push(`doi:${doi}`);
|
|
8103
|
+
}
|
|
8104
|
+
if (url) {
|
|
8105
|
+
trailing.push(url);
|
|
8106
|
+
}
|
|
8107
|
+
const trailingText = trailing.length ? ` \u2014 ${trailing.join(", ")}` : "";
|
|
8108
|
+
entrySections.push(`- [${entry.key}] ${title2 || "(untitled)"} (${descriptor})${trailingText}`);
|
|
8109
|
+
}
|
|
8110
|
+
const totalEntries = entries.length;
|
|
8111
|
+
const truncated = entries.length > 200;
|
|
8112
|
+
const typeSummary = [...citationTypes.entries()].sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0])).map(([type, count]) => `${type} (${count})`).join(", ");
|
|
8113
|
+
const title = input.fileName ? path7.basename(input.fileName, path7.extname(input.fileName)) : "BibTeX library";
|
|
8114
|
+
const extractedText = [
|
|
8115
|
+
`# ${title}`,
|
|
8116
|
+
"",
|
|
8117
|
+
`BibTeX library with ${totalEntries} entr${totalEntries === 1 ? "y" : "ies"}.`,
|
|
8118
|
+
typeSummary ? `Citation types: ${typeSummary}.` : null,
|
|
8119
|
+
"",
|
|
8120
|
+
"## Entries",
|
|
8121
|
+
"",
|
|
8122
|
+
...entrySections,
|
|
8123
|
+
truncated ? `
|
|
8124
|
+
_Preview truncated to the first 200 entries._` : null
|
|
8125
|
+
].filter((item) => item !== null).join("\n").trim();
|
|
8126
|
+
const warnings = library.errors?.length ? [`BibTeX parser reported ${library.errors.length} parse error(s).`] : void 0;
|
|
8127
|
+
return {
|
|
8128
|
+
title,
|
|
8129
|
+
extractedText,
|
|
8130
|
+
artifact: {
|
|
8131
|
+
...extractionMetadata("bibtex", input.mimeType, "bibtex_text"),
|
|
8132
|
+
metadata: {
|
|
8133
|
+
entry_count: String(totalEntries),
|
|
8134
|
+
citation_types: [...citationTypes.keys()].sort().join(",")
|
|
8135
|
+
},
|
|
8136
|
+
warnings
|
|
8137
|
+
}
|
|
8138
|
+
};
|
|
8139
|
+
} catch (error) {
|
|
8140
|
+
return {
|
|
8141
|
+
artifact: {
|
|
8142
|
+
...extractionMetadata("bibtex", input.mimeType, "bibtex_text"),
|
|
8143
|
+
warnings: [`BibTeX extraction failed: ${error instanceof Error ? truncate(error.message, 240) : "unknown error"}`]
|
|
8144
|
+
}
|
|
8145
|
+
};
|
|
8146
|
+
}
|
|
8147
|
+
}
|
|
8148
|
+
async function extractRtfText(input) {
|
|
8149
|
+
try {
|
|
8150
|
+
const rtfParser = await import("rtf-parser");
|
|
8151
|
+
const parseString = rtfParser.string ?? rtfParser.default?.string;
|
|
8152
|
+
if (typeof parseString !== "function") {
|
|
8153
|
+
throw new Error("rtf-parser did not expose a string parser.");
|
|
8154
|
+
}
|
|
8155
|
+
const rtfText = decodeTextBytes(input.bytes);
|
|
8156
|
+
const document = await new Promise((resolve, reject) => {
|
|
8157
|
+
parseString(rtfText, (err, doc) => {
|
|
8158
|
+
if (err || !doc) {
|
|
8159
|
+
reject(err ?? new Error("RTF parse returned no document"));
|
|
8160
|
+
return;
|
|
8161
|
+
}
|
|
8162
|
+
resolve(doc);
|
|
8163
|
+
});
|
|
8164
|
+
});
|
|
8165
|
+
const paragraphs = [];
|
|
8166
|
+
for (const paragraph of document.content ?? []) {
|
|
8167
|
+
const spans = paragraph.content ?? [];
|
|
8168
|
+
const text = normalizeWhitespace(spans.map((span) => span.value ?? "").join(""));
|
|
8169
|
+
if (text) {
|
|
8170
|
+
paragraphs.push(text);
|
|
8171
|
+
}
|
|
8172
|
+
}
|
|
8173
|
+
const title = input.fileName ? path7.basename(input.fileName, path7.extname(input.fileName)) : void 0;
|
|
8174
|
+
const extractedText = [title ? `# ${title}` : null, "", ...paragraphs].filter((item) => item !== null).join("\n\n").trim();
|
|
8175
|
+
return {
|
|
8176
|
+
title,
|
|
8177
|
+
extractedText: extractedText || void 0,
|
|
8178
|
+
artifact: {
|
|
8179
|
+
...extractionMetadata("rtf", input.mimeType, "rtf_text"),
|
|
8180
|
+
metadata: {
|
|
8181
|
+
paragraph_count: String(paragraphs.length)
|
|
8182
|
+
}
|
|
8183
|
+
}
|
|
8184
|
+
};
|
|
8185
|
+
} catch (error) {
|
|
8186
|
+
return {
|
|
8187
|
+
artifact: {
|
|
8188
|
+
...extractionMetadata("rtf", input.mimeType, "rtf_text"),
|
|
8189
|
+
warnings: [`RTF extraction failed: ${error instanceof Error ? truncate(error.message, 240) : "unknown error"}`]
|
|
8190
|
+
}
|
|
8191
|
+
};
|
|
8192
|
+
}
|
|
8193
|
+
}
|
|
8194
|
+
function collectOrgNodeText(node) {
|
|
8195
|
+
if (typeof node.value === "string") {
|
|
8196
|
+
return node.value;
|
|
5843
8197
|
}
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
8198
|
+
if (!Array.isArray(node.children)) {
|
|
8199
|
+
return "";
|
|
8200
|
+
}
|
|
8201
|
+
return node.children.map((child) => collectOrgNodeText(child)).join("");
|
|
8202
|
+
}
|
|
8203
|
+
function renderOrgNode(node, lines) {
|
|
8204
|
+
if (node.type === "headline") {
|
|
8205
|
+
const depth = Math.min(Math.max(node.level ?? 1, 1), 6);
|
|
8206
|
+
const keyword = node.keyword ? `${node.keyword} ` : "";
|
|
8207
|
+
const tags = node.tags?.length ? ` \`${node.tags.join(":")}\`` : "";
|
|
8208
|
+
const text = normalizeWhitespace(collectOrgNodeText(node));
|
|
8209
|
+
lines.push("");
|
|
8210
|
+
lines.push(`${"#".repeat(depth)} ${keyword}${text}${tags}`.trim());
|
|
8211
|
+
lines.push("");
|
|
8212
|
+
return;
|
|
8213
|
+
}
|
|
8214
|
+
if (node.type === "paragraph") {
|
|
8215
|
+
const text = normalizeWhitespace(collectOrgNodeText(node));
|
|
8216
|
+
if (text) {
|
|
8217
|
+
lines.push(text);
|
|
8218
|
+
lines.push("");
|
|
5847
8219
|
}
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
8220
|
+
return;
|
|
8221
|
+
}
|
|
8222
|
+
if (node.type === "list") {
|
|
8223
|
+
for (const child of node.children ?? []) {
|
|
8224
|
+
if (child.type === "list.item") {
|
|
8225
|
+
const text = normalizeWhitespace(collectOrgNodeText(child));
|
|
8226
|
+
if (text) {
|
|
8227
|
+
lines.push(`- ${text}`);
|
|
8228
|
+
}
|
|
8229
|
+
}
|
|
5853
8230
|
}
|
|
5854
|
-
|
|
5855
|
-
|
|
8231
|
+
lines.push("");
|
|
8232
|
+
return;
|
|
8233
|
+
}
|
|
8234
|
+
if (node.type === "block") {
|
|
8235
|
+
const name = node.name ?? "";
|
|
8236
|
+
const body = typeof node.value === "string" ? node.value.trimEnd() : "";
|
|
8237
|
+
if (body) {
|
|
8238
|
+
lines.push(`\`\`\`${name === "src" ? "" : name.toLowerCase()}`);
|
|
8239
|
+
lines.push(body);
|
|
8240
|
+
lines.push("```");
|
|
8241
|
+
lines.push("");
|
|
8242
|
+
}
|
|
8243
|
+
return;
|
|
8244
|
+
}
|
|
8245
|
+
for (const child of node.children ?? []) {
|
|
8246
|
+
renderOrgNode(child, lines);
|
|
8247
|
+
}
|
|
8248
|
+
}
|
|
8249
|
+
async function extractOrgText(input) {
|
|
8250
|
+
try {
|
|
8251
|
+
const orga = await import("orga");
|
|
8252
|
+
const text = decodeTextBytes(input.bytes);
|
|
8253
|
+
const document = orga.parse(text);
|
|
8254
|
+
const properties = document.properties ?? {};
|
|
8255
|
+
const documentTitle = Array.isArray(properties.title) ? properties.title.join(" ") : typeof properties.title === "string" ? properties.title : "";
|
|
8256
|
+
let headlineCount = 0;
|
|
8257
|
+
let todoCount = 0;
|
|
8258
|
+
const walk = (node) => {
|
|
8259
|
+
if (node.type === "headline") {
|
|
8260
|
+
headlineCount += 1;
|
|
8261
|
+
if (node.keyword) {
|
|
8262
|
+
todoCount += 1;
|
|
8263
|
+
}
|
|
8264
|
+
}
|
|
8265
|
+
for (const child of node.children ?? []) {
|
|
8266
|
+
walk(child);
|
|
8267
|
+
}
|
|
8268
|
+
};
|
|
8269
|
+
walk(document);
|
|
8270
|
+
const bodyLines = [];
|
|
8271
|
+
for (const child of document.children ?? []) {
|
|
8272
|
+
renderOrgNode(child, bodyLines);
|
|
8273
|
+
}
|
|
8274
|
+
const title = documentTitle.trim() || (input.fileName ? path7.basename(input.fileName, path7.extname(input.fileName)) : void 0);
|
|
8275
|
+
const extractedText = [title ? `# ${title}` : null, "", ...bodyLines].filter((item) => item !== null).join("\n").trim();
|
|
8276
|
+
return {
|
|
8277
|
+
title,
|
|
8278
|
+
extractedText: extractedText || void 0,
|
|
8279
|
+
artifact: {
|
|
8280
|
+
...extractionMetadata("org", input.mimeType, "org_text"),
|
|
8281
|
+
metadata: {
|
|
8282
|
+
headline_count: String(headlineCount),
|
|
8283
|
+
todo_count: String(todoCount)
|
|
8284
|
+
}
|
|
8285
|
+
}
|
|
8286
|
+
};
|
|
8287
|
+
} catch (error) {
|
|
8288
|
+
return {
|
|
8289
|
+
artifact: {
|
|
8290
|
+
...extractionMetadata("org", input.mimeType, "org_text"),
|
|
8291
|
+
warnings: [`Org extraction failed: ${error instanceof Error ? truncate(error.message, 240) : "unknown error"}`]
|
|
8292
|
+
}
|
|
8293
|
+
};
|
|
8294
|
+
}
|
|
8295
|
+
}
|
|
8296
|
+
async function extractAsciiDocText(input) {
|
|
8297
|
+
try {
|
|
8298
|
+
const asciidoctorModule = await import("@asciidoctor/core");
|
|
8299
|
+
const factory = asciidoctorModule.default ?? asciidoctorModule;
|
|
8300
|
+
const processor = factory();
|
|
8301
|
+
const source = decodeTextBytes(input.bytes);
|
|
8302
|
+
const loaded = processor.load(source, { safe: "safe" });
|
|
8303
|
+
const html = processor.convert(source, { safe: "safe", standalone: false });
|
|
8304
|
+
const markdown = htmlToMarkdown(html);
|
|
8305
|
+
const docTitle = (typeof loaded.getTitle === "function" ? loaded.getTitle() : void 0) ?? void 0;
|
|
8306
|
+
const fileTitle = input.fileName ? path7.basename(input.fileName, path7.extname(input.fileName)) : void 0;
|
|
8307
|
+
const title = docTitle?.trim() || fileTitle;
|
|
8308
|
+
const extractedText = [title ? `# ${title}` : null, "", markdown].filter((item) => item !== null).join("\n").trim();
|
|
8309
|
+
return {
|
|
8310
|
+
title,
|
|
8311
|
+
extractedText: extractedText || void 0,
|
|
8312
|
+
artifact: {
|
|
8313
|
+
...extractionMetadata("asciidoc", input.mimeType, "asciidoc_text"),
|
|
8314
|
+
metadata: {
|
|
8315
|
+
html_size: String(html.length),
|
|
8316
|
+
markdown_size: String(markdown.length)
|
|
8317
|
+
}
|
|
8318
|
+
}
|
|
8319
|
+
};
|
|
8320
|
+
} catch (error) {
|
|
8321
|
+
return {
|
|
8322
|
+
artifact: {
|
|
8323
|
+
...extractionMetadata("asciidoc", input.mimeType, "asciidoc_text"),
|
|
8324
|
+
warnings: [`AsciiDoc extraction failed: ${error instanceof Error ? truncate(error.message, 240) : "unknown error"}`]
|
|
8325
|
+
}
|
|
8326
|
+
};
|
|
5856
8327
|
}
|
|
5857
|
-
return entries;
|
|
5858
8328
|
}
|
|
5859
8329
|
async function extractTranscriptText(input) {
|
|
5860
8330
|
try {
|
|
@@ -6624,7 +9094,7 @@ function inferKind(mimeType, filePath, detectionOptions = {}) {
|
|
|
6624
9094
|
if (isTranscriptFilePath(filePath) || mimeType === "application/x-subrip" || mimeType === "text/vtt") {
|
|
6625
9095
|
return "transcript";
|
|
6626
9096
|
}
|
|
6627
|
-
if (mimeType.includes("markdown")) {
|
|
9097
|
+
if (mimeType.includes("markdown") || filePath.toLowerCase().endsWith(".mdx")) {
|
|
6628
9098
|
return "markdown";
|
|
6629
9099
|
}
|
|
6630
9100
|
if (mimeType.includes("html")) {
|
|
@@ -6633,7 +9103,7 @@ function inferKind(mimeType, filePath, detectionOptions = {}) {
|
|
|
6633
9103
|
if (mimeType === "application/pdf" || filePath.toLowerCase().endsWith(".pdf")) {
|
|
6634
9104
|
return "pdf";
|
|
6635
9105
|
}
|
|
6636
|
-
if (mimeType === "application/vnd.openxmlformats-officedocument.wordprocessingml.document" || filePath.toLowerCase().endsWith(".docx")) {
|
|
9106
|
+
if (mimeType === "application/vnd.openxmlformats-officedocument.wordprocessingml.document" || mimeType === "application/vnd.ms-word.document.macroenabled.12" || mimeType === "application/vnd.ms-word.template.macroenabled.12" || mimeType === "application/vnd.openxmlformats-officedocument.wordprocessingml.template" || filePath.toLowerCase().endsWith(".docx") || filePath.toLowerCase().endsWith(".docm") || filePath.toLowerCase().endsWith(".dotx") || filePath.toLowerCase().endsWith(".dotm")) {
|
|
6637
9107
|
return "docx";
|
|
6638
9108
|
}
|
|
6639
9109
|
if (isEmailFilePath(filePath) || mimeType === "message/rfc822" || mimeType === "application/mbox") {
|
|
@@ -6648,20 +9118,66 @@ function inferKind(mimeType, filePath, detectionOptions = {}) {
|
|
|
6648
9118
|
if (mimeType === "text/csv" || mimeType === "text/tab-separated-values" || filePath.toLowerCase().endsWith(".csv") || filePath.toLowerCase().endsWith(".tsv")) {
|
|
6649
9119
|
return "csv";
|
|
6650
9120
|
}
|
|
9121
|
+
if (mimeType === "application/x-ipynb+json" || filePath.toLowerCase().endsWith(".ipynb")) {
|
|
9122
|
+
return "jupyter";
|
|
9123
|
+
}
|
|
9124
|
+
if (mimeType === "application/vnd.oasis.opendocument.text" || filePath.toLowerCase().endsWith(".odt")) {
|
|
9125
|
+
return "odt";
|
|
9126
|
+
}
|
|
9127
|
+
if (mimeType === "application/vnd.oasis.opendocument.presentation" || filePath.toLowerCase().endsWith(".odp")) {
|
|
9128
|
+
return "odp";
|
|
9129
|
+
}
|
|
9130
|
+
if (mimeType === "application/vnd.oasis.opendocument.spreadsheet" || filePath.toLowerCase().endsWith(".ods")) {
|
|
9131
|
+
return "ods";
|
|
9132
|
+
}
|
|
9133
|
+
if (filePath.toLowerCase().endsWith(".bib") || mimeType === "application/x-bibtex") {
|
|
9134
|
+
return "bibtex";
|
|
9135
|
+
}
|
|
9136
|
+
if (mimeType === "application/rtf" || mimeType === "text/rtf" || filePath.toLowerCase().endsWith(".rtf")) {
|
|
9137
|
+
return "rtf";
|
|
9138
|
+
}
|
|
9139
|
+
if (filePath.toLowerCase().endsWith(".org") || mimeType === "text/x-org") {
|
|
9140
|
+
return "org";
|
|
9141
|
+
}
|
|
9142
|
+
if (filePath.toLowerCase().endsWith(".adoc") || filePath.toLowerCase().endsWith(".asciidoc") || mimeType === "text/x-asciidoc") {
|
|
9143
|
+
return "asciidoc";
|
|
9144
|
+
}
|
|
9145
|
+
if (isStructuredDataPath(filePath, mimeType)) {
|
|
9146
|
+
return "data";
|
|
9147
|
+
}
|
|
6651
9148
|
if (mimeType.startsWith("text/") || isStructuredTextMime(mimeType)) {
|
|
6652
9149
|
return "text";
|
|
6653
9150
|
}
|
|
6654
|
-
if (mimeType === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" || filePath.toLowerCase().endsWith(".xlsx")) {
|
|
9151
|
+
if (mimeType === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" || mimeType === "application/vnd.ms-excel" || mimeType === "application/vnd.ms-excel.sheet.macroenabled.12" || mimeType === "application/vnd.ms-excel.template.macroenabled.12" || mimeType === "application/vnd.openxmlformats-officedocument.spreadsheetml.template" || filePath.toLowerCase().endsWith(".xlsx") || filePath.toLowerCase().endsWith(".xlsm") || filePath.toLowerCase().endsWith(".xltx") || filePath.toLowerCase().endsWith(".xltm") || filePath.toLowerCase().endsWith(".xls")) {
|
|
6655
9152
|
return "xlsx";
|
|
6656
9153
|
}
|
|
6657
|
-
if (mimeType === "application/vnd.openxmlformats-officedocument.presentationml.presentation" || filePath.toLowerCase().endsWith(".pptx")) {
|
|
9154
|
+
if (mimeType === "application/vnd.openxmlformats-officedocument.presentationml.presentation" || mimeType === "application/vnd.ms-powerpoint.presentation.macroenabled.12" || mimeType === "application/vnd.ms-powerpoint.template.macroenabled.12" || mimeType === "application/vnd.openxmlformats-officedocument.presentationml.template" || filePath.toLowerCase().endsWith(".pptx") || filePath.toLowerCase().endsWith(".pptm") || filePath.toLowerCase().endsWith(".potx") || filePath.toLowerCase().endsWith(".potm")) {
|
|
6658
9155
|
return "pptx";
|
|
6659
9156
|
}
|
|
6660
|
-
if (mimeType.startsWith("image/")) {
|
|
9157
|
+
if (mimeType.startsWith("image/") || isImagePath(filePath)) {
|
|
6661
9158
|
return "image";
|
|
6662
9159
|
}
|
|
6663
9160
|
return "binary";
|
|
6664
9161
|
}
|
|
9162
|
+
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
9163
|
+
".png",
|
|
9164
|
+
".jpg",
|
|
9165
|
+
".jpeg",
|
|
9166
|
+
".webp",
|
|
9167
|
+
".gif",
|
|
9168
|
+
".bmp",
|
|
9169
|
+
".ico",
|
|
9170
|
+
".tiff",
|
|
9171
|
+
".tif",
|
|
9172
|
+
".heic",
|
|
9173
|
+
".heif",
|
|
9174
|
+
".avif",
|
|
9175
|
+
".jxl",
|
|
9176
|
+
".svg"
|
|
9177
|
+
]);
|
|
9178
|
+
function isImagePath(filePath) {
|
|
9179
|
+
return IMAGE_EXTENSIONS.has(path12.extname(filePath).toLowerCase());
|
|
9180
|
+
}
|
|
6665
9181
|
function isStructuredTextMime(mimeType) {
|
|
6666
9182
|
switch (mimeType) {
|
|
6667
9183
|
case "application/json":
|
|
@@ -6682,6 +9198,23 @@ function isStructuredTextMime(mimeType) {
|
|
|
6682
9198
|
return false;
|
|
6683
9199
|
}
|
|
6684
9200
|
}
|
|
9201
|
+
function isStructuredDataPath(filePath, mimeType) {
|
|
9202
|
+
const lower = filePath.toLowerCase();
|
|
9203
|
+
if (lower.endsWith(".yaml") || lower.endsWith(".yml") || lower.endsWith(".toml") || mimeType === "application/toml" || mimeType === "application/yaml" || mimeType === "application/x-yaml") {
|
|
9204
|
+
return true;
|
|
9205
|
+
}
|
|
9206
|
+
if (lower.endsWith(".xml") || lower.endsWith(".ini") || lower.endsWith(".env") || lower.endsWith(".properties") || lower.endsWith(".conf") || lower.endsWith(".cfg") || mimeType === "application/xml" || mimeType === "text/xml") {
|
|
9207
|
+
return true;
|
|
9208
|
+
}
|
|
9209
|
+
if (lower.endsWith(".json") || lower.endsWith(".jsonc") || lower.endsWith(".json5") || mimeType === "application/json" || mimeType === "application/json5") {
|
|
9210
|
+
const base = path12.basename(lower);
|
|
9211
|
+
if (base === "package.json" || base === "package-lock.json" || base === "tsconfig.json" || base === "pnpm-lock.yaml") {
|
|
9212
|
+
return false;
|
|
9213
|
+
}
|
|
9214
|
+
return true;
|
|
9215
|
+
}
|
|
9216
|
+
return false;
|
|
9217
|
+
}
|
|
6685
9218
|
async function localCodeDetectionOptions(absolutePath, payloadBytes) {
|
|
6686
9219
|
if (path12.extname(absolutePath)) {
|
|
6687
9220
|
return {};
|
|
@@ -6723,8 +9256,7 @@ function titleFromText(fallback, content, filePath) {
|
|
|
6723
9256
|
return rstTitle;
|
|
6724
9257
|
}
|
|
6725
9258
|
}
|
|
6726
|
-
|
|
6727
|
-
return heading || fallback;
|
|
9259
|
+
return firstMarkdownHeading(content) ?? fallback;
|
|
6728
9260
|
}
|
|
6729
9261
|
function guessMimeType(target) {
|
|
6730
9262
|
if (isRstFilePath(target)) {
|
|
@@ -6888,8 +9420,7 @@ function normalizeRstExtractedText(content) {
|
|
|
6888
9420
|
}
|
|
6889
9421
|
function titleFromRst(fallback, content) {
|
|
6890
9422
|
const normalized = normalizeRstExtractedText(content);
|
|
6891
|
-
|
|
6892
|
-
return heading || fallback;
|
|
9423
|
+
return firstMarkdownHeading(normalized) ?? fallback;
|
|
6893
9424
|
}
|
|
6894
9425
|
function extractedTextForPlainSource(filePath, sourceKind, content) {
|
|
6895
9426
|
if (sourceKind === "text" && isRstFilePath(filePath)) {
|
|
@@ -8339,6 +10870,60 @@ async function prepareFileInputs(rootDir, absoluteInput, repoRoot, sourceClass)
|
|
|
8339
10870
|
title = extracted.title?.trim() || title;
|
|
8340
10871
|
extractedText = extracted.extractedText;
|
|
8341
10872
|
extractionArtifact = extracted.artifact;
|
|
10873
|
+
} else if (sourceKind === "jupyter") {
|
|
10874
|
+
title = path12.basename(absoluteInput, path12.extname(absoluteInput));
|
|
10875
|
+
const extracted = await extractJupyterNotebook({ mimeType, bytes: payloadBytes, fileName: absoluteInput });
|
|
10876
|
+
title = extracted.title?.trim() || title;
|
|
10877
|
+
extractedText = extracted.extractedText;
|
|
10878
|
+
extractionArtifact = extracted.artifact;
|
|
10879
|
+
} else if (sourceKind === "odt") {
|
|
10880
|
+
title = path12.basename(absoluteInput, path12.extname(absoluteInput));
|
|
10881
|
+
const extracted = await extractOdtText({ mimeType, bytes: payloadBytes, fileName: absoluteInput });
|
|
10882
|
+
title = extracted.title?.trim() || title;
|
|
10883
|
+
extractedText = extracted.extractedText;
|
|
10884
|
+
extractionArtifact = extracted.artifact;
|
|
10885
|
+
} else if (sourceKind === "odp") {
|
|
10886
|
+
title = path12.basename(absoluteInput, path12.extname(absoluteInput));
|
|
10887
|
+
const extracted = await extractOdpText({ mimeType, bytes: payloadBytes, fileName: absoluteInput });
|
|
10888
|
+
title = extracted.title?.trim() || title;
|
|
10889
|
+
extractedText = extracted.extractedText;
|
|
10890
|
+
extractionArtifact = extracted.artifact;
|
|
10891
|
+
} else if (sourceKind === "ods") {
|
|
10892
|
+
title = path12.basename(absoluteInput, path12.extname(absoluteInput));
|
|
10893
|
+
const extracted = await extractOdsText({ mimeType, bytes: payloadBytes, fileName: absoluteInput });
|
|
10894
|
+
title = extracted.title?.trim() || title;
|
|
10895
|
+
extractedText = extracted.extractedText;
|
|
10896
|
+
extractionArtifact = extracted.artifact;
|
|
10897
|
+
} else if (sourceKind === "data") {
|
|
10898
|
+
title = path12.basename(absoluteInput, path12.extname(absoluteInput));
|
|
10899
|
+
const extracted = await extractStructuredData({ mimeType, bytes: payloadBytes, fileName: absoluteInput });
|
|
10900
|
+
title = extracted.title?.trim() || title;
|
|
10901
|
+
extractedText = extracted.extractedText;
|
|
10902
|
+
extractionArtifact = extracted.artifact;
|
|
10903
|
+
} else if (sourceKind === "bibtex") {
|
|
10904
|
+
title = path12.basename(absoluteInput, path12.extname(absoluteInput));
|
|
10905
|
+
const extracted = await extractBibTeXText({ mimeType, bytes: payloadBytes, fileName: absoluteInput });
|
|
10906
|
+
title = extracted.title?.trim() || title;
|
|
10907
|
+
extractedText = extracted.extractedText;
|
|
10908
|
+
extractionArtifact = extracted.artifact;
|
|
10909
|
+
} else if (sourceKind === "rtf") {
|
|
10910
|
+
title = path12.basename(absoluteInput, path12.extname(absoluteInput));
|
|
10911
|
+
const extracted = await extractRtfText({ mimeType, bytes: payloadBytes, fileName: absoluteInput });
|
|
10912
|
+
title = extracted.title?.trim() || title;
|
|
10913
|
+
extractedText = extracted.extractedText;
|
|
10914
|
+
extractionArtifact = extracted.artifact;
|
|
10915
|
+
} else if (sourceKind === "org") {
|
|
10916
|
+
title = path12.basename(absoluteInput, path12.extname(absoluteInput));
|
|
10917
|
+
const extracted = await extractOrgText({ mimeType, bytes: payloadBytes, fileName: absoluteInput });
|
|
10918
|
+
title = extracted.title?.trim() || title;
|
|
10919
|
+
extractedText = extracted.extractedText;
|
|
10920
|
+
extractionArtifact = extracted.artifact;
|
|
10921
|
+
} else if (sourceKind === "asciidoc") {
|
|
10922
|
+
title = path12.basename(absoluteInput, path12.extname(absoluteInput));
|
|
10923
|
+
const extracted = await extractAsciiDocText({ mimeType, bytes: payloadBytes, fileName: absoluteInput });
|
|
10924
|
+
title = extracted.title?.trim() || title;
|
|
10925
|
+
extractedText = extracted.extractedText;
|
|
10926
|
+
extractionArtifact = extracted.artifact;
|
|
8342
10927
|
} else if (sourceKind === "epub") {
|
|
8343
10928
|
title = path12.basename(absoluteInput, path12.extname(absoluteInput));
|
|
8344
10929
|
const extracted = await extractEpubChapters({ mimeType, bytes: payloadBytes, fileName: absoluteInput });
|
|
@@ -8665,7 +11250,11 @@ async function collectInboxAttachmentRefs(inputDir, files) {
|
|
|
8665
11250
|
for (const absolutePath of files) {
|
|
8666
11251
|
const mimeType = guessMimeType(absolutePath);
|
|
8667
11252
|
const detectionOptions = await localCodeDetectionOptions(absolutePath);
|
|
8668
|
-
|
|
11253
|
+
let sourceKind = inferKind(mimeType, absolutePath, detectionOptions);
|
|
11254
|
+
const lowerExt = path12.extname(absolutePath).toLowerCase();
|
|
11255
|
+
if ((lowerExt === ".html" || lowerExt === ".htm") && sourceKind === "code") {
|
|
11256
|
+
sourceKind = "html";
|
|
11257
|
+
}
|
|
8669
11258
|
if (sourceKind !== "markdown" && sourceKind !== "html") {
|
|
8670
11259
|
continue;
|
|
8671
11260
|
}
|
|
@@ -9009,7 +11598,11 @@ async function importInbox(rootDir, inputDir) {
|
|
|
9009
11598
|
const mimeType = guessMimeType(absolutePath);
|
|
9010
11599
|
const detectionOptions = await localCodeDetectionOptions(absolutePath);
|
|
9011
11600
|
let sourceKind = inferKind(mimeType, absolutePath, detectionOptions);
|
|
9012
|
-
|
|
11601
|
+
const lowerExt = path12.extname(absolutePath).toLowerCase();
|
|
11602
|
+
if ((lowerExt === ".html" || lowerExt === ".htm") && sourceKind === "code") {
|
|
11603
|
+
sourceKind = "html";
|
|
11604
|
+
}
|
|
11605
|
+
if (sourceKind === "binary" && lowerExt === ".zip") {
|
|
9013
11606
|
const bytes = await fs11.readFile(absolutePath);
|
|
9014
11607
|
if (isSlackExportArchive(bytes)) {
|
|
9015
11608
|
sourceKind = "chat_export";
|
|
@@ -9213,9 +11806,55 @@ import { z as z7 } from "zod";
|
|
|
9213
11806
|
|
|
9214
11807
|
// src/analysis.ts
|
|
9215
11808
|
import path14 from "path";
|
|
9216
|
-
import
|
|
9217
|
-
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
11809
|
+
import nlp2 from "compromise";
|
|
9218
11810
|
import { z as z2 } from "zod";
|
|
11811
|
+
|
|
11812
|
+
// src/tokenize.ts
|
|
11813
|
+
import nlp from "compromise";
|
|
11814
|
+
var CLOSED_CLASS_POS_SELECTOR = "#Determiner, #Preposition, #Conjunction, #Pronoun, #Auxiliary, #Copula";
|
|
11815
|
+
function splitTermToTokens(term, tokens) {
|
|
11816
|
+
for (const piece of term.split(/[^a-z0-9-]+/)) {
|
|
11817
|
+
const trimmed = piece.replace(/^-+|-+$/g, "");
|
|
11818
|
+
if (trimmed.length >= 2) {
|
|
11819
|
+
tokens.push(trimmed);
|
|
11820
|
+
}
|
|
11821
|
+
}
|
|
11822
|
+
}
|
|
11823
|
+
function tokenize(text) {
|
|
11824
|
+
const lower = text.toLowerCase();
|
|
11825
|
+
try {
|
|
11826
|
+
const terms = nlp(lower).terms().out("array");
|
|
11827
|
+
const tokens = [];
|
|
11828
|
+
for (const term of terms) {
|
|
11829
|
+
splitTermToTokens(term, tokens);
|
|
11830
|
+
}
|
|
11831
|
+
if (tokens.length > 0) {
|
|
11832
|
+
return tokens;
|
|
11833
|
+
}
|
|
11834
|
+
} catch {
|
|
11835
|
+
}
|
|
11836
|
+
return lower.match(/[a-z0-9][a-z0-9-]{1,}/g) ?? [];
|
|
11837
|
+
}
|
|
11838
|
+
function contentTokens(text, minLength = 4) {
|
|
11839
|
+
const lower = text.toLowerCase();
|
|
11840
|
+
const tokens = [];
|
|
11841
|
+
try {
|
|
11842
|
+
const contentDoc = nlp(lower).not(CLOSED_CLASS_POS_SELECTOR);
|
|
11843
|
+
const terms = contentDoc.terms().out("array");
|
|
11844
|
+
for (const term of terms) {
|
|
11845
|
+
splitTermToTokens(term, tokens);
|
|
11846
|
+
}
|
|
11847
|
+
} catch {
|
|
11848
|
+
}
|
|
11849
|
+
if (tokens.length === 0) {
|
|
11850
|
+
for (const piece of lower.match(/[a-z0-9][a-z0-9-]{1,}/g) ?? []) {
|
|
11851
|
+
tokens.push(piece);
|
|
11852
|
+
}
|
|
11853
|
+
}
|
|
11854
|
+
return tokens.filter((token) => token.length >= minLength);
|
|
11855
|
+
}
|
|
11856
|
+
|
|
11857
|
+
// src/analysis.ts
|
|
9219
11858
|
var ANALYSIS_FORMAT_VERSION = 7;
|
|
9220
11859
|
var sourceAnalysisSchema = z2.object({
|
|
9221
11860
|
title: z2.string().min(1),
|
|
@@ -9234,46 +11873,6 @@ var sourceAnalysisSchema = z2.object({
|
|
|
9234
11873
|
questions: z2.array(z2.string()).max(6).default([]),
|
|
9235
11874
|
tags: z2.array(z2.string()).max(5).default([])
|
|
9236
11875
|
});
|
|
9237
|
-
var STOPWORDS = /* @__PURE__ */ new Set([
|
|
9238
|
-
"about",
|
|
9239
|
-
"after",
|
|
9240
|
-
"also",
|
|
9241
|
-
"been",
|
|
9242
|
-
"being",
|
|
9243
|
-
"between",
|
|
9244
|
-
"both",
|
|
9245
|
-
"could",
|
|
9246
|
-
"does",
|
|
9247
|
-
"each",
|
|
9248
|
-
"from",
|
|
9249
|
-
"have",
|
|
9250
|
-
"into",
|
|
9251
|
-
"just",
|
|
9252
|
-
"more",
|
|
9253
|
-
"much",
|
|
9254
|
-
"only",
|
|
9255
|
-
"other",
|
|
9256
|
-
"over",
|
|
9257
|
-
"same",
|
|
9258
|
-
"some",
|
|
9259
|
-
"such",
|
|
9260
|
-
"than",
|
|
9261
|
-
"that",
|
|
9262
|
-
"their",
|
|
9263
|
-
"there",
|
|
9264
|
-
"these",
|
|
9265
|
-
"they",
|
|
9266
|
-
"this",
|
|
9267
|
-
"very",
|
|
9268
|
-
"what",
|
|
9269
|
-
"when",
|
|
9270
|
-
"where",
|
|
9271
|
-
"which",
|
|
9272
|
-
"while",
|
|
9273
|
-
"with",
|
|
9274
|
-
"would",
|
|
9275
|
-
"your"
|
|
9276
|
-
]);
|
|
9277
11876
|
var HEURISTIC_SECTION_SOURCE_KINDS = /* @__PURE__ */ new Map([
|
|
9278
11877
|
["transcript", "Transcript"],
|
|
9279
11878
|
["chat_export", "Messages"],
|
|
@@ -9282,10 +11881,7 @@ var HEURISTIC_SECTION_SOURCE_KINDS = /* @__PURE__ */ new Map([
|
|
|
9282
11881
|
]);
|
|
9283
11882
|
function extractTopTerms(text, count) {
|
|
9284
11883
|
const frequency = /* @__PURE__ */ new Map();
|
|
9285
|
-
for (const token of text
|
|
9286
|
-
if (STOPWORDS.has(token)) {
|
|
9287
|
-
continue;
|
|
9288
|
-
}
|
|
11884
|
+
for (const token of contentTokens(text)) {
|
|
9289
11885
|
frequency.set(token, (frequency.get(token) ?? 0) + 1);
|
|
9290
11886
|
}
|
|
9291
11887
|
return [...frequency.entries()].sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0])).slice(0, count).map(([token]) => token);
|
|
@@ -9293,7 +11889,7 @@ function extractTopTerms(text, count) {
|
|
|
9293
11889
|
function extractEntities(text, count) {
|
|
9294
11890
|
const candidates = [];
|
|
9295
11891
|
try {
|
|
9296
|
-
const doc =
|
|
11892
|
+
const doc = nlp2(text);
|
|
9297
11893
|
const segments = [
|
|
9298
11894
|
doc.match("#ProperNoun+").out("array"),
|
|
9299
11895
|
doc.people().out("array"),
|
|
@@ -9311,10 +11907,6 @@ function extractEntities(text, count) {
|
|
|
9311
11907
|
}
|
|
9312
11908
|
} catch {
|
|
9313
11909
|
}
|
|
9314
|
-
if (candidates.length === 0) {
|
|
9315
|
-
const matches = text.match(/\b[A-Z][A-Za-z0-9-]+(?:\s+[A-Z][A-Za-z0-9-]+){0,2}\b/g) ?? [];
|
|
9316
|
-
candidates.push(...matches.map((value) => normalizeWhitespace(value)));
|
|
9317
|
-
}
|
|
9318
11910
|
return uniqueBy(candidates, (value) => value.toLowerCase()).slice(0, count);
|
|
9319
11911
|
}
|
|
9320
11912
|
function detectPolarity(text) {
|
|
@@ -9326,26 +11918,6 @@ function detectPolarity(text) {
|
|
|
9326
11918
|
}
|
|
9327
11919
|
return "neutral";
|
|
9328
11920
|
}
|
|
9329
|
-
function parseMarkdownNodes(text) {
|
|
9330
|
-
try {
|
|
9331
|
-
const root = fromMarkdown(text);
|
|
9332
|
-
return Array.isArray(root.children) ? root.children : [];
|
|
9333
|
-
} catch {
|
|
9334
|
-
return [];
|
|
9335
|
-
}
|
|
9336
|
-
}
|
|
9337
|
-
function markdownNodeText(node) {
|
|
9338
|
-
if (node.type === "text" || node.type === "inlineCode" || node.type === "code") {
|
|
9339
|
-
return normalizeWhitespace(node.value ?? "");
|
|
9340
|
-
}
|
|
9341
|
-
if (node.type === "image") {
|
|
9342
|
-
return normalizeWhitespace(node.alt ?? "");
|
|
9343
|
-
}
|
|
9344
|
-
if (node.type === "break" || node.type === "thematicBreak") {
|
|
9345
|
-
return " ";
|
|
9346
|
-
}
|
|
9347
|
-
return normalizeWhitespace((node.children ?? []).map((child) => markdownNodeText(child)).join(" "));
|
|
9348
|
-
}
|
|
9349
11921
|
function markdownNodesText(nodes) {
|
|
9350
11922
|
return normalizeWhitespace(nodes.map((node) => markdownNodeText(node)).join("\n"));
|
|
9351
11923
|
}
|
|
@@ -10620,7 +13192,7 @@ function filterGraphBySourceClass(graph, sourceClass) {
|
|
|
10620
13192
|
}
|
|
10621
13193
|
|
|
10622
13194
|
// src/graph-enrichment.ts
|
|
10623
|
-
var
|
|
13195
|
+
var STOPWORDS = /* @__PURE__ */ new Set([
|
|
10624
13196
|
"about",
|
|
10625
13197
|
"after",
|
|
10626
13198
|
"also",
|
|
@@ -10684,7 +13256,7 @@ function addFeature(bucket, reason, value) {
|
|
|
10684
13256
|
}
|
|
10685
13257
|
function themeTokens(value) {
|
|
10686
13258
|
return uniqueBy(
|
|
10687
|
-
normalizeValue(value).split(/[^a-z0-9]+/i).filter((token) => token.length >= 4 && !
|
|
13259
|
+
normalizeValue(value).split(/[^a-z0-9]+/i).filter((token) => token.length >= 4 && !STOPWORDS.has(token)),
|
|
10688
13260
|
(token) => token
|
|
10689
13261
|
).slice(0, 6);
|
|
10690
13262
|
}
|
|
@@ -13319,8 +15891,7 @@ function getDatabaseSync() {
|
|
|
13319
15891
|
return builtin.DatabaseSync;
|
|
13320
15892
|
}
|
|
13321
15893
|
function toFtsQuery(query) {
|
|
13322
|
-
|
|
13323
|
-
return tokens.join(" OR ");
|
|
15894
|
+
return tokenize(query).join(" OR ");
|
|
13324
15895
|
}
|
|
13325
15896
|
function normalizeKind(value) {
|
|
13326
15897
|
return value === "index" || value === "source" || value === "module" || value === "concept" || value === "entity" || value === "output" || value === "insight" || value === "graph_report" || value === "community_summary" ? value : void 0;
|
|
@@ -13749,7 +16320,7 @@ async function resolveImageGenerationProvider(rootDir) {
|
|
|
13749
16320
|
if (!providerConfig) {
|
|
13750
16321
|
throw new Error(`No provider configured with id "${preferredProviderId}" for task "imageProvider".`);
|
|
13751
16322
|
}
|
|
13752
|
-
const { createProvider: createProvider2 } = await import("./registry-
|
|
16323
|
+
const { createProvider: createProvider2 } = await import("./registry-W6ZFRI73.js");
|
|
13753
16324
|
return createProvider2(preferredProviderId, providerConfig, rootDir);
|
|
13754
16325
|
}
|
|
13755
16326
|
async function generateOutputArtifacts(rootDir, input) {
|
|
@@ -18016,7 +20587,7 @@ async function bootstrapDemo(rootDir, input) {
|
|
|
18016
20587
|
}
|
|
18017
20588
|
|
|
18018
20589
|
// src/mcp.ts
|
|
18019
|
-
var SERVER_VERSION = "0.
|
|
20590
|
+
var SERVER_VERSION = "0.7.0";
|
|
18020
20591
|
async function createMcpServer(rootDir) {
|
|
18021
20592
|
const server = new McpServer({
|
|
18022
20593
|
name: "swarmvault",
|
|
@@ -18028,10 +20599,10 @@ async function createMcpServer(rootDir) {
|
|
|
18028
20599
|
{
|
|
18029
20600
|
description: "Return the current SwarmVault workspace paths and high-level counts."
|
|
18030
20601
|
},
|
|
18031
|
-
async () => {
|
|
20602
|
+
safeHandler(async () => {
|
|
18032
20603
|
const info = await getWorkspaceInfo(rootDir);
|
|
18033
20604
|
return asToolText(info);
|
|
18034
|
-
}
|
|
20605
|
+
})
|
|
18035
20606
|
);
|
|
18036
20607
|
server.registerTool(
|
|
18037
20608
|
"search_pages",
|
|
@@ -18042,10 +20613,10 @@ async function createMcpServer(rootDir) {
|
|
|
18042
20613
|
limit: z8.number().int().min(1).max(25).optional().describe("Maximum number of results")
|
|
18043
20614
|
}
|
|
18044
20615
|
},
|
|
18045
|
-
async ({ query, limit }) => {
|
|
20616
|
+
safeHandler(async ({ query, limit }) => {
|
|
18046
20617
|
const results = await searchVault(rootDir, query, limit ?? 5);
|
|
18047
20618
|
return asToolText(results);
|
|
18048
|
-
}
|
|
20619
|
+
})
|
|
18049
20620
|
);
|
|
18050
20621
|
server.registerTool(
|
|
18051
20622
|
"read_page",
|
|
@@ -18055,13 +20626,13 @@ async function createMcpServer(rootDir) {
|
|
|
18055
20626
|
path: z8.string().min(1).describe("Path relative to wiki/, for example sources/example.md")
|
|
18056
20627
|
}
|
|
18057
20628
|
},
|
|
18058
|
-
async ({ path: relativePath }) => {
|
|
20629
|
+
safeHandler(async ({ path: relativePath }) => {
|
|
18059
20630
|
const page = await readPage(rootDir, relativePath);
|
|
18060
20631
|
if (!page) {
|
|
18061
20632
|
return asToolError(`Page not found: ${relativePath}`);
|
|
18062
20633
|
}
|
|
18063
20634
|
return asToolText(page);
|
|
18064
|
-
}
|
|
20635
|
+
})
|
|
18065
20636
|
);
|
|
18066
20637
|
server.registerTool(
|
|
18067
20638
|
"list_sources",
|
|
@@ -18071,10 +20642,10 @@ async function createMcpServer(rootDir) {
|
|
|
18071
20642
|
limit: z8.number().int().min(1).max(100).optional().describe("Maximum number of manifests to return")
|
|
18072
20643
|
}
|
|
18073
20644
|
},
|
|
18074
|
-
async ({ limit }) => {
|
|
20645
|
+
safeHandler(async ({ limit }) => {
|
|
18075
20646
|
const manifests = await listManifests(rootDir);
|
|
18076
20647
|
return asToolText(limit ? manifests.slice(0, limit) : manifests);
|
|
18077
|
-
}
|
|
20648
|
+
})
|
|
18078
20649
|
);
|
|
18079
20650
|
server.registerTool(
|
|
18080
20651
|
"query_graph",
|
|
@@ -18086,22 +20657,22 @@ async function createMcpServer(rootDir) {
|
|
|
18086
20657
|
budget: z8.number().int().min(3).max(50).optional().describe("Maximum nodes to summarize")
|
|
18087
20658
|
}
|
|
18088
20659
|
},
|
|
18089
|
-
async ({ question, traversal, budget }) => {
|
|
20660
|
+
safeHandler(async ({ question, traversal, budget }) => {
|
|
18090
20661
|
const result = await queryGraphVault(rootDir, question, {
|
|
18091
20662
|
traversal,
|
|
18092
20663
|
budget
|
|
18093
20664
|
});
|
|
18094
20665
|
return asToolText(result);
|
|
18095
|
-
}
|
|
20666
|
+
})
|
|
18096
20667
|
);
|
|
18097
20668
|
server.registerTool(
|
|
18098
20669
|
"graph_report",
|
|
18099
20670
|
{
|
|
18100
20671
|
description: "Return the machine-readable graph report and trust artifact."
|
|
18101
20672
|
},
|
|
18102
|
-
async () => {
|
|
20673
|
+
safeHandler(async () => {
|
|
18103
20674
|
return asToolText(await readGraphReport(rootDir) ?? { error: "Graph report not found. Run `swarmvault compile` first." });
|
|
18104
|
-
}
|
|
20675
|
+
})
|
|
18105
20676
|
);
|
|
18106
20677
|
server.registerTool(
|
|
18107
20678
|
"get_node",
|
|
@@ -18111,9 +20682,9 @@ async function createMcpServer(rootDir) {
|
|
|
18111
20682
|
target: z8.string().min(1).describe("Node or page label/id")
|
|
18112
20683
|
}
|
|
18113
20684
|
},
|
|
18114
|
-
async ({ target }) => {
|
|
20685
|
+
safeHandler(async ({ target }) => {
|
|
18115
20686
|
return asToolText(await explainGraphVault(rootDir, target));
|
|
18116
|
-
}
|
|
20687
|
+
})
|
|
18117
20688
|
);
|
|
18118
20689
|
server.registerTool(
|
|
18119
20690
|
"get_hyperedges",
|
|
@@ -18124,9 +20695,9 @@ async function createMcpServer(rootDir) {
|
|
|
18124
20695
|
limit: z8.number().int().min(1).max(50).optional().describe("Maximum hyperedges to return")
|
|
18125
20696
|
}
|
|
18126
20697
|
},
|
|
18127
|
-
async ({ target, limit }) => {
|
|
20698
|
+
safeHandler(async ({ target, limit }) => {
|
|
18128
20699
|
return asToolText(await listGraphHyperedges(rootDir, target, limit ?? 25));
|
|
18129
|
-
}
|
|
20700
|
+
})
|
|
18130
20701
|
);
|
|
18131
20702
|
server.registerTool(
|
|
18132
20703
|
"get_neighbors",
|
|
@@ -18136,10 +20707,10 @@ async function createMcpServer(rootDir) {
|
|
|
18136
20707
|
target: z8.string().min(1).describe("Node or page label/id")
|
|
18137
20708
|
}
|
|
18138
20709
|
},
|
|
18139
|
-
async ({ target }) => {
|
|
20710
|
+
safeHandler(async ({ target }) => {
|
|
18140
20711
|
const explanation = await explainGraphVault(rootDir, target);
|
|
18141
20712
|
return asToolText(explanation.neighbors);
|
|
18142
|
-
}
|
|
20713
|
+
})
|
|
18143
20714
|
);
|
|
18144
20715
|
server.registerTool(
|
|
18145
20716
|
"shortest_path",
|
|
@@ -18150,9 +20721,9 @@ async function createMcpServer(rootDir) {
|
|
|
18150
20721
|
to: z8.string().min(1).describe("End node/page label or id")
|
|
18151
20722
|
}
|
|
18152
20723
|
},
|
|
18153
|
-
async ({ from, to }) => {
|
|
20724
|
+
safeHandler(async ({ from, to }) => {
|
|
18154
20725
|
return asToolText(await pathGraphVault(rootDir, from, to));
|
|
18155
|
-
}
|
|
20726
|
+
})
|
|
18156
20727
|
);
|
|
18157
20728
|
server.registerTool(
|
|
18158
20729
|
"god_nodes",
|
|
@@ -18162,9 +20733,9 @@ async function createMcpServer(rootDir) {
|
|
|
18162
20733
|
limit: z8.number().int().min(1).max(25).optional().describe("Maximum nodes to return")
|
|
18163
20734
|
}
|
|
18164
20735
|
},
|
|
18165
|
-
async ({ limit }) => {
|
|
20736
|
+
safeHandler(async ({ limit }) => {
|
|
18166
20737
|
return asToolText(await listGodNodes(rootDir, limit ?? 10));
|
|
18167
|
-
}
|
|
20738
|
+
})
|
|
18168
20739
|
);
|
|
18169
20740
|
server.registerTool(
|
|
18170
20741
|
"query_vault",
|
|
@@ -18176,14 +20747,14 @@ async function createMcpServer(rootDir) {
|
|
|
18176
20747
|
format: z8.enum(["markdown", "report", "slides", "chart", "image"]).optional().describe("Output format")
|
|
18177
20748
|
}
|
|
18178
20749
|
},
|
|
18179
|
-
async ({ question, save, format }) => {
|
|
20750
|
+
safeHandler(async ({ question, save, format }) => {
|
|
18180
20751
|
const result = await queryVault(rootDir, {
|
|
18181
20752
|
question,
|
|
18182
20753
|
save: save ?? true,
|
|
18183
20754
|
format
|
|
18184
20755
|
});
|
|
18185
20756
|
return asToolText(result);
|
|
18186
|
-
}
|
|
20757
|
+
})
|
|
18187
20758
|
);
|
|
18188
20759
|
server.registerTool(
|
|
18189
20760
|
"ingest_input",
|
|
@@ -18193,10 +20764,10 @@ async function createMcpServer(rootDir) {
|
|
|
18193
20764
|
input: z8.string().min(1).describe("Local path or URL to ingest")
|
|
18194
20765
|
}
|
|
18195
20766
|
},
|
|
18196
|
-
async ({ input }) => {
|
|
20767
|
+
safeHandler(async ({ input }) => {
|
|
18197
20768
|
const result = await ingestInputDetailed(rootDir, input);
|
|
18198
20769
|
return asToolText(result);
|
|
18199
|
-
}
|
|
20770
|
+
})
|
|
18200
20771
|
);
|
|
18201
20772
|
server.registerTool(
|
|
18202
20773
|
"compile_vault",
|
|
@@ -18206,20 +20777,20 @@ async function createMcpServer(rootDir) {
|
|
|
18206
20777
|
approve: z8.boolean().optional().describe("Stage a review bundle without applying active page changes")
|
|
18207
20778
|
}
|
|
18208
20779
|
},
|
|
18209
|
-
async ({ approve }) => {
|
|
20780
|
+
safeHandler(async ({ approve }) => {
|
|
18210
20781
|
const result = await compileVault(rootDir, { approve: approve ?? false });
|
|
18211
20782
|
return asToolText(result);
|
|
18212
|
-
}
|
|
20783
|
+
})
|
|
18213
20784
|
);
|
|
18214
20785
|
server.registerTool(
|
|
18215
20786
|
"lint_vault",
|
|
18216
20787
|
{
|
|
18217
20788
|
description: "Run anti-drift and vault health checks."
|
|
18218
20789
|
},
|
|
18219
|
-
async () => {
|
|
20790
|
+
safeHandler(async () => {
|
|
18220
20791
|
const findings = await lintVault(rootDir);
|
|
18221
20792
|
return asToolText(findings);
|
|
18222
|
-
}
|
|
20793
|
+
})
|
|
18223
20794
|
);
|
|
18224
20795
|
server.registerResource(
|
|
18225
20796
|
"swarmvault-config",
|
|
@@ -18390,6 +20961,17 @@ function asToolError(message) {
|
|
|
18390
20961
|
]
|
|
18391
20962
|
};
|
|
18392
20963
|
}
|
|
20964
|
+
function safeHandler(handler) {
|
|
20965
|
+
return async (args) => {
|
|
20966
|
+
try {
|
|
20967
|
+
return await handler(args);
|
|
20968
|
+
} catch (error) {
|
|
20969
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
20970
|
+
console.error(`[swarmvault-mcp] tool handler failed: ${message}`);
|
|
20971
|
+
return asToolError(message);
|
|
20972
|
+
}
|
|
20973
|
+
};
|
|
20974
|
+
}
|
|
18393
20975
|
function asTextResource(uri, text) {
|
|
18394
20976
|
return {
|
|
18395
20977
|
contents: [
|
|
@@ -18637,13 +21219,22 @@ async function serveSchedules(rootDir, pollMs = 3e4) {
|
|
|
18637
21219
|
}
|
|
18638
21220
|
running = true;
|
|
18639
21221
|
try {
|
|
18640
|
-
|
|
21222
|
+
let schedules = [];
|
|
21223
|
+
try {
|
|
21224
|
+
schedules = await listSchedules(rootDir);
|
|
21225
|
+
} catch (error) {
|
|
21226
|
+
console.error(`[swarmvault-schedule] failed to list schedules: ${error instanceof Error ? error.message : String(error)}`);
|
|
21227
|
+
}
|
|
18641
21228
|
const due = schedules.filter((item) => item.enabled).filter((item) => !item.nextRunAt || Date.parse(item.nextRunAt) <= Date.now()).sort((left, right) => (left.nextRunAt ?? "").localeCompare(right.nextRunAt ?? ""));
|
|
18642
21229
|
for (const schedule of due) {
|
|
18643
21230
|
if (closed) {
|
|
18644
21231
|
break;
|
|
18645
21232
|
}
|
|
18646
|
-
|
|
21233
|
+
try {
|
|
21234
|
+
await runSchedule(rootDir, schedule.jobId);
|
|
21235
|
+
} catch (error) {
|
|
21236
|
+
console.error(`[swarmvault-schedule] job ${schedule.jobId} crashed: ${error instanceof Error ? error.message : String(error)}`);
|
|
21237
|
+
}
|
|
18647
21238
|
}
|
|
18648
21239
|
} finally {
|
|
18649
21240
|
running = false;
|
|
@@ -20586,10 +23177,6 @@ var MAX_BACKOFF_MS = 3e4;
|
|
|
20586
23177
|
var BACKOFF_THRESHOLD = 3;
|
|
20587
23178
|
var CRITICAL_THRESHOLD = 10;
|
|
20588
23179
|
var REPO_WATCH_IGNORES = /* @__PURE__ */ new Set([".git", ".venv"]);
|
|
20589
|
-
function withinRoot3(rootPath, targetPath) {
|
|
20590
|
-
const relative = path27.relative(rootPath, targetPath);
|
|
20591
|
-
return relative === "" || !relative.startsWith("..") && !path27.isAbsolute(relative);
|
|
20592
|
-
}
|
|
20593
23180
|
function hasIgnoredRepoSegment(baseDir, targetPath) {
|
|
20594
23181
|
const relativePath = path27.relative(baseDir, targetPath);
|
|
20595
23182
|
if (!relativePath || relativePath.startsWith("..")) {
|
|
@@ -20759,11 +23346,11 @@ async function watchVault(rootDir, options = {}) {
|
|
|
20759
23346
|
interval: 100,
|
|
20760
23347
|
ignored: (targetPath) => {
|
|
20761
23348
|
const absolutePath = path27.resolve(targetPath);
|
|
20762
|
-
const primaryTarget = watchTargets.filter((watchTarget) =>
|
|
23349
|
+
const primaryTarget = watchTargets.filter((watchTarget) => isPathWithin(watchTarget, absolutePath)).sort((left, right) => right.length - left.length)[0] ?? null;
|
|
20763
23350
|
if (!primaryTarget) {
|
|
20764
23351
|
return false;
|
|
20765
23352
|
}
|
|
20766
|
-
if (primaryTarget !== inboxWatchRoot && ignoredRoots.some((ignoreRoot) =>
|
|
23353
|
+
if (primaryTarget !== inboxWatchRoot && ignoredRoots.some((ignoreRoot) => isPathWithin(ignoreRoot, absolutePath))) {
|
|
20767
23354
|
return true;
|
|
20768
23355
|
}
|
|
20769
23356
|
return hasIgnoredRepoSegment(primaryTarget, absolutePath);
|
|
@@ -20947,7 +23534,7 @@ async function watchVault(rootDir, options = {}) {
|
|
|
20947
23534
|
}
|
|
20948
23535
|
};
|
|
20949
23536
|
const reasonForPath = (targetPath) => {
|
|
20950
|
-
const baseDir = watchTargets.filter((watchTarget) =>
|
|
23537
|
+
const baseDir = watchTargets.filter((watchTarget) => isPathWithin(watchTarget, path27.resolve(targetPath))).sort((left, right) => right.length - left.length)[0] ?? paths.inboxDir;
|
|
20951
23538
|
return path27.relative(baseDir, targetPath) || ".";
|
|
20952
23539
|
};
|
|
20953
23540
|
watcher.on("add", (filePath) => schedule(`add:${reasonForPath(filePath)}`)).on("change", (filePath) => schedule(`change:${reasonForPath(filePath)}`)).on("unlink", (filePath) => schedule(`unlink:${reasonForPath(filePath)}`)).on("addDir", (dirPath) => schedule(`addDir:${reasonForPath(dirPath)}`)).on("unlinkDir", (dirPath) => schedule(`unlinkDir:${reasonForPath(dirPath)}`)).on("error", (caught) => schedule(`error:${caught instanceof Error ? caught.message : String(caught)}`));
|