@nudojs/lsp 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server.js +832 -135
- package/package.json +15 -5
- package/CHANGELOG.md +0 -41
- package/agent-skill/SKILL.md +0 -83
- package/src/__tests__/definition.test.ts +0 -32
- package/src/__tests__/lsp-integration.test.ts +0 -822
- package/src/agent-tools.ts +0 -325
- package/src/semantic-tokens.ts +0 -45
- package/src/server.ts +0 -672
- package/src/symbols.ts +0 -109
- package/src/validation.ts +0 -197
- package/tsconfig.json +0 -12
package/dist/server.js
CHANGED
|
@@ -73,7 +73,7 @@ var require_ms = __commonJS({
|
|
|
73
73
|
options = options || {};
|
|
74
74
|
var type = typeof val;
|
|
75
75
|
if (type === "string" && val.length > 0) {
|
|
76
|
-
return
|
|
76
|
+
return parse4(val);
|
|
77
77
|
} else if (type === "number" && isFinite(val)) {
|
|
78
78
|
return options.long ? fmtLong(val) : fmtShort(val);
|
|
79
79
|
}
|
|
@@ -81,7 +81,7 @@ var require_ms = __commonJS({
|
|
|
81
81
|
"val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
|
|
82
82
|
);
|
|
83
83
|
};
|
|
84
|
-
function
|
|
84
|
+
function parse4(str) {
|
|
85
85
|
str = String(str);
|
|
86
86
|
if (str.length > 100) {
|
|
87
87
|
return;
|
|
@@ -17328,7 +17328,7 @@ var require_resolve_uri_umd = __commonJS({
|
|
|
17328
17328
|
}
|
|
17329
17329
|
url.path = path;
|
|
17330
17330
|
}
|
|
17331
|
-
function
|
|
17331
|
+
function resolve3(input, base) {
|
|
17332
17332
|
if (!input && !base)
|
|
17333
17333
|
return "";
|
|
17334
17334
|
const url = parseUrl(input);
|
|
@@ -17381,7 +17381,7 @@ var require_resolve_uri_umd = __commonJS({
|
|
|
17381
17381
|
return url.scheme + "//" + url.user + url.host + url.port + url.path + queryHash;
|
|
17382
17382
|
}
|
|
17383
17383
|
}
|
|
17384
|
-
return
|
|
17384
|
+
return resolve3;
|
|
17385
17385
|
}));
|
|
17386
17386
|
}
|
|
17387
17387
|
});
|
|
@@ -17600,11 +17600,11 @@ var require_trace_mapping_umd = __commonJS({
|
|
|
17600
17600
|
state.lastNeedle = needle;
|
|
17601
17601
|
return state.lastIndex = binarySearch(haystack, needle, low, high);
|
|
17602
17602
|
}
|
|
17603
|
-
function
|
|
17603
|
+
function parse4(map) {
|
|
17604
17604
|
return typeof map === "string" ? JSON.parse(map) : map;
|
|
17605
17605
|
}
|
|
17606
17606
|
var FlattenMap = function(map, mapUrl) {
|
|
17607
|
-
const parsed =
|
|
17607
|
+
const parsed = parse4(map);
|
|
17608
17608
|
if (!("sections" in parsed)) {
|
|
17609
17609
|
return new TraceMap(parsed, mapUrl);
|
|
17610
17610
|
}
|
|
@@ -17668,7 +17668,7 @@ var require_trace_mapping_umd = __commonJS({
|
|
|
17668
17668
|
}
|
|
17669
17669
|
}
|
|
17670
17670
|
function addSection(input, mapUrl, mappings, sources, sourcesContent, names, ignoreList, lineOffset, columnOffset, stopLine, stopColumn) {
|
|
17671
|
-
const parsed =
|
|
17671
|
+
const parsed = parse4(input);
|
|
17672
17672
|
if ("sections" in parsed) return recurse(...arguments);
|
|
17673
17673
|
const map = new TraceMap(parsed, mapUrl);
|
|
17674
17674
|
const sourcesOffset = sources.length;
|
|
@@ -17718,7 +17718,7 @@ var require_trace_mapping_umd = __commonJS({
|
|
|
17718
17718
|
constructor(map, mapUrl) {
|
|
17719
17719
|
const isString = typeof map === "string";
|
|
17720
17720
|
if (!isString && map._decodedMemo) return map;
|
|
17721
|
-
const parsed =
|
|
17721
|
+
const parsed = parse4(map);
|
|
17722
17722
|
const { version, file, names, sourceRoot, sources, sourcesContent } = parsed;
|
|
17723
17723
|
this.version = version;
|
|
17724
17724
|
this.file = file;
|
|
@@ -17727,8 +17727,8 @@ var require_trace_mapping_umd = __commonJS({
|
|
|
17727
17727
|
this.sources = sources;
|
|
17728
17728
|
this.sourcesContent = sourcesContent;
|
|
17729
17729
|
this.ignoreList = parsed.ignoreList || parsed.x_google_ignoreList || void 0;
|
|
17730
|
-
const
|
|
17731
|
-
this.resolvedSources = sources.map(
|
|
17730
|
+
const resolve3 = resolver(mapUrl, sourceRoot);
|
|
17731
|
+
this.resolvedSources = sources.map(resolve3);
|
|
17732
17732
|
const { mappings } = parsed;
|
|
17733
17733
|
if (typeof mappings === "string") {
|
|
17734
17734
|
this._encoded = mappings;
|
|
@@ -28350,14 +28350,14 @@ var require_lib6 = __commonJS({
|
|
|
28350
28350
|
super.checkParams(node, false, true);
|
|
28351
28351
|
this.scope.exit();
|
|
28352
28352
|
}
|
|
28353
|
-
forwardNoArrowParamsConversionAt(node,
|
|
28353
|
+
forwardNoArrowParamsConversionAt(node, parse5) {
|
|
28354
28354
|
let result;
|
|
28355
28355
|
if (this.state.noArrowParamsConversionAt.includes(this.offsetToSourcePos(node.start))) {
|
|
28356
28356
|
this.state.noArrowParamsConversionAt.push(this.state.start);
|
|
28357
|
-
result =
|
|
28357
|
+
result = parse5();
|
|
28358
28358
|
this.state.noArrowParamsConversionAt.pop();
|
|
28359
28359
|
} else {
|
|
28360
|
-
result =
|
|
28360
|
+
result = parse5();
|
|
28361
28361
|
}
|
|
28362
28362
|
return result;
|
|
28363
28363
|
}
|
|
@@ -39752,7 +39752,7 @@ var require_lib6 = __commonJS({
|
|
|
39752
39752
|
return result;
|
|
39753
39753
|
}
|
|
39754
39754
|
};
|
|
39755
|
-
function
|
|
39755
|
+
function parse4(input, options) {
|
|
39756
39756
|
var _options;
|
|
39757
39757
|
if (((_options = options) == null ? void 0 : _options.sourceType) === "unambiguous") {
|
|
39758
39758
|
options = Object.assign({}, options);
|
|
@@ -39839,7 +39839,7 @@ var require_lib6 = __commonJS({
|
|
|
39839
39839
|
}
|
|
39840
39840
|
return cls;
|
|
39841
39841
|
}
|
|
39842
|
-
exports.parse =
|
|
39842
|
+
exports.parse = parse4;
|
|
39843
39843
|
exports.parseExpression = parseExpression;
|
|
39844
39844
|
exports.tokTypes = tokTypes;
|
|
39845
39845
|
}
|
|
@@ -41773,7 +41773,7 @@ var require_introspection = __commonJS({
|
|
|
41773
41773
|
exports.isStatic = isStatic;
|
|
41774
41774
|
exports.matchesPattern = matchesPattern;
|
|
41775
41775
|
exports.referencesImport = referencesImport;
|
|
41776
|
-
exports.resolve =
|
|
41776
|
+
exports.resolve = resolve3;
|
|
41777
41777
|
exports.willIMaybeExecuteBefore = willIMaybeExecuteBefore;
|
|
41778
41778
|
var _t = require_lib3();
|
|
41779
41779
|
var {
|
|
@@ -42031,7 +42031,7 @@ var require_introspection = __commonJS({
|
|
|
42031
42031
|
nodeMap.set(target.node, result);
|
|
42032
42032
|
return result;
|
|
42033
42033
|
}
|
|
42034
|
-
function
|
|
42034
|
+
function resolve3(dangerous, resolved) {
|
|
42035
42035
|
return _resolve.call(this, dangerous, resolved) || this;
|
|
42036
42036
|
}
|
|
42037
42037
|
function _resolve(dangerous, resolved) {
|
|
@@ -43396,29 +43396,37 @@ import {
|
|
|
43396
43396
|
InlayHintKind
|
|
43397
43397
|
} from "vscode-languageserver/node";
|
|
43398
43398
|
import { TextDocument } from "vscode-languageserver-textdocument";
|
|
43399
|
-
import {
|
|
43399
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
43400
43400
|
import {
|
|
43401
43401
|
getTypeAtPosition,
|
|
43402
|
+
getHoverAtPosition as getHoverAtPosition2,
|
|
43402
43403
|
getCompletionsAtPosition,
|
|
43403
|
-
getCasesForFile
|
|
43404
|
+
getCasesForFile,
|
|
43405
|
+
buildSemanticTokens,
|
|
43406
|
+
isNudoTargetPath,
|
|
43407
|
+
collectAbsInlays as collectAbsInlays2
|
|
43404
43408
|
} from "@nudojs/service";
|
|
43405
|
-
import { parse as
|
|
43409
|
+
import { parse as parse3 } from "@nudojs/parser";
|
|
43406
43410
|
|
|
43407
43411
|
// src/symbols.ts
|
|
43408
43412
|
var import_traverse = __toESM(require_lib8(), 1);
|
|
43413
|
+
import { parse } from "@nudojs/parser";
|
|
43414
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "fs";
|
|
43415
|
+
import { dirname, join, resolve } from "path";
|
|
43409
43416
|
function locFromNode(node) {
|
|
43410
43417
|
return {
|
|
43411
43418
|
start: { line: node.loc?.start.line ?? 1, column: node.loc?.start.column ?? 0 },
|
|
43412
43419
|
end: { line: node.loc?.end.line ?? 1, column: node.loc?.end.column ?? 0 }
|
|
43413
43420
|
};
|
|
43414
43421
|
}
|
|
43422
|
+
function traverseFn() {
|
|
43423
|
+
return typeof import_traverse.default === "function" ? import_traverse.default : import_traverse.default.default;
|
|
43424
|
+
}
|
|
43415
43425
|
function buildSymbolTable(ast, uri) {
|
|
43416
43426
|
const definitions = /* @__PURE__ */ new Map();
|
|
43417
43427
|
const references = [];
|
|
43418
|
-
const traverseFn = typeof import_traverse.default === "function" ? import_traverse.default : import_traverse.default.default;
|
|
43419
43428
|
try {
|
|
43420
|
-
traverseFn(ast, {
|
|
43421
|
-
// Collect definitions
|
|
43429
|
+
traverseFn()(ast, {
|
|
43422
43430
|
FunctionDeclaration(path) {
|
|
43423
43431
|
if (path.node.id) {
|
|
43424
43432
|
definitions.set(path.node.id.name, {
|
|
@@ -43449,7 +43457,6 @@ function buildSymbolTable(ast, uri) {
|
|
|
43449
43457
|
});
|
|
43450
43458
|
}
|
|
43451
43459
|
},
|
|
43452
|
-
// Collect references
|
|
43453
43460
|
Identifier(path) {
|
|
43454
43461
|
if (path.parentPath?.node.type === "FunctionDeclaration" && path.parentPath.node.id === path.node) return;
|
|
43455
43462
|
if (path.parentPath?.node.type === "VariableDeclarator" && path.parentPath.node.id === path.node) return;
|
|
@@ -43473,9 +43480,8 @@ function findReferences(symbolTable, name) {
|
|
|
43473
43480
|
}
|
|
43474
43481
|
function findIdentifierAtPosition(ast, line, column) {
|
|
43475
43482
|
let found = null;
|
|
43476
|
-
const traverseFn = typeof import_traverse.default === "function" ? import_traverse.default : import_traverse.default.default;
|
|
43477
43483
|
try {
|
|
43478
|
-
traverseFn(ast, {
|
|
43484
|
+
traverseFn()(ast, {
|
|
43479
43485
|
Identifier(path) {
|
|
43480
43486
|
const loc = path.node.loc;
|
|
43481
43487
|
if (!loc) return;
|
|
@@ -43489,34 +43495,378 @@ function findIdentifierAtPosition(ast, line, column) {
|
|
|
43489
43495
|
}
|
|
43490
43496
|
return found;
|
|
43491
43497
|
}
|
|
43498
|
+
var SymbolKind = {
|
|
43499
|
+
Function: 12,
|
|
43500
|
+
Variable: 13,
|
|
43501
|
+
Class: 5,
|
|
43502
|
+
Method: 6,
|
|
43503
|
+
Property: 7,
|
|
43504
|
+
Constant: 14
|
|
43505
|
+
};
|
|
43506
|
+
function rangeOfLoc(loc) {
|
|
43507
|
+
return {
|
|
43508
|
+
start: { line: loc.start.line - 1, character: loc.start.column },
|
|
43509
|
+
end: { line: loc.end.line - 1, character: loc.end.column }
|
|
43510
|
+
};
|
|
43511
|
+
}
|
|
43512
|
+
function rangeOfNode(node) {
|
|
43513
|
+
return rangeOfLoc(locFromNode(node));
|
|
43514
|
+
}
|
|
43515
|
+
function documentSymbols(ast) {
|
|
43516
|
+
const out = [];
|
|
43517
|
+
const program = ast.program ?? ast;
|
|
43518
|
+
const body = program.body ?? [];
|
|
43519
|
+
const pushFn = (fnNode, idNode, exported) => {
|
|
43520
|
+
if (!idNode?.name) return;
|
|
43521
|
+
const range = rangeOfNode(fnNode);
|
|
43522
|
+
const selection = rangeOfNode(idNode);
|
|
43523
|
+
const children = [];
|
|
43524
|
+
const params = (fnNode.params ?? []).map((p) => p?.name ?? (p?.type === "RestElement" ? `...${p.argument?.name}` : "_")).filter(Boolean);
|
|
43525
|
+
out.push({
|
|
43526
|
+
name: idNode.name,
|
|
43527
|
+
detail: `(${params.join(", ")})${exported ? " export" : ""}`,
|
|
43528
|
+
kind: SymbolKind.Function,
|
|
43529
|
+
range,
|
|
43530
|
+
selectionRange: selection,
|
|
43531
|
+
children: children.length ? children : void 0
|
|
43532
|
+
});
|
|
43533
|
+
};
|
|
43534
|
+
for (const stmt of body) {
|
|
43535
|
+
let decl = stmt;
|
|
43536
|
+
let exported = false;
|
|
43537
|
+
if (stmt.type === "ExportNamedDeclaration" && stmt.declaration) {
|
|
43538
|
+
decl = stmt.declaration;
|
|
43539
|
+
exported = true;
|
|
43540
|
+
} else if (stmt.type === "ExportDefaultDeclaration") {
|
|
43541
|
+
decl = stmt.declaration;
|
|
43542
|
+
exported = true;
|
|
43543
|
+
}
|
|
43544
|
+
if (decl?.type === "FunctionDeclaration") {
|
|
43545
|
+
pushFn(decl, decl.id, exported);
|
|
43546
|
+
continue;
|
|
43547
|
+
}
|
|
43548
|
+
if (decl?.type === "ClassDeclaration" && decl.id) {
|
|
43549
|
+
out.push({
|
|
43550
|
+
name: decl.id.name,
|
|
43551
|
+
detail: exported ? "export class" : "class",
|
|
43552
|
+
kind: SymbolKind.Class,
|
|
43553
|
+
range: rangeOfNode(decl),
|
|
43554
|
+
selectionRange: rangeOfNode(decl.id),
|
|
43555
|
+
children: (decl.body?.body ?? []).flatMap((m) => {
|
|
43556
|
+
const key = m.key?.name ?? m.key?.value;
|
|
43557
|
+
if (!key || m.type !== "ClassMethod" && m.type !== "ClassProperty") return [];
|
|
43558
|
+
return [{
|
|
43559
|
+
name: String(key),
|
|
43560
|
+
kind: m.type === "ClassMethod" ? SymbolKind.Method : SymbolKind.Property,
|
|
43561
|
+
range: rangeOfNode(m),
|
|
43562
|
+
selectionRange: rangeOfNode(m.key)
|
|
43563
|
+
}];
|
|
43564
|
+
})
|
|
43565
|
+
});
|
|
43566
|
+
continue;
|
|
43567
|
+
}
|
|
43568
|
+
if (decl?.type === "VariableDeclaration") {
|
|
43569
|
+
for (const d of decl.declarations ?? []) {
|
|
43570
|
+
if (d.id?.type !== "Identifier") continue;
|
|
43571
|
+
const init = d.init;
|
|
43572
|
+
const isFn = init && (init.type === "ArrowFunctionExpression" || init.type === "FunctionExpression");
|
|
43573
|
+
out.push({
|
|
43574
|
+
name: d.id.name,
|
|
43575
|
+
detail: exported ? "export const" : "const",
|
|
43576
|
+
kind: isFn ? SymbolKind.Function : SymbolKind.Variable,
|
|
43577
|
+
range: rangeOfNode(d),
|
|
43578
|
+
selectionRange: rangeOfNode(d.id)
|
|
43579
|
+
});
|
|
43580
|
+
}
|
|
43581
|
+
}
|
|
43582
|
+
}
|
|
43583
|
+
return out;
|
|
43584
|
+
}
|
|
43585
|
+
function collectImportBindings(ast, fromFile) {
|
|
43586
|
+
const map = /* @__PURE__ */ new Map();
|
|
43587
|
+
const program = ast.program ?? ast;
|
|
43588
|
+
for (const stmt of program.body ?? []) {
|
|
43589
|
+
if (stmt.type !== "ImportDeclaration") continue;
|
|
43590
|
+
const spec = stmt.source.value;
|
|
43591
|
+
const resolvedPath = resolveRelativeModule(spec, fromFile);
|
|
43592
|
+
for (const specNode of stmt.specifiers ?? []) {
|
|
43593
|
+
if (specNode.type === "ImportSpecifier") {
|
|
43594
|
+
const imported = specNode.imported.type === "Identifier" ? specNode.imported.name : String(specNode.imported.value);
|
|
43595
|
+
map.set(specNode.local.name, { spec, importedName: imported, resolvedPath });
|
|
43596
|
+
} else if (specNode.type === "ImportDefaultSpecifier") {
|
|
43597
|
+
map.set(specNode.local.name, { spec, importedName: "default", resolvedPath });
|
|
43598
|
+
} else if (specNode.type === "ImportNamespaceSpecifier") {
|
|
43599
|
+
map.set(specNode.local.name, { spec, importedName: "*", resolvedPath });
|
|
43600
|
+
}
|
|
43601
|
+
}
|
|
43602
|
+
}
|
|
43603
|
+
return map;
|
|
43604
|
+
}
|
|
43605
|
+
function resolveRelativeModule(spec, fromFile) {
|
|
43606
|
+
if (!spec.startsWith(".") && !spec.startsWith("/")) return void 0;
|
|
43607
|
+
const base = resolve(dirname(fromFile), spec);
|
|
43608
|
+
for (const cand of [
|
|
43609
|
+
base,
|
|
43610
|
+
`${base}.js`,
|
|
43611
|
+
`${base}.cjs`,
|
|
43612
|
+
`${base}.mjs`,
|
|
43613
|
+
`${base}.ts`,
|
|
43614
|
+
`${base}.mts`,
|
|
43615
|
+
`${base}.cts`,
|
|
43616
|
+
join(base, "index.js"),
|
|
43617
|
+
join(base, "index.mjs"),
|
|
43618
|
+
join(base, "index.ts")
|
|
43619
|
+
]) {
|
|
43620
|
+
try {
|
|
43621
|
+
if (existsSync(cand) && statSync(cand).isFile()) return cand;
|
|
43622
|
+
} catch {
|
|
43623
|
+
}
|
|
43624
|
+
}
|
|
43625
|
+
return void 0;
|
|
43626
|
+
}
|
|
43627
|
+
function readSourceIfExists(filePath) {
|
|
43628
|
+
try {
|
|
43629
|
+
return readFileSync(filePath, "utf-8");
|
|
43630
|
+
} catch {
|
|
43631
|
+
return void 0;
|
|
43632
|
+
}
|
|
43633
|
+
}
|
|
43634
|
+
function findExportDefinition(targetSource, exportName) {
|
|
43635
|
+
let ast;
|
|
43636
|
+
try {
|
|
43637
|
+
ast = parse(targetSource);
|
|
43638
|
+
} catch {
|
|
43639
|
+
return null;
|
|
43640
|
+
}
|
|
43641
|
+
const program = ast.program ?? ast;
|
|
43642
|
+
for (const stmt of program.body ?? []) {
|
|
43643
|
+
let decl = stmt;
|
|
43644
|
+
if (stmt.type === "ExportNamedDeclaration" && stmt.declaration) {
|
|
43645
|
+
decl = stmt.declaration;
|
|
43646
|
+
} else if (stmt.type === "ExportDefaultDeclaration") {
|
|
43647
|
+
decl = stmt.declaration;
|
|
43648
|
+
if (exportName === "default") {
|
|
43649
|
+
if (decl?.type === "FunctionDeclaration" && decl.id) {
|
|
43650
|
+
return { name: decl.id.name, kind: "function", loc: locFromNode(decl.id) };
|
|
43651
|
+
}
|
|
43652
|
+
if (decl?.type === "ClassDeclaration" && decl.id) {
|
|
43653
|
+
return { name: decl.id.name, kind: "class", loc: locFromNode(decl.id) };
|
|
43654
|
+
}
|
|
43655
|
+
if (decl?.type === "Identifier") {
|
|
43656
|
+
return { name: decl.name, kind: "variable", loc: locFromNode(decl) };
|
|
43657
|
+
}
|
|
43658
|
+
return null;
|
|
43659
|
+
}
|
|
43660
|
+
continue;
|
|
43661
|
+
}
|
|
43662
|
+
if (decl?.type === "FunctionDeclaration" && decl.id?.name === exportName) {
|
|
43663
|
+
return { name: decl.id.name, kind: "function", loc: locFromNode(decl.id) };
|
|
43664
|
+
}
|
|
43665
|
+
if (decl?.type === "ClassDeclaration" && decl.id?.name === exportName) {
|
|
43666
|
+
return { name: decl.id.name, kind: "class", loc: locFromNode(decl.id) };
|
|
43667
|
+
}
|
|
43668
|
+
if (decl?.type === "VariableDeclaration") {
|
|
43669
|
+
for (const d of decl.declarations ?? []) {
|
|
43670
|
+
if (d.id?.type === "Identifier" && d.id.name === exportName) {
|
|
43671
|
+
return { name: d.id.name, kind: "variable", loc: locFromNode(d.id) };
|
|
43672
|
+
}
|
|
43673
|
+
}
|
|
43674
|
+
}
|
|
43675
|
+
if (stmt.type === "ExportNamedDeclaration" && !stmt.declaration && stmt.specifiers) {
|
|
43676
|
+
for (const s of stmt.specifiers) {
|
|
43677
|
+
if (s.type !== "ExportSpecifier") continue;
|
|
43678
|
+
const exported = s.exported.type === "Identifier" ? s.exported.name : String(s.exported.value);
|
|
43679
|
+
if (exported !== exportName) continue;
|
|
43680
|
+
const local = s.local.type === "Identifier" ? s.local.name : String(s.local.value);
|
|
43681
|
+
const table = buildSymbolTable(ast, "");
|
|
43682
|
+
const def = table.definitions.get(local);
|
|
43683
|
+
if (def) return { name: local, kind: def.kind, loc: def.loc };
|
|
43684
|
+
}
|
|
43685
|
+
}
|
|
43686
|
+
}
|
|
43687
|
+
return null;
|
|
43688
|
+
}
|
|
43689
|
+
function findCrossFileDefinition(fromFile, source, ident) {
|
|
43690
|
+
let ast;
|
|
43691
|
+
try {
|
|
43692
|
+
ast = parse(source);
|
|
43693
|
+
} catch {
|
|
43694
|
+
return null;
|
|
43695
|
+
}
|
|
43696
|
+
const bindings = collectImportBindings(ast, fromFile);
|
|
43697
|
+
const binding = bindings.get(ident);
|
|
43698
|
+
if (!binding?.resolvedPath) return null;
|
|
43699
|
+
if (binding.importedName === "*") return null;
|
|
43700
|
+
const targetSource = readSourceIfExists(binding.resolvedPath);
|
|
43701
|
+
if (targetSource === void 0) return null;
|
|
43702
|
+
const def = findExportDefinition(targetSource, binding.importedName);
|
|
43703
|
+
if (!def) return null;
|
|
43704
|
+
return { filePath: binding.resolvedPath, loc: def.loc, name: def.name };
|
|
43705
|
+
}
|
|
43706
|
+
function findCrossFileReferences(definingFile, exportName, options = {}) {
|
|
43707
|
+
const out = [];
|
|
43708
|
+
const root = options.rootDir ?? dirname(definingFile);
|
|
43709
|
+
const maxFiles = options.maxFiles ?? 200;
|
|
43710
|
+
const candidates = new Set(options.extraFiles ?? []);
|
|
43711
|
+
try {
|
|
43712
|
+
collectJsFiles(root, candidates, maxFiles, 0);
|
|
43713
|
+
} catch {
|
|
43714
|
+
}
|
|
43715
|
+
const definingNorm = resolve(definingFile);
|
|
43716
|
+
for (const cand of candidates) {
|
|
43717
|
+
if (resolve(cand) === definingNorm) continue;
|
|
43718
|
+
const src = readSourceIfExists(cand);
|
|
43719
|
+
if (src === void 0) continue;
|
|
43720
|
+
let ast;
|
|
43721
|
+
try {
|
|
43722
|
+
ast = parse(src);
|
|
43723
|
+
} catch {
|
|
43724
|
+
continue;
|
|
43725
|
+
}
|
|
43726
|
+
const bindings = collectImportBindings(ast, cand);
|
|
43727
|
+
for (const [local, b] of bindings) {
|
|
43728
|
+
if (!b.resolvedPath || resolve(b.resolvedPath) !== definingNorm) continue;
|
|
43729
|
+
if (b.importedName !== exportName && b.importedName !== "*") continue;
|
|
43730
|
+
const table = buildSymbolTable(ast, cand);
|
|
43731
|
+
for (const ref of table.references) {
|
|
43732
|
+
if (ref.name !== local) continue;
|
|
43733
|
+
out.push({ name: local, loc: ref.loc, uri: cand });
|
|
43734
|
+
}
|
|
43735
|
+
}
|
|
43736
|
+
}
|
|
43737
|
+
return out;
|
|
43738
|
+
}
|
|
43739
|
+
function collectJsFiles(dir, out, max, depth) {
|
|
43740
|
+
if (out.size >= max || depth > 6) return;
|
|
43741
|
+
let entries;
|
|
43742
|
+
try {
|
|
43743
|
+
entries = readdirSync(dir);
|
|
43744
|
+
} catch {
|
|
43745
|
+
return;
|
|
43746
|
+
}
|
|
43747
|
+
for (const name of entries) {
|
|
43748
|
+
if (name === "node_modules" || name === ".git" || name === "dist") continue;
|
|
43749
|
+
const full = join(dir, name);
|
|
43750
|
+
try {
|
|
43751
|
+
const st = statSync(full);
|
|
43752
|
+
if (st.isDirectory()) {
|
|
43753
|
+
collectJsFiles(full, out, max, depth + 1);
|
|
43754
|
+
} else if (/\.(js|mjs|cjs|ts|mts)$/.test(name) && !/\.d\.ts$/.test(name)) {
|
|
43755
|
+
out.add(full);
|
|
43756
|
+
}
|
|
43757
|
+
} catch {
|
|
43758
|
+
}
|
|
43759
|
+
}
|
|
43760
|
+
}
|
|
43761
|
+
function resolveDefinition(fromFile, source, ident) {
|
|
43762
|
+
const ast = parse(source);
|
|
43763
|
+
const table = buildSymbolTable(ast, fromFile);
|
|
43764
|
+
const local = findDefinition(table, ident);
|
|
43765
|
+
if (local) return { filePath: fromFile, loc: local.loc, name: local.name };
|
|
43766
|
+
return findCrossFileDefinition(fromFile, source, ident);
|
|
43767
|
+
}
|
|
43768
|
+
function resolveReferences(fromFile, source, ident, options = {}) {
|
|
43769
|
+
const includeDecl = options.includeDeclaration !== false;
|
|
43770
|
+
const ast = parse(source);
|
|
43771
|
+
const table = buildSymbolTable(ast, fromFile);
|
|
43772
|
+
const localRefs = findReferences(table, ident);
|
|
43773
|
+
const localDef = findDefinition(table, ident);
|
|
43774
|
+
if (localDef) {
|
|
43775
|
+
const exportName = localDef.name;
|
|
43776
|
+
const isExported = isExportedName(ast, exportName);
|
|
43777
|
+
const cross2 = isExported ? findCrossFileReferences(fromFile, exportName, { extraFiles: options.extraFiles }) : [];
|
|
43778
|
+
const decl = includeDecl ? [{ name: localDef.name, loc: localDef.loc, uri: fromFile }] : [];
|
|
43779
|
+
return [...decl, ...localRefs, ...cross2];
|
|
43780
|
+
}
|
|
43781
|
+
const crossDef = findCrossFileDefinition(fromFile, source, ident);
|
|
43782
|
+
if (!crossDef) return localRefs;
|
|
43783
|
+
const defSource = readSourceIfExists(crossDef.filePath) ?? "";
|
|
43784
|
+
let defAst = null;
|
|
43785
|
+
try {
|
|
43786
|
+
defAst = parse(defSource);
|
|
43787
|
+
} catch {
|
|
43788
|
+
defAst = null;
|
|
43789
|
+
}
|
|
43790
|
+
const defLocalRefs = [];
|
|
43791
|
+
let defDecl = [];
|
|
43792
|
+
if (defAst) {
|
|
43793
|
+
const defTable = buildSymbolTable(defAst, crossDef.filePath);
|
|
43794
|
+
defLocalRefs.push(...findReferences(defTable, crossDef.name));
|
|
43795
|
+
const d = findDefinition(defTable, crossDef.name);
|
|
43796
|
+
if (d && includeDecl) {
|
|
43797
|
+
defDecl = [{ name: d.name, loc: d.loc, uri: crossDef.filePath }];
|
|
43798
|
+
}
|
|
43799
|
+
}
|
|
43800
|
+
const cross = findCrossFileReferences(crossDef.filePath, crossDef.name, {
|
|
43801
|
+
extraFiles: [...options.extraFiles ?? [], fromFile]
|
|
43802
|
+
});
|
|
43803
|
+
const seen = /* @__PURE__ */ new Set();
|
|
43804
|
+
const all = [];
|
|
43805
|
+
for (const r of [...defDecl, ...defLocalRefs, ...localRefs, ...cross]) {
|
|
43806
|
+
const key = `${r.uri ?? ""}:${r.loc.start.line}:${r.loc.start.column}`;
|
|
43807
|
+
if (seen.has(key)) continue;
|
|
43808
|
+
seen.add(key);
|
|
43809
|
+
all.push(r);
|
|
43810
|
+
}
|
|
43811
|
+
return all;
|
|
43812
|
+
}
|
|
43813
|
+
function isExportedName(ast, name) {
|
|
43814
|
+
const program = ast.program ?? ast;
|
|
43815
|
+
for (const stmt of program.body ?? []) {
|
|
43816
|
+
if (stmt.type === "ExportNamedDeclaration") {
|
|
43817
|
+
if (stmt.declaration) {
|
|
43818
|
+
const d = stmt.declaration;
|
|
43819
|
+
if (d.type === "FunctionDeclaration" && d.id?.name === name) return true;
|
|
43820
|
+
if (d.type === "ClassDeclaration" && d.id?.name === name) return true;
|
|
43821
|
+
if (d.type === "VariableDeclaration") {
|
|
43822
|
+
for (const dec of d.declarations ?? []) {
|
|
43823
|
+
if (dec.id?.type === "Identifier" && dec.id.name === name) return true;
|
|
43824
|
+
}
|
|
43825
|
+
}
|
|
43826
|
+
}
|
|
43827
|
+
for (const s of stmt.specifiers ?? []) {
|
|
43828
|
+
if (s.type !== "ExportSpecifier") continue;
|
|
43829
|
+
const exported = s.exported.type === "Identifier" ? s.exported.name : String(s.exported.value);
|
|
43830
|
+
if (exported === name) return true;
|
|
43831
|
+
}
|
|
43832
|
+
}
|
|
43833
|
+
if (stmt.type === "ExportDefaultDeclaration") {
|
|
43834
|
+
const d = stmt.declaration;
|
|
43835
|
+
if (d?.id?.name === name) return true;
|
|
43836
|
+
if (d?.type === "Identifier" && d.name === name) return true;
|
|
43837
|
+
}
|
|
43838
|
+
}
|
|
43839
|
+
return false;
|
|
43840
|
+
}
|
|
43492
43841
|
|
|
43493
43842
|
// src/semantic-tokens.ts
|
|
43494
|
-
|
|
43495
|
-
|
|
43496
|
-
|
|
43497
|
-
|
|
43498
|
-
|
|
43499
|
-
"type",
|
|
43500
|
-
"keyword",
|
|
43501
|
-
"string",
|
|
43502
|
-
"number",
|
|
43503
|
-
"comment",
|
|
43504
|
-
"decorator"
|
|
43505
|
-
];
|
|
43506
|
-
var TOKEN_MODIFIERS = [
|
|
43507
|
-
"declaration",
|
|
43508
|
-
"readonly",
|
|
43509
|
-
"deprecated",
|
|
43510
|
-
"unreachable"
|
|
43511
|
-
];
|
|
43843
|
+
import {
|
|
43844
|
+
SEMANTIC_TOKEN_TYPES,
|
|
43845
|
+
SEMANTIC_TOKEN_MODIFIERS,
|
|
43846
|
+
encodeSemanticTokens
|
|
43847
|
+
} from "@nudojs/service";
|
|
43512
43848
|
|
|
43513
43849
|
// src/validation.ts
|
|
43850
|
+
import { dirname as dirname2, resolve as resolvePath } from "path";
|
|
43514
43851
|
import {
|
|
43515
43852
|
analyzeFile,
|
|
43516
43853
|
analyzeFileAsync,
|
|
43517
43854
|
buildModuleGraph,
|
|
43518
|
-
computeDirtySet
|
|
43855
|
+
computeDirtySet,
|
|
43856
|
+
defaultLoadModule,
|
|
43857
|
+
clearAnalysisSessionCaches,
|
|
43858
|
+
evictAbsModuleCacheFiles,
|
|
43859
|
+
evictBPathCacheForFiles,
|
|
43860
|
+
evictAnalysisFileCacheForFiles,
|
|
43861
|
+
evictFnAnalysisCacheForFiles
|
|
43519
43862
|
} from "@nudojs/service";
|
|
43863
|
+
import {
|
|
43864
|
+
checkSource,
|
|
43865
|
+
pTrue,
|
|
43866
|
+
evictGeneralizeMemoForPaths,
|
|
43867
|
+
evictCheckSourceMemoForPaths,
|
|
43868
|
+
extractNudoImports
|
|
43869
|
+
} from "@nudojs/core";
|
|
43520
43870
|
import {
|
|
43521
43871
|
DiagnosticSeverity,
|
|
43522
43872
|
DiagnosticTag
|
|
@@ -43524,15 +43874,65 @@ import {
|
|
|
43524
43874
|
var analysisCache = /* @__PURE__ */ new Map();
|
|
43525
43875
|
var knownFiles = /* @__PURE__ */ new Set();
|
|
43526
43876
|
var moduleGraphCache = /* @__PURE__ */ new Map();
|
|
43877
|
+
var nudoDepParents = /* @__PURE__ */ new Map();
|
|
43878
|
+
function normPath(p) {
|
|
43879
|
+
return p.replace(/\\/g, "/");
|
|
43880
|
+
}
|
|
43881
|
+
function registerNudoImportDeps(filePath, source) {
|
|
43882
|
+
const parent = normPath(resolvePath(filePath));
|
|
43883
|
+
for (const set of nudoDepParents.values()) {
|
|
43884
|
+
set.delete(parent);
|
|
43885
|
+
}
|
|
43886
|
+
const imports = extractNudoImports(source);
|
|
43887
|
+
for (const imp of imports) {
|
|
43888
|
+
if (!imp.spec.startsWith(".") && !imp.spec.startsWith("/")) continue;
|
|
43889
|
+
const dep = normPath(resolvePath(dirname2(filePath), imp.spec));
|
|
43890
|
+
let set = nudoDepParents.get(dep);
|
|
43891
|
+
if (!set) {
|
|
43892
|
+
set = /* @__PURE__ */ new Set();
|
|
43893
|
+
nudoDepParents.set(dep, set);
|
|
43894
|
+
}
|
|
43895
|
+
set.add(parent);
|
|
43896
|
+
}
|
|
43897
|
+
}
|
|
43898
|
+
async function handleNudoDepFileChanged(nudoPath, deps) {
|
|
43899
|
+
const p = normPath(resolvePath(nudoPath));
|
|
43900
|
+
evictGeneralizeMemoForPaths([p]);
|
|
43901
|
+
evictCheckSourceMemoForPaths([p]);
|
|
43902
|
+
const parents = nudoDepParents.get(p);
|
|
43903
|
+
if (!parents || parents.size === 0) return;
|
|
43904
|
+
const parentList = [...parents];
|
|
43905
|
+
evictBPathCacheForFiles(parentList);
|
|
43906
|
+
evictAnalysisFileCacheForFiles(parentList);
|
|
43907
|
+
evictFnAnalysisCacheForFiles(parentList);
|
|
43908
|
+
for (const parent of parentList) {
|
|
43909
|
+
const doc = deps.getOpenDocumentByPath?.(parent);
|
|
43910
|
+
if (!doc) continue;
|
|
43911
|
+
await validateText(
|
|
43912
|
+
parent,
|
|
43913
|
+
doc.uri,
|
|
43914
|
+
doc.getText(),
|
|
43915
|
+
doc.version,
|
|
43916
|
+
deps,
|
|
43917
|
+
false
|
|
43918
|
+
);
|
|
43919
|
+
}
|
|
43920
|
+
}
|
|
43527
43921
|
function forgetValidatedFile(filePath) {
|
|
43922
|
+
const parent = normPath(resolvePath(filePath));
|
|
43528
43923
|
knownFiles.delete(filePath);
|
|
43529
43924
|
analysisCache.delete(filePath);
|
|
43925
|
+
for (const set of nudoDepParents.values()) {
|
|
43926
|
+
set.delete(parent);
|
|
43927
|
+
}
|
|
43530
43928
|
}
|
|
43531
43929
|
function evictModuleGraphCacheEntries(uris) {
|
|
43532
|
-
|
|
43930
|
+
const paths = uris.map(uriToFilePath);
|
|
43931
|
+
for (const p of paths) moduleGraphCache.delete(p);
|
|
43932
|
+
evictAbsModuleCacheFiles(paths);
|
|
43533
43933
|
}
|
|
43534
43934
|
function hasNudoDirectives(source) {
|
|
43535
|
-
return /@nudo:(case|mock|pure|skip|sample|
|
|
43935
|
+
return /@nudo:(case|mock|pure|skip|sample|refine|import|env|mock-module|as|replace)\b/.test(source);
|
|
43536
43936
|
}
|
|
43537
43937
|
function uriToFilePath(uri) {
|
|
43538
43938
|
return uri.startsWith("file://") ? decodeURIComponent(uri.slice(7)) : uri;
|
|
@@ -43578,6 +43978,43 @@ function toLspDiagnostic(d, uri) {
|
|
|
43578
43978
|
}
|
|
43579
43979
|
return diag;
|
|
43580
43980
|
}
|
|
43981
|
+
function lspLoadModule(spec, fromFile) {
|
|
43982
|
+
return defaultLoadModule(spec, fromFile);
|
|
43983
|
+
}
|
|
43984
|
+
function checkToLspDiagnostics(filePath, source, loadModule) {
|
|
43985
|
+
try {
|
|
43986
|
+
const report = checkSource(filePath, source, pTrue, {
|
|
43987
|
+
loadModule: loadModule ?? lspLoadModule,
|
|
43988
|
+
fromFile: filePath
|
|
43989
|
+
});
|
|
43990
|
+
return report.issues.filter((i) => i.severity === "error" || i.severity === "warning").map((i) => {
|
|
43991
|
+
const line = (i.line ?? 1) - 1;
|
|
43992
|
+
const col = i.column ?? 0;
|
|
43993
|
+
const parts = [i.message];
|
|
43994
|
+
if (i.actual) parts.push(`actual: ${i.actual}`);
|
|
43995
|
+
if (i.expected) parts.push(`expected: ${i.expected}`);
|
|
43996
|
+
if (i.suggestion) parts.push(i.suggestion);
|
|
43997
|
+
return {
|
|
43998
|
+
severity: i.severity === "error" ? DiagnosticSeverity.Error : i.severity === "warning" ? DiagnosticSeverity.Warning : DiagnosticSeverity.Information,
|
|
43999
|
+
range: {
|
|
44000
|
+
start: { line, character: col },
|
|
44001
|
+
end: { line, character: col + 1 }
|
|
44002
|
+
},
|
|
44003
|
+
message: parts.join(" \xB7 "),
|
|
44004
|
+
source: "nudo-check",
|
|
44005
|
+
code: i.code,
|
|
44006
|
+
data: {
|
|
44007
|
+
actual: i.actual,
|
|
44008
|
+
expected: i.expected,
|
|
44009
|
+
fn: i.fn,
|
|
44010
|
+
suggestions: i.suggestion ? [i.suggestion] : []
|
|
44011
|
+
}
|
|
44012
|
+
};
|
|
44013
|
+
});
|
|
44014
|
+
} catch {
|
|
44015
|
+
return [];
|
|
44016
|
+
}
|
|
44017
|
+
}
|
|
43581
44018
|
async function validateText(filePath, uri, text, version, deps, propagate = false) {
|
|
43582
44019
|
if (deps.isNudoUri && !deps.isNudoUri(uri)) {
|
|
43583
44020
|
deps.sendDiagnostics({ uri, diagnostics: [] });
|
|
@@ -43600,7 +44037,10 @@ async function validateText(filePath, uri, text, version, deps, propagate = fals
|
|
|
43600
44037
|
}
|
|
43601
44038
|
analysisCache.set(filePath, { version, result });
|
|
43602
44039
|
knownFiles.add(filePath);
|
|
43603
|
-
|
|
44040
|
+
registerNudoImportDeps(filePath, text);
|
|
44041
|
+
const checkDiags = checkToLspDiagnostics(filePath, text);
|
|
44042
|
+
const evalDiags = result.diagnostics.map((d) => toLspDiagnostic(d, uri));
|
|
44043
|
+
deps.sendDiagnostics({ uri, diagnostics: [...checkDiags, ...evalDiags] });
|
|
43604
44044
|
if (!propagate || !deps.getOpenDocumentByPath) return;
|
|
43605
44045
|
let dependents;
|
|
43606
44046
|
try {
|
|
@@ -43612,22 +44052,31 @@ async function validateText(filePath, uri, text, version, deps, propagate = fals
|
|
|
43612
44052
|
if (dirtyPath === filePath) continue;
|
|
43613
44053
|
const doc = deps.getOpenDocumentByPath(dirtyPath);
|
|
43614
44054
|
if (!doc) continue;
|
|
44055
|
+
evictBPathCacheForFiles([dirtyPath]);
|
|
44056
|
+
evictAnalysisFileCacheForFiles([dirtyPath]);
|
|
44057
|
+
evictFnAnalysisCacheForFiles([dirtyPath]);
|
|
43615
44058
|
await validateText(dirtyPath, doc.uri, doc.getText(), doc.version, deps, false);
|
|
43616
44059
|
}
|
|
43617
44060
|
}
|
|
43618
44061
|
|
|
43619
44062
|
// src/agent-tools.ts
|
|
43620
|
-
import { readFileSync } from "fs";
|
|
43621
|
-
import { resolve } from "path";
|
|
43622
|
-
import {
|
|
43623
|
-
|
|
43624
|
-
|
|
44063
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
44064
|
+
import { resolve as resolve2 } from "path";
|
|
44065
|
+
import {
|
|
44066
|
+
analyzeFile as analyzeFile2,
|
|
44067
|
+
buildCaseDirective,
|
|
44068
|
+
getHoverAtPosition,
|
|
44069
|
+
collectAbsInlays,
|
|
44070
|
+
serializeInferJson
|
|
44071
|
+
} from "@nudojs/service";
|
|
44072
|
+
import { parse as parse2 } from "@nudojs/parser";
|
|
44073
|
+
import { T, typeValueToString, checkSource as checkSource2, serializeCheckJson, pTrue as pTrue2 } from "@nudojs/core";
|
|
43625
44074
|
function textResult(text) {
|
|
43626
44075
|
return { content: [{ type: "text", text }] };
|
|
43627
44076
|
}
|
|
43628
44077
|
function normalizeFilePath(file) {
|
|
43629
44078
|
const path = file.startsWith("file://") ? decodeURIComponent(file.slice(7)) : file;
|
|
43630
|
-
return
|
|
44079
|
+
return resolve2(path);
|
|
43631
44080
|
}
|
|
43632
44081
|
var BARE_PRIMITIVES = /* @__PURE__ */ new Set(["number", "string", "boolean", "bigint", "symbol"]);
|
|
43633
44082
|
function splitTopLevelUnion(expr) {
|
|
@@ -43692,7 +44141,7 @@ function injectBindings(source, bindings) {
|
|
|
43692
44141
|
const applied = [];
|
|
43693
44142
|
const unapplied = [];
|
|
43694
44143
|
if (bindings.length === 0) return { source, applied, unapplied };
|
|
43695
|
-
const ast =
|
|
44144
|
+
const ast = parse2(source);
|
|
43696
44145
|
const declLines = /* @__PURE__ */ new Map();
|
|
43697
44146
|
for (const stmt of ast.program.body) {
|
|
43698
44147
|
const names = /* @__PURE__ */ new Set();
|
|
@@ -43731,11 +44180,111 @@ function injectBindings(source, bindings) {
|
|
|
43731
44180
|
function readSource(filePath, deps = {}) {
|
|
43732
44181
|
const open = deps.getOpenText?.(filePath);
|
|
43733
44182
|
if (open) return open.text;
|
|
43734
|
-
return (deps.readFile ?? ((p) =>
|
|
44183
|
+
return (deps.readFile ?? ((p) => readFileSync2(p, "utf-8")))(filePath);
|
|
43735
44184
|
}
|
|
43736
44185
|
function analysisError(err) {
|
|
43737
44186
|
return textResult(`Error: ${err.message}`);
|
|
43738
44187
|
}
|
|
44188
|
+
function checkTool(params, deps = {}) {
|
|
44189
|
+
try {
|
|
44190
|
+
const filePath = normalizeFilePath(params.file);
|
|
44191
|
+
const source = params.source ?? readSource(filePath, deps);
|
|
44192
|
+
const report = checkSource2(filePath, source, pTrue2, {
|
|
44193
|
+
loadModule: params.loadModule ?? lspLoadModule,
|
|
44194
|
+
fromFile: filePath
|
|
44195
|
+
});
|
|
44196
|
+
const json = serializeCheckJson(report);
|
|
44197
|
+
if (params.format === "json") {
|
|
44198
|
+
return textResult(JSON.stringify(json, null, 2));
|
|
44199
|
+
}
|
|
44200
|
+
const lines = [
|
|
44201
|
+
json.ok ? "nudo check OK" : "nudo check FAILED",
|
|
44202
|
+
`${json.summary.errors} error \xB7 ${json.summary.warnings} warning \xB7 ${json.summary.functions} fn`
|
|
44203
|
+
];
|
|
44204
|
+
for (const i of json.issues) {
|
|
44205
|
+
if (i.severity === "info") continue;
|
|
44206
|
+
const loc = i.line != null ? ` L${i.line}` : "";
|
|
44207
|
+
lines.push(`[${i.severity}]${loc} ${i.message}`);
|
|
44208
|
+
if (i.actual) lines.push(` actual: ${i.actual}`);
|
|
44209
|
+
if (i.expected) lines.push(` expected: ${i.expected}`);
|
|
44210
|
+
}
|
|
44211
|
+
lines.push("");
|
|
44212
|
+
lines.push(JSON.stringify(json, null, 2));
|
|
44213
|
+
return textResult(lines.join("\n"));
|
|
44214
|
+
} catch (err) {
|
|
44215
|
+
return analysisError(err);
|
|
44216
|
+
}
|
|
44217
|
+
}
|
|
44218
|
+
function hoverTool(params, deps = {}) {
|
|
44219
|
+
try {
|
|
44220
|
+
const filePath = normalizeFilePath(params.file);
|
|
44221
|
+
const source = params.source ?? readSource(filePath, deps);
|
|
44222
|
+
const hover = getHoverAtPosition(filePath, source, params.line, params.column);
|
|
44223
|
+
const payload = {
|
|
44224
|
+
file: filePath,
|
|
44225
|
+
line: params.line,
|
|
44226
|
+
column: params.column,
|
|
44227
|
+
abs: hover?.abs ?? null,
|
|
44228
|
+
absMultiline: hover?.absMultiline ?? null,
|
|
44229
|
+
intension: hover?.intension ?? null,
|
|
44230
|
+
/** 有损外延,仅对照 */
|
|
44231
|
+
ext: hover?.typeText ?? null
|
|
44232
|
+
};
|
|
44233
|
+
if (params.includeInlays) {
|
|
44234
|
+
payload.inlays = collectAbsInlays(source, {
|
|
44235
|
+
loadModule: params.loadModule ?? lspLoadModule,
|
|
44236
|
+
fromFile: filePath
|
|
44237
|
+
});
|
|
44238
|
+
}
|
|
44239
|
+
return textResult(JSON.stringify(payload, null, 2));
|
|
44240
|
+
} catch (err) {
|
|
44241
|
+
return analysisError(err);
|
|
44242
|
+
}
|
|
44243
|
+
}
|
|
44244
|
+
function inferTool(params, deps = {}) {
|
|
44245
|
+
try {
|
|
44246
|
+
const filePath = normalizeFilePath(params.file);
|
|
44247
|
+
const source = params.source ?? readSource(filePath, deps);
|
|
44248
|
+
const result = analyzeFile2(filePath, source);
|
|
44249
|
+
let json = serializeInferJson(result, filePath);
|
|
44250
|
+
if (params.functions && params.functions.length > 0) {
|
|
44251
|
+
const keep = new Set(params.functions);
|
|
44252
|
+
const filtered = json.functions.filter((f) => keep.has(f.name));
|
|
44253
|
+
let cases = 0;
|
|
44254
|
+
for (const f of filtered) {
|
|
44255
|
+
cases += f.cases?.length ?? 0;
|
|
44256
|
+
}
|
|
44257
|
+
const summary = {
|
|
44258
|
+
...json.summary,
|
|
44259
|
+
functions: filtered.length,
|
|
44260
|
+
cases
|
|
44261
|
+
};
|
|
44262
|
+
json = { ...json, functions: filtered, summary };
|
|
44263
|
+
}
|
|
44264
|
+
if (params.format === "json") {
|
|
44265
|
+
return textResult(JSON.stringify(json, null, 2));
|
|
44266
|
+
}
|
|
44267
|
+
const lines = [
|
|
44268
|
+
`nudo infer ${json.file}`,
|
|
44269
|
+
`${json.summary.functions} fn \xB7 ${json.summary.cases} case \xB7 ${json.summary.diagnostics} diag`
|
|
44270
|
+
];
|
|
44271
|
+
for (const f of json.functions) {
|
|
44272
|
+
lines.push("");
|
|
44273
|
+
lines.push(`${f.name}${f.entryOnly ? " [entry-only]" : ""}`);
|
|
44274
|
+
for (const c of f.cases) {
|
|
44275
|
+
const args = c.args.join(", ");
|
|
44276
|
+
lines.push(` ${c.name}: (${args}) => ${c.result}`);
|
|
44277
|
+
if (c.intension?.abs) lines.push(` abs: ${c.intension.abs}`);
|
|
44278
|
+
else if (c.intension?.display) lines.push(` intension: ${c.intension.display}`);
|
|
44279
|
+
}
|
|
44280
|
+
}
|
|
44281
|
+
lines.push("");
|
|
44282
|
+
lines.push(JSON.stringify(json, null, 2));
|
|
44283
|
+
return textResult(lines.join("\n"));
|
|
44284
|
+
} catch (err) {
|
|
44285
|
+
return analysisError(err);
|
|
44286
|
+
}
|
|
44287
|
+
}
|
|
43739
44288
|
function whatIf(params, deps = {}) {
|
|
43740
44289
|
try {
|
|
43741
44290
|
const filePath = normalizeFilePath(params.file);
|
|
@@ -43820,6 +44369,9 @@ var NUDO_COMMANDS = [
|
|
|
43820
44369
|
"nudo.whatIf",
|
|
43821
44370
|
"nudo.suggestCase",
|
|
43822
44371
|
"nudo.trace",
|
|
44372
|
+
"nudo.check",
|
|
44373
|
+
"nudo.hover",
|
|
44374
|
+
"nudo.infer",
|
|
43823
44375
|
"nudo.selectCase",
|
|
43824
44376
|
"nudo.getActiveCases"
|
|
43825
44377
|
];
|
|
@@ -43848,6 +44400,8 @@ connection.onInitialize((_params) => ({
|
|
|
43848
44400
|
definitionProvider: true,
|
|
43849
44401
|
referencesProvider: true,
|
|
43850
44402
|
renameProvider: true,
|
|
44403
|
+
documentSymbolProvider: true,
|
|
44404
|
+
workspaceSymbolProvider: true,
|
|
43851
44405
|
codeActionProvider: {
|
|
43852
44406
|
codeActionKinds: ["quickfix"]
|
|
43853
44407
|
},
|
|
@@ -43857,8 +44411,8 @@ connection.onInitialize((_params) => ({
|
|
|
43857
44411
|
semanticTokensProvider: {
|
|
43858
44412
|
full: true,
|
|
43859
44413
|
legend: {
|
|
43860
|
-
tokenTypes: [...
|
|
43861
|
-
tokenModifiers: [...
|
|
44414
|
+
tokenTypes: [...SEMANTIC_TOKEN_TYPES],
|
|
44415
|
+
tokenModifiers: [...SEMANTIC_TOKEN_MODIFIERS]
|
|
43862
44416
|
}
|
|
43863
44417
|
},
|
|
43864
44418
|
executeCommandProvider: {
|
|
@@ -43906,16 +44460,27 @@ function registerWatchedFilesListener(listener) {
|
|
|
43906
44460
|
if (idx >= 0) watchedFilesListeners.splice(idx, 1);
|
|
43907
44461
|
};
|
|
43908
44462
|
}
|
|
44463
|
+
function isNudoDepPath(filePath) {
|
|
44464
|
+
return /\.nudo\.(js|mjs|ts)$/.test(filePath);
|
|
44465
|
+
}
|
|
43909
44466
|
function handleWatchedFilesChanges(changes, isOpen) {
|
|
43910
44467
|
const gone = [];
|
|
44468
|
+
const nudoTouched = [];
|
|
43911
44469
|
for (const change of changes) {
|
|
43912
|
-
|
|
43913
|
-
if (
|
|
43914
|
-
|
|
43915
|
-
|
|
43916
|
-
|
|
43917
|
-
|
|
43918
|
-
|
|
44470
|
+
const filePath = uriToFilePath(change.uri);
|
|
44471
|
+
if (change.type === FileChangeType.Deleted) {
|
|
44472
|
+
if (isOpen(change.uri)) continue;
|
|
44473
|
+
gone.push(change.uri);
|
|
44474
|
+
forgetValidatedFile(filePath);
|
|
44475
|
+
activeCases.delete(change.uri);
|
|
44476
|
+
nudoFileCache.delete(change.uri);
|
|
44477
|
+
connection.sendDiagnostics({ uri: change.uri, diagnostics: [] });
|
|
44478
|
+
if (isNudoDepPath(filePath)) nudoTouched.push(filePath);
|
|
44479
|
+
continue;
|
|
44480
|
+
}
|
|
44481
|
+
if (isNudoDepPath(filePath)) {
|
|
44482
|
+
nudoTouched.push(filePath);
|
|
44483
|
+
}
|
|
43919
44484
|
}
|
|
43920
44485
|
if (gone.length > 0) {
|
|
43921
44486
|
for (const listener of [...watchedFilesListeners]) {
|
|
@@ -43925,6 +44490,13 @@ function handleWatchedFilesChanges(changes, isOpen) {
|
|
|
43925
44490
|
}
|
|
43926
44491
|
}
|
|
43927
44492
|
}
|
|
44493
|
+
if (nudoTouched.length > 0) {
|
|
44494
|
+
const deps = validationDeps();
|
|
44495
|
+
for (const p of nudoTouched) {
|
|
44496
|
+
void handleNudoDepFileChanged(p, deps).catch(() => {
|
|
44497
|
+
});
|
|
44498
|
+
}
|
|
44499
|
+
}
|
|
43928
44500
|
return gone;
|
|
43929
44501
|
}
|
|
43930
44502
|
connection.onDidChangeWatchedFiles(
|
|
@@ -43959,14 +44531,27 @@ connection.onHover((params) => {
|
|
|
43959
44531
|
const column = params.position.character;
|
|
43960
44532
|
const cases = getActiveCasesForUri(params.textDocument.uri);
|
|
43961
44533
|
try {
|
|
43962
|
-
const
|
|
43963
|
-
if (!
|
|
44534
|
+
const hover = getHoverAtPosition2(filePath, source, line, column, cases);
|
|
44535
|
+
if (!hover) return null;
|
|
44536
|
+
const lines = [];
|
|
44537
|
+
if (hover.absMultiline) {
|
|
44538
|
+
lines.push("```nudo", hover.absMultiline, "```");
|
|
44539
|
+
} else if (hover.abs) {
|
|
44540
|
+
lines.push("```nudo", hover.abs, "```");
|
|
44541
|
+
}
|
|
44542
|
+
if (hover.intension && hover.intension !== hover.abs) {
|
|
44543
|
+
lines.push("```nudo", hover.intension, "```");
|
|
44544
|
+
}
|
|
44545
|
+
if (hover.typeText && hover.typeText !== hover.intension && hover.typeText !== hover.abs) {
|
|
44546
|
+
lines.push("```nudo", `ext: ${hover.typeText}`, "```");
|
|
44547
|
+
}
|
|
44548
|
+
if (lines.length === 0) {
|
|
44549
|
+
lines.push("```nudo", hover.typeText, "```");
|
|
44550
|
+
}
|
|
43964
44551
|
return {
|
|
43965
44552
|
contents: {
|
|
43966
44553
|
kind: MarkupKind.Markdown,
|
|
43967
|
-
value:
|
|
43968
|
-
${typeValueToString2(tv)}
|
|
43969
|
-
\`\`\``
|
|
44554
|
+
value: lines.join("\n")
|
|
43970
44555
|
}
|
|
43971
44556
|
};
|
|
43972
44557
|
} catch {
|
|
@@ -44048,89 +44633,195 @@ connection.languages.inlayHint.on((params) => {
|
|
|
44048
44633
|
paddingLeft: true
|
|
44049
44634
|
});
|
|
44050
44635
|
}
|
|
44636
|
+
try {
|
|
44637
|
+
for (const abs of collectAbsInlays2(source, {
|
|
44638
|
+
loadModule: lspLoadModule,
|
|
44639
|
+
fromFile: filePath
|
|
44640
|
+
})) {
|
|
44641
|
+
const lineIdx = abs.line - 1;
|
|
44642
|
+
if (lineIdx < 0 || lineIdx >= lines.length) continue;
|
|
44643
|
+
hints.push({
|
|
44644
|
+
position: { line: lineIdx, character: abs.character },
|
|
44645
|
+
label: abs.label,
|
|
44646
|
+
kind: abs.kind === "parameter" ? InlayHintKind.Parameter : InlayHintKind.Type,
|
|
44647
|
+
paddingLeft: true
|
|
44648
|
+
});
|
|
44649
|
+
}
|
|
44650
|
+
} catch {
|
|
44651
|
+
}
|
|
44051
44652
|
return hints;
|
|
44052
44653
|
} catch {
|
|
44053
44654
|
return [];
|
|
44054
44655
|
}
|
|
44055
44656
|
});
|
|
44657
|
+
function filePathToUri(filePath) {
|
|
44658
|
+
if (filePath.startsWith("file://")) return filePath;
|
|
44659
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
44660
|
+
return normalized.startsWith("/") ? `file://${normalized}` : `file:///${normalized}`;
|
|
44661
|
+
}
|
|
44662
|
+
function navigationExtraFiles(currentPath) {
|
|
44663
|
+
const open = documents.all().map((d) => uriToFilePath(d.uri));
|
|
44664
|
+
const all = /* @__PURE__ */ new Set([...open, ...knownFiles, currentPath]);
|
|
44665
|
+
return [...all];
|
|
44666
|
+
}
|
|
44667
|
+
connection.onDocumentSymbol((params) => {
|
|
44668
|
+
const document2 = documents.get(params.textDocument.uri);
|
|
44669
|
+
if (!document2) return [];
|
|
44670
|
+
if (!isNudoFile(params.textDocument.uri)) return [];
|
|
44671
|
+
try {
|
|
44672
|
+
const ast = parse3(document2.getText());
|
|
44673
|
+
const toLsp = (s) => ({
|
|
44674
|
+
name: s.name,
|
|
44675
|
+
detail: s.detail,
|
|
44676
|
+
kind: s.kind,
|
|
44677
|
+
range: s.range,
|
|
44678
|
+
selectionRange: s.selectionRange,
|
|
44679
|
+
children: s.children?.map(toLsp)
|
|
44680
|
+
});
|
|
44681
|
+
return documentSymbols(ast).map(toLsp);
|
|
44682
|
+
} catch {
|
|
44683
|
+
return [];
|
|
44684
|
+
}
|
|
44685
|
+
});
|
|
44686
|
+
connection.onWorkspaceSymbol((params) => {
|
|
44687
|
+
const query = params.query.toLowerCase();
|
|
44688
|
+
const out = [];
|
|
44689
|
+
const files = /* @__PURE__ */ new Set([...knownFiles]);
|
|
44690
|
+
for (const d of documents.all()) files.add(uriToFilePath(d.uri));
|
|
44691
|
+
for (const filePath of files) {
|
|
44692
|
+
const doc = documents.all().find((d) => uriToFilePath(d.uri) === filePath);
|
|
44693
|
+
let source;
|
|
44694
|
+
if (doc) {
|
|
44695
|
+
source = doc.getText();
|
|
44696
|
+
} else {
|
|
44697
|
+
try {
|
|
44698
|
+
source = readFileSync3(filePath, "utf-8");
|
|
44699
|
+
} catch {
|
|
44700
|
+
source = void 0;
|
|
44701
|
+
}
|
|
44702
|
+
}
|
|
44703
|
+
if (source === void 0) continue;
|
|
44704
|
+
try {
|
|
44705
|
+
const ast = parse3(source);
|
|
44706
|
+
const uri = doc?.uri ?? filePathToUri(filePath);
|
|
44707
|
+
for (const sym of documentSymbols(ast)) {
|
|
44708
|
+
if (query && !sym.name.toLowerCase().includes(query)) continue;
|
|
44709
|
+
out.push({
|
|
44710
|
+
name: sym.name,
|
|
44711
|
+
kind: sym.kind,
|
|
44712
|
+
location: {
|
|
44713
|
+
uri,
|
|
44714
|
+
range: {
|
|
44715
|
+
start: { line: sym.selectionRange.start.line, character: sym.selectionRange.start.character },
|
|
44716
|
+
end: { line: sym.selectionRange.end.line, character: sym.selectionRange.end.character }
|
|
44717
|
+
}
|
|
44718
|
+
}
|
|
44719
|
+
});
|
|
44720
|
+
}
|
|
44721
|
+
} catch {
|
|
44722
|
+
}
|
|
44723
|
+
}
|
|
44724
|
+
return out;
|
|
44725
|
+
});
|
|
44056
44726
|
connection.onDefinition((params) => {
|
|
44057
44727
|
const document2 = documents.get(params.textDocument.uri);
|
|
44058
44728
|
if (!document2) return null;
|
|
44059
44729
|
if (!isNudoFile(params.textDocument.uri)) return null;
|
|
44060
44730
|
const source = document2.getText();
|
|
44061
|
-
const
|
|
44062
|
-
const table = buildSymbolTable(ast, params.textDocument.uri);
|
|
44731
|
+
const filePath = uriToFilePath(params.textDocument.uri);
|
|
44063
44732
|
const line = params.position.line + 1;
|
|
44064
44733
|
const column = params.position.character;
|
|
44065
|
-
|
|
44066
|
-
|
|
44067
|
-
|
|
44068
|
-
|
|
44069
|
-
|
|
44070
|
-
|
|
44071
|
-
|
|
44072
|
-
|
|
44073
|
-
|
|
44074
|
-
|
|
44075
|
-
|
|
44734
|
+
try {
|
|
44735
|
+
const ast = parse3(source);
|
|
44736
|
+
const identAtPos = findIdentifierAtPosition(ast, line, column);
|
|
44737
|
+
if (!identAtPos) return null;
|
|
44738
|
+
const def = resolveDefinition(filePath, source, identAtPos);
|
|
44739
|
+
if (!def) return null;
|
|
44740
|
+
return {
|
|
44741
|
+
uri: filePathToUri(def.filePath),
|
|
44742
|
+
range: {
|
|
44743
|
+
start: { line: def.loc.start.line - 1, character: def.loc.start.column },
|
|
44744
|
+
end: { line: def.loc.end.line - 1, character: def.loc.end.column }
|
|
44745
|
+
}
|
|
44746
|
+
};
|
|
44747
|
+
} catch {
|
|
44748
|
+
return null;
|
|
44749
|
+
}
|
|
44076
44750
|
});
|
|
44077
44751
|
connection.onReferences((params) => {
|
|
44078
44752
|
const document2 = documents.get(params.textDocument.uri);
|
|
44079
44753
|
if (!document2) return [];
|
|
44080
44754
|
if (!isNudoFile(params.textDocument.uri)) return [];
|
|
44081
44755
|
const source = document2.getText();
|
|
44082
|
-
const
|
|
44083
|
-
const table = buildSymbolTable(ast, params.textDocument.uri);
|
|
44756
|
+
const filePath = uriToFilePath(params.textDocument.uri);
|
|
44084
44757
|
const line = params.position.line + 1;
|
|
44085
44758
|
const column = params.position.character;
|
|
44086
|
-
|
|
44087
|
-
|
|
44088
|
-
|
|
44089
|
-
|
|
44090
|
-
|
|
44091
|
-
|
|
44092
|
-
|
|
44093
|
-
|
|
44094
|
-
|
|
44095
|
-
|
|
44759
|
+
try {
|
|
44760
|
+
const ast = parse3(source);
|
|
44761
|
+
const identAtPos = findIdentifierAtPosition(ast, line, column);
|
|
44762
|
+
if (!identAtPos) return [];
|
|
44763
|
+
const refs = resolveReferences(filePath, source, identAtPos, {
|
|
44764
|
+
extraFiles: navigationExtraFiles(filePath),
|
|
44765
|
+
includeDeclaration: params.context?.includeDeclaration !== false
|
|
44766
|
+
});
|
|
44767
|
+
return refs.map((ref) => ({
|
|
44768
|
+
uri: ref.uri ? filePathToUri(ref.uri) : params.textDocument.uri,
|
|
44769
|
+
range: {
|
|
44770
|
+
start: { line: ref.loc.start.line - 1, character: ref.loc.start.column },
|
|
44771
|
+
end: { line: ref.loc.end.line - 1, character: ref.loc.end.column }
|
|
44772
|
+
}
|
|
44773
|
+
}));
|
|
44774
|
+
} catch {
|
|
44775
|
+
return [];
|
|
44776
|
+
}
|
|
44096
44777
|
});
|
|
44097
44778
|
connection.onRenameRequest((params) => {
|
|
44098
44779
|
const document2 = documents.get(params.textDocument.uri);
|
|
44099
44780
|
if (!document2) return null;
|
|
44100
44781
|
if (!isNudoFile(params.textDocument.uri)) return null;
|
|
44101
44782
|
const source = document2.getText();
|
|
44102
|
-
const
|
|
44103
|
-
const table = buildSymbolTable(ast, params.textDocument.uri);
|
|
44783
|
+
const filePath = uriToFilePath(params.textDocument.uri);
|
|
44104
44784
|
const line = params.position.line + 1;
|
|
44105
44785
|
const column = params.position.character;
|
|
44106
|
-
|
|
44107
|
-
|
|
44108
|
-
|
|
44109
|
-
|
|
44110
|
-
|
|
44111
|
-
|
|
44112
|
-
|
|
44113
|
-
|
|
44114
|
-
|
|
44115
|
-
|
|
44116
|
-
|
|
44117
|
-
|
|
44118
|
-
|
|
44119
|
-
|
|
44120
|
-
|
|
44121
|
-
|
|
44122
|
-
|
|
44123
|
-
|
|
44124
|
-
|
|
44125
|
-
|
|
44126
|
-
|
|
44127
|
-
}
|
|
44128
|
-
|
|
44129
|
-
|
|
44130
|
-
|
|
44131
|
-
|
|
44786
|
+
try {
|
|
44787
|
+
const ast = parse3(source);
|
|
44788
|
+
const identAtPos = findIdentifierAtPosition(ast, line, column);
|
|
44789
|
+
if (!identAtPos) return null;
|
|
44790
|
+
const def = resolveDefinition(filePath, source, identAtPos);
|
|
44791
|
+
const refs = resolveReferences(filePath, source, identAtPos, {
|
|
44792
|
+
extraFiles: navigationExtraFiles(filePath)
|
|
44793
|
+
});
|
|
44794
|
+
const changes = {};
|
|
44795
|
+
const push = (uri, loc) => {
|
|
44796
|
+
const list = changes[uri] ??= [];
|
|
44797
|
+
list.push({
|
|
44798
|
+
range: {
|
|
44799
|
+
start: { line: loc.start.line - 1, character: loc.start.column },
|
|
44800
|
+
end: { line: loc.end.line - 1, character: loc.end.column }
|
|
44801
|
+
},
|
|
44802
|
+
newText: params.newName
|
|
44803
|
+
});
|
|
44804
|
+
};
|
|
44805
|
+
if (def) {
|
|
44806
|
+
push(filePathToUri(def.filePath), def.loc);
|
|
44807
|
+
}
|
|
44808
|
+
for (const ref of refs) {
|
|
44809
|
+
push(ref.uri ? filePathToUri(ref.uri) : params.textDocument.uri, ref.loc);
|
|
44810
|
+
}
|
|
44811
|
+
for (const uri of Object.keys(changes)) {
|
|
44812
|
+
const seen = /* @__PURE__ */ new Set();
|
|
44813
|
+
changes[uri] = changes[uri].filter((e) => {
|
|
44814
|
+
const key = `${e.range.start.line}:${e.range.start.character}:${e.range.end.line}:${e.range.end.character}`;
|
|
44815
|
+
if (seen.has(key)) return false;
|
|
44816
|
+
seen.add(key);
|
|
44817
|
+
return true;
|
|
44818
|
+
});
|
|
44132
44819
|
}
|
|
44133
|
-
|
|
44820
|
+
if (Object.keys(changes).length === 0) return null;
|
|
44821
|
+
return { changes };
|
|
44822
|
+
} catch {
|
|
44823
|
+
return null;
|
|
44824
|
+
}
|
|
44134
44825
|
});
|
|
44135
44826
|
connection.onCodeAction((params) => {
|
|
44136
44827
|
const document2 = documents.get(params.textDocument.uri);
|
|
@@ -44153,14 +44844,6 @@ connection.onCodeAction((params) => {
|
|
|
44153
44844
|
}
|
|
44154
44845
|
});
|
|
44155
44846
|
}
|
|
44156
|
-
if (diag.code === "nudo-assertion-failed") {
|
|
44157
|
-
actions.push({
|
|
44158
|
-
title: "Update @nudo:returns to match inferred type",
|
|
44159
|
-
kind: "quickfix",
|
|
44160
|
-
diagnostics: [diag],
|
|
44161
|
-
isPreferred: false
|
|
44162
|
-
});
|
|
44163
|
-
}
|
|
44164
44847
|
}
|
|
44165
44848
|
return actions;
|
|
44166
44849
|
});
|
|
@@ -44174,7 +44857,7 @@ connection.onSignatureHelp((params) => {
|
|
|
44174
44857
|
const column = params.position.character;
|
|
44175
44858
|
const cases = getActiveCasesForUri(params.textDocument.uri);
|
|
44176
44859
|
try {
|
|
44177
|
-
const ast =
|
|
44860
|
+
const ast = parse3(source);
|
|
44178
44861
|
const callInfo = findEnclosingCall(ast, line, column);
|
|
44179
44862
|
if (!callInfo) return null;
|
|
44180
44863
|
const fnType = getTypeAtPosition(filePath, source, callInfo.calleeLine, callInfo.calleeCol, cases);
|
|
@@ -44239,7 +44922,12 @@ connection.languages.semanticTokens.on((params) => {
|
|
|
44239
44922
|
const document2 = documents.get(params.textDocument.uri);
|
|
44240
44923
|
if (!document2) return { data: [] };
|
|
44241
44924
|
if (!isNudoFile(params.textDocument.uri)) return { data: [] };
|
|
44242
|
-
|
|
44925
|
+
try {
|
|
44926
|
+
const filePath = uriToFilePath(document2.uri);
|
|
44927
|
+
return { data: buildSemanticTokens(filePath, document2.getText()) };
|
|
44928
|
+
} catch {
|
|
44929
|
+
return { data: [] };
|
|
44930
|
+
}
|
|
44243
44931
|
});
|
|
44244
44932
|
function uriForFileOrUri(params) {
|
|
44245
44933
|
if (params.uri) return params.uri;
|
|
@@ -44281,6 +44969,12 @@ function dispatchNudoCommand(command, arg) {
|
|
|
44281
44969
|
return suggestCase(arg, agentToolDeps);
|
|
44282
44970
|
case "nudo.trace":
|
|
44283
44971
|
return trace(arg, agentToolDeps);
|
|
44972
|
+
case "nudo.check":
|
|
44973
|
+
return checkTool(arg, agentToolDeps);
|
|
44974
|
+
case "nudo.hover":
|
|
44975
|
+
return hoverTool(arg, agentToolDeps);
|
|
44976
|
+
case "nudo.infer":
|
|
44977
|
+
return inferTool(arg, agentToolDeps);
|
|
44284
44978
|
case "nudo.selectCase":
|
|
44285
44979
|
return handleSelectCase(arg);
|
|
44286
44980
|
case "nudo.getActiveCases":
|
|
@@ -44300,6 +44994,9 @@ function dispatchAgentRequest(command, params) {
|
|
|
44300
44994
|
connection.onRequest("nudo/whatIf", (params) => dispatchAgentRequest("nudo.whatIf", params));
|
|
44301
44995
|
connection.onRequest("nudo/suggestCase", (params) => dispatchAgentRequest("nudo.suggestCase", params));
|
|
44302
44996
|
connection.onRequest("nudo/trace", (params) => dispatchAgentRequest("nudo.trace", params));
|
|
44997
|
+
connection.onRequest("nudo/check", (params) => dispatchAgentRequest("nudo.check", params));
|
|
44998
|
+
connection.onRequest("nudo/hover", (params) => dispatchAgentRequest("nudo.hover", params));
|
|
44999
|
+
connection.onRequest("nudo/infer", (params) => dispatchAgentRequest("nudo.infer", params));
|
|
44303
45000
|
connection.languages.diagnostics.on((params) => {
|
|
44304
45001
|
const document2 = documents.get(params.textDocument.uri);
|
|
44305
45002
|
if (!document2) return { kind: "full", items: [] };
|
|
@@ -44317,7 +45014,7 @@ connection.languages.diagnostics.on((params) => {
|
|
|
44317
45014
|
});
|
|
44318
45015
|
var nudoFileCache = /* @__PURE__ */ new Map();
|
|
44319
45016
|
function isNudoFile(uri) {
|
|
44320
|
-
if (!
|
|
45017
|
+
if (!isNudoTargetPath(uriToFilePath(uri))) return false;
|
|
44321
45018
|
const cached = nudoFileCache.get(uri);
|
|
44322
45019
|
if (cached !== void 0) return cached;
|
|
44323
45020
|
const doc = documents.get(uri);
|