@nudojs/lsp 0.4.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 +525 -87
- package/package.json +15 -5
- package/CHANGELOG.md +0 -63
- package/agent-skill/SKILL.md +0 -82
- package/src/__tests__/agent-check.test.ts +0 -47
- package/src/__tests__/agent-hover.test.ts +0 -28
- package/src/__tests__/agent-infer.test.ts +0 -38
- package/src/__tests__/check-diagnostics.test.ts +0 -46
- package/src/__tests__/definition.test.ts +0 -32
- package/src/__tests__/lsp-integration.test.ts +0 -921
- package/src/__tests__/nudo-dep-evict.test.ts +0 -103
- package/src/agent-tools.ts +0 -486
- package/src/semantic-tokens.ts +0 -9
- package/src/server.ts +0 -748
- package/src/symbols.ts +0 -109
- package/src/validation.ts +0 -348
- 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,6 +43396,7 @@ import {
|
|
|
43396
43396
|
InlayHintKind
|
|
43397
43397
|
} from "vscode-languageserver/node";
|
|
43398
43398
|
import { TextDocument } from "vscode-languageserver-textdocument";
|
|
43399
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
43399
43400
|
import {
|
|
43400
43401
|
getTypeAtPosition,
|
|
43401
43402
|
getHoverAtPosition as getHoverAtPosition2,
|
|
@@ -43405,23 +43406,27 @@ import {
|
|
|
43405
43406
|
isNudoTargetPath,
|
|
43406
43407
|
collectAbsInlays as collectAbsInlays2
|
|
43407
43408
|
} from "@nudojs/service";
|
|
43408
|
-
import { parse as
|
|
43409
|
+
import { parse as parse3 } from "@nudojs/parser";
|
|
43409
43410
|
|
|
43410
43411
|
// src/symbols.ts
|
|
43411
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";
|
|
43412
43416
|
function locFromNode(node) {
|
|
43413
43417
|
return {
|
|
43414
43418
|
start: { line: node.loc?.start.line ?? 1, column: node.loc?.start.column ?? 0 },
|
|
43415
43419
|
end: { line: node.loc?.end.line ?? 1, column: node.loc?.end.column ?? 0 }
|
|
43416
43420
|
};
|
|
43417
43421
|
}
|
|
43422
|
+
function traverseFn() {
|
|
43423
|
+
return typeof import_traverse.default === "function" ? import_traverse.default : import_traverse.default.default;
|
|
43424
|
+
}
|
|
43418
43425
|
function buildSymbolTable(ast, uri) {
|
|
43419
43426
|
const definitions = /* @__PURE__ */ new Map();
|
|
43420
43427
|
const references = [];
|
|
43421
|
-
const traverseFn = typeof import_traverse.default === "function" ? import_traverse.default : import_traverse.default.default;
|
|
43422
43428
|
try {
|
|
43423
|
-
traverseFn(ast, {
|
|
43424
|
-
// Collect definitions
|
|
43429
|
+
traverseFn()(ast, {
|
|
43425
43430
|
FunctionDeclaration(path) {
|
|
43426
43431
|
if (path.node.id) {
|
|
43427
43432
|
definitions.set(path.node.id.name, {
|
|
@@ -43452,7 +43457,6 @@ function buildSymbolTable(ast, uri) {
|
|
|
43452
43457
|
});
|
|
43453
43458
|
}
|
|
43454
43459
|
},
|
|
43455
|
-
// Collect references
|
|
43456
43460
|
Identifier(path) {
|
|
43457
43461
|
if (path.parentPath?.node.type === "FunctionDeclaration" && path.parentPath.node.id === path.node) return;
|
|
43458
43462
|
if (path.parentPath?.node.type === "VariableDeclarator" && path.parentPath.node.id === path.node) return;
|
|
@@ -43476,9 +43480,8 @@ function findReferences(symbolTable, name) {
|
|
|
43476
43480
|
}
|
|
43477
43481
|
function findIdentifierAtPosition(ast, line, column) {
|
|
43478
43482
|
let found = null;
|
|
43479
|
-
const traverseFn = typeof import_traverse.default === "function" ? import_traverse.default : import_traverse.default.default;
|
|
43480
43483
|
try {
|
|
43481
|
-
traverseFn(ast, {
|
|
43484
|
+
traverseFn()(ast, {
|
|
43482
43485
|
Identifier(path) {
|
|
43483
43486
|
const loc = path.node.loc;
|
|
43484
43487
|
if (!loc) return;
|
|
@@ -43492,6 +43495,349 @@ function findIdentifierAtPosition(ast, line, column) {
|
|
|
43492
43495
|
}
|
|
43493
43496
|
return found;
|
|
43494
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
|
+
}
|
|
43495
43841
|
|
|
43496
43842
|
// src/semantic-tokens.ts
|
|
43497
43843
|
import {
|
|
@@ -43501,7 +43847,7 @@ import {
|
|
|
43501
43847
|
} from "@nudojs/service";
|
|
43502
43848
|
|
|
43503
43849
|
// src/validation.ts
|
|
43504
|
-
import { dirname, resolve as resolvePath } from "path";
|
|
43850
|
+
import { dirname as dirname2, resolve as resolvePath } from "path";
|
|
43505
43851
|
import {
|
|
43506
43852
|
analyzeFile,
|
|
43507
43853
|
analyzeFileAsync,
|
|
@@ -43540,7 +43886,7 @@ function registerNudoImportDeps(filePath, source) {
|
|
|
43540
43886
|
const imports = extractNudoImports(source);
|
|
43541
43887
|
for (const imp of imports) {
|
|
43542
43888
|
if (!imp.spec.startsWith(".") && !imp.spec.startsWith("/")) continue;
|
|
43543
|
-
const dep = normPath(resolvePath(
|
|
43889
|
+
const dep = normPath(resolvePath(dirname2(filePath), imp.spec));
|
|
43544
43890
|
let set = nudoDepParents.get(dep);
|
|
43545
43891
|
if (!set) {
|
|
43546
43892
|
set = /* @__PURE__ */ new Set();
|
|
@@ -43714,8 +44060,8 @@ async function validateText(filePath, uri, text, version, deps, propagate = fals
|
|
|
43714
44060
|
}
|
|
43715
44061
|
|
|
43716
44062
|
// src/agent-tools.ts
|
|
43717
|
-
import { readFileSync } from "fs";
|
|
43718
|
-
import { resolve } from "path";
|
|
44063
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
44064
|
+
import { resolve as resolve2 } from "path";
|
|
43719
44065
|
import {
|
|
43720
44066
|
analyzeFile as analyzeFile2,
|
|
43721
44067
|
buildCaseDirective,
|
|
@@ -43723,14 +44069,14 @@ import {
|
|
|
43723
44069
|
collectAbsInlays,
|
|
43724
44070
|
serializeInferJson
|
|
43725
44071
|
} from "@nudojs/service";
|
|
43726
|
-
import { parse } from "@nudojs/parser";
|
|
44072
|
+
import { parse as parse2 } from "@nudojs/parser";
|
|
43727
44073
|
import { T, typeValueToString, checkSource as checkSource2, serializeCheckJson, pTrue as pTrue2 } from "@nudojs/core";
|
|
43728
44074
|
function textResult(text) {
|
|
43729
44075
|
return { content: [{ type: "text", text }] };
|
|
43730
44076
|
}
|
|
43731
44077
|
function normalizeFilePath(file) {
|
|
43732
44078
|
const path = file.startsWith("file://") ? decodeURIComponent(file.slice(7)) : file;
|
|
43733
|
-
return
|
|
44079
|
+
return resolve2(path);
|
|
43734
44080
|
}
|
|
43735
44081
|
var BARE_PRIMITIVES = /* @__PURE__ */ new Set(["number", "string", "boolean", "bigint", "symbol"]);
|
|
43736
44082
|
function splitTopLevelUnion(expr) {
|
|
@@ -43795,7 +44141,7 @@ function injectBindings(source, bindings) {
|
|
|
43795
44141
|
const applied = [];
|
|
43796
44142
|
const unapplied = [];
|
|
43797
44143
|
if (bindings.length === 0) return { source, applied, unapplied };
|
|
43798
|
-
const ast =
|
|
44144
|
+
const ast = parse2(source);
|
|
43799
44145
|
const declLines = /* @__PURE__ */ new Map();
|
|
43800
44146
|
for (const stmt of ast.program.body) {
|
|
43801
44147
|
const names = /* @__PURE__ */ new Set();
|
|
@@ -43834,7 +44180,7 @@ function injectBindings(source, bindings) {
|
|
|
43834
44180
|
function readSource(filePath, deps = {}) {
|
|
43835
44181
|
const open = deps.getOpenText?.(filePath);
|
|
43836
44182
|
if (open) return open.text;
|
|
43837
|
-
return (deps.readFile ?? ((p) =>
|
|
44183
|
+
return (deps.readFile ?? ((p) => readFileSync2(p, "utf-8")))(filePath);
|
|
43838
44184
|
}
|
|
43839
44185
|
function analysisError(err) {
|
|
43840
44186
|
return textResult(`Error: ${err.message}`);
|
|
@@ -44054,6 +44400,8 @@ connection.onInitialize((_params) => ({
|
|
|
44054
44400
|
definitionProvider: true,
|
|
44055
44401
|
referencesProvider: true,
|
|
44056
44402
|
renameProvider: true,
|
|
44403
|
+
documentSymbolProvider: true,
|
|
44404
|
+
workspaceSymbolProvider: true,
|
|
44057
44405
|
codeActionProvider: {
|
|
44058
44406
|
codeActionKinds: ["quickfix"]
|
|
44059
44407
|
},
|
|
@@ -44306,84 +44654,174 @@ connection.languages.inlayHint.on((params) => {
|
|
|
44306
44654
|
return [];
|
|
44307
44655
|
}
|
|
44308
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
|
+
});
|
|
44309
44726
|
connection.onDefinition((params) => {
|
|
44310
44727
|
const document2 = documents.get(params.textDocument.uri);
|
|
44311
44728
|
if (!document2) return null;
|
|
44312
44729
|
if (!isNudoFile(params.textDocument.uri)) return null;
|
|
44313
44730
|
const source = document2.getText();
|
|
44314
|
-
const
|
|
44315
|
-
const table = buildSymbolTable(ast, params.textDocument.uri);
|
|
44731
|
+
const filePath = uriToFilePath(params.textDocument.uri);
|
|
44316
44732
|
const line = params.position.line + 1;
|
|
44317
44733
|
const column = params.position.character;
|
|
44318
|
-
|
|
44319
|
-
|
|
44320
|
-
|
|
44321
|
-
|
|
44322
|
-
|
|
44323
|
-
|
|
44324
|
-
|
|
44325
|
-
|
|
44326
|
-
|
|
44327
|
-
|
|
44328
|
-
|
|
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
|
+
}
|
|
44329
44750
|
});
|
|
44330
44751
|
connection.onReferences((params) => {
|
|
44331
44752
|
const document2 = documents.get(params.textDocument.uri);
|
|
44332
44753
|
if (!document2) return [];
|
|
44333
44754
|
if (!isNudoFile(params.textDocument.uri)) return [];
|
|
44334
44755
|
const source = document2.getText();
|
|
44335
|
-
const
|
|
44336
|
-
const table = buildSymbolTable(ast, params.textDocument.uri);
|
|
44756
|
+
const filePath = uriToFilePath(params.textDocument.uri);
|
|
44337
44757
|
const line = params.position.line + 1;
|
|
44338
44758
|
const column = params.position.character;
|
|
44339
|
-
|
|
44340
|
-
|
|
44341
|
-
|
|
44342
|
-
|
|
44343
|
-
|
|
44344
|
-
|
|
44345
|
-
|
|
44346
|
-
|
|
44347
|
-
|
|
44348
|
-
|
|
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
|
+
}
|
|
44349
44777
|
});
|
|
44350
44778
|
connection.onRenameRequest((params) => {
|
|
44351
44779
|
const document2 = documents.get(params.textDocument.uri);
|
|
44352
44780
|
if (!document2) return null;
|
|
44353
44781
|
if (!isNudoFile(params.textDocument.uri)) return null;
|
|
44354
44782
|
const source = document2.getText();
|
|
44355
|
-
const
|
|
44356
|
-
const table = buildSymbolTable(ast, params.textDocument.uri);
|
|
44783
|
+
const filePath = uriToFilePath(params.textDocument.uri);
|
|
44357
44784
|
const line = params.position.line + 1;
|
|
44358
44785
|
const column = params.position.character;
|
|
44359
|
-
|
|
44360
|
-
|
|
44361
|
-
|
|
44362
|
-
|
|
44363
|
-
|
|
44364
|
-
|
|
44365
|
-
|
|
44366
|
-
|
|
44367
|
-
|
|
44368
|
-
|
|
44369
|
-
|
|
44370
|
-
|
|
44371
|
-
|
|
44372
|
-
|
|
44373
|
-
|
|
44374
|
-
|
|
44375
|
-
|
|
44376
|
-
|
|
44377
|
-
|
|
44378
|
-
|
|
44379
|
-
|
|
44380
|
-
}
|
|
44381
|
-
|
|
44382
|
-
|
|
44383
|
-
|
|
44384
|
-
|
|
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
|
+
});
|
|
44385
44819
|
}
|
|
44386
|
-
|
|
44820
|
+
if (Object.keys(changes).length === 0) return null;
|
|
44821
|
+
return { changes };
|
|
44822
|
+
} catch {
|
|
44823
|
+
return null;
|
|
44824
|
+
}
|
|
44387
44825
|
});
|
|
44388
44826
|
connection.onCodeAction((params) => {
|
|
44389
44827
|
const document2 = documents.get(params.textDocument.uri);
|
|
@@ -44419,7 +44857,7 @@ connection.onSignatureHelp((params) => {
|
|
|
44419
44857
|
const column = params.position.character;
|
|
44420
44858
|
const cases = getActiveCasesForUri(params.textDocument.uri);
|
|
44421
44859
|
try {
|
|
44422
|
-
const ast =
|
|
44860
|
+
const ast = parse3(source);
|
|
44423
44861
|
const callInfo = findEnclosingCall(ast, line, column);
|
|
44424
44862
|
if (!callInfo) return null;
|
|
44425
44863
|
const fnType = getTypeAtPosition(filePath, source, callInfo.calleeLine, callInfo.calleeCol, cases);
|