@orkestrel/probe 0.0.6 → 0.0.8
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/src/core/index.cjs +12 -4
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +24 -8
- package/dist/src/core/index.d.ts +24 -8
- package/dist/src/core/index.js +12 -4
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +139 -288
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +80 -24
- package/dist/src/server/index.d.ts +80 -24
- package/dist/src/server/index.js +141 -289
- package/dist/src/server/index.js.map +1 -1
- package/package.json +5 -4
package/dist/src/server/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import { closeSync, constants, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { closeSync, constants, existsSync, ftruncateSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
@@ -8,7 +8,8 @@ import { CLAIM_SHAPE, ProbeError, computeReceipt, createDestroyedError, formatCh
|
|
|
8
8
|
import { Emitter } from "@orkestrel/emitter";
|
|
9
9
|
import { createQueue } from "@orkestrel/queue";
|
|
10
10
|
import { createTimeout } from "@orkestrel/timeout";
|
|
11
|
-
import {
|
|
11
|
+
import { createLSPClient } from "@orkestrel/lsp";
|
|
12
|
+
import { createStdioTransport } from "@orkestrel/lsp/server";
|
|
12
13
|
import { PassThrough } from "node:stream";
|
|
13
14
|
import { setTimeout } from "node:timers/promises";
|
|
14
15
|
import { createMCPLegacy, createMCPServer } from "@orkestrel/mcp";
|
|
@@ -113,12 +114,18 @@ function resolveWorkspaceFile(workspace, target, mutate = false) {
|
|
|
113
114
|
* A containment walk and the write that follows it are separate calls, so a process that swaps the
|
|
114
115
|
* final component between them decides where the bytes land. `writeFileSync` opens with the default
|
|
115
116
|
* `w` flag, which follows a symbolic link at that component and creates the file when it is absent,
|
|
116
|
-
* so the walk's reading does not bind the write. Opening `O_WRONLY |
|
|
117
|
-
*
|
|
117
|
+
* so the walk's reading does not bind the write. Opening `O_WRONLY | O_NOFOLLOW` moves that
|
|
118
|
+
* decision into the call that writes: a link at the final component refuses the open, and the
|
|
118
119
|
* omitted `O_CREAT` fails `ENOENT` for a target that has gone since the walk saw it. This is the
|
|
119
120
|
* mutating counterpart of the `wx` flag every create in this package uses. Which code the refusal
|
|
120
121
|
* carries is the host's; Linux with Node v22.22.2 reported `ELOOP` on 2026-08-24.
|
|
121
122
|
*
|
|
123
|
+
* Truncation runs through the held descriptor rather than through an `O_TRUNC` flag, so it reaches
|
|
124
|
+
* the file the open bound. A Windows host refuses the numeric `O_TRUNC` without `O_CREAT` outright:
|
|
125
|
+
* measured on 2026-08-26 on Windows 11 with Node v24.19.0 over NTFS, `openSync` reported `EINVAL`
|
|
126
|
+
* for `O_WRONLY | O_TRUNC` and for `O_RDWR | O_TRUNC` while `O_WRONLY` alone opened, and adding
|
|
127
|
+
* `O_CREAT` would trade that refusal for the create this function must never perform.
|
|
128
|
+
*
|
|
122
129
|
* A directory component stays open, because Node exposes no descriptor-relative call to walk and
|
|
123
130
|
* write through one set of descriptors. Where a host's Node build defines no `O_NOFOLLOW`, that flag
|
|
124
131
|
* contributes nothing to the flag set and the final component is open on that host too.
|
|
@@ -138,8 +145,9 @@ function resolveWorkspaceFile(workspace, target, mutate = false) {
|
|
|
138
145
|
* ```
|
|
139
146
|
*/
|
|
140
147
|
function overwriteFile(file, text) {
|
|
141
|
-
const descriptor = openSync(file, constants.O_WRONLY | constants.
|
|
148
|
+
const descriptor = openSync(file, constants.O_WRONLY | constants.O_NOFOLLOW);
|
|
142
149
|
try {
|
|
150
|
+
ftruncateSync(descriptor, 0);
|
|
143
151
|
writeFileSync(descriptor, text, "utf8");
|
|
144
152
|
} finally {
|
|
145
153
|
closeSync(descriptor);
|
|
@@ -514,24 +522,6 @@ function matchesWorkspaceModule(path) {
|
|
|
514
522
|
return /\.(?:[cm]?[jt]sx?|vue|json)$/.test(path);
|
|
515
523
|
}
|
|
516
524
|
/**
|
|
517
|
-
* Reads a JSON-RPC frame's declared byte length.
|
|
518
|
-
*
|
|
519
|
-
* @param header - The frame header text without its terminating empty line
|
|
520
|
-
* @returns The non-negative content length, or `undefined` for an invalid header
|
|
521
|
-
*
|
|
522
|
-
* @example
|
|
523
|
-
* ```ts
|
|
524
|
-
* parseContentLength('Content-Length: 128') // 128
|
|
525
|
-
* parseContentLength('Content-Type: application/json') // undefined
|
|
526
|
-
* ```
|
|
527
|
-
*/
|
|
528
|
-
function parseContentLength(header) {
|
|
529
|
-
const text = /(?:^|\r\n)Content-Length:\s*(\d+)(?:\r\n|$)/i.exec(header)?.[1];
|
|
530
|
-
if (text === void 0) return void 0;
|
|
531
|
-
const length = Number.parseInt(text, 10);
|
|
532
|
-
return Number.isSafeInteger(length) && length >= 0 ? length : void 0;
|
|
533
|
-
}
|
|
534
|
-
/**
|
|
535
525
|
* Normalizes a caught or foreign error into readable text.
|
|
536
526
|
*
|
|
537
527
|
* @param value - The value to describe
|
|
@@ -805,7 +795,7 @@ var Overlay = class {
|
|
|
805
795
|
};
|
|
806
796
|
//#endregion
|
|
807
797
|
//#region package.json
|
|
808
|
-
var version = "0.0.
|
|
798
|
+
var version = "0.0.8";
|
|
809
799
|
var peerDependencies = {
|
|
810
800
|
"oxlint": "^1.77.0",
|
|
811
801
|
"typescript": "^6.0.0",
|
|
@@ -817,13 +807,22 @@ var peerDependencies = {
|
|
|
817
807
|
* Inspects virtual documents through one resident Oxlint language server.
|
|
818
808
|
*
|
|
819
809
|
* @remarks
|
|
820
|
-
* Construction starts the target workspace's Oxlint binary with its Language Server Protocol
|
|
821
|
-
*
|
|
822
|
-
*
|
|
810
|
+
* Construction starts the target workspace's Oxlint binary with its Language Server Protocol mode
|
|
811
|
+
* and hands the conversation to `@orkestrel/lsp`: `createStdioTransport` owns the child process and
|
|
812
|
+
* its bytes, and `createLSPClient` owns the framing, the request correlation, the capabilities this
|
|
813
|
+
* stage advertises, and the choice between pulled and pushed diagnostics. This stage owns the
|
|
814
|
+
* workspace, the candidate identity, and the projection from a diagnostic to an `Issue`.
|
|
815
|
+
*
|
|
816
|
+
* Each inspection opens the supplied text by URI, waits for the client's diagnostics, and closes the
|
|
817
|
+
* document without writing it to disk. The caller's own signal is what bounds that wait, so a server
|
|
818
|
+
* that admits a document and publishes nothing refuses the inspection when the caller's bound
|
|
819
|
+
* expires rather than holding it for the life of the process. This stage mints no bound of its own
|
|
820
|
+
* for the wait: a second one would race the caller's, and the answer would depend on scheduling.
|
|
823
821
|
*
|
|
824
822
|
* Teardown is bounded at both ends. Warming waits for the server's `initialize` response and the
|
|
825
|
-
* ending waits for its `shutdown` reply, and the protocol leaves both answers to the server, so
|
|
826
|
-
*
|
|
823
|
+
* ending waits for its `shutdown` reply, and the protocol leaves both answers to the server, so the
|
|
824
|
+
* client's deadline bounds each exchange and the transport's cooperative window takes the ending
|
|
825
|
+
* back with a signal when that window passes.
|
|
827
826
|
*
|
|
828
827
|
* The URI is the path the candidate declared, so the candidate receives exactly the rule set the
|
|
829
828
|
* workspace's own lint gate applies to that path, including an override anchored to one directory,
|
|
@@ -836,24 +835,20 @@ var peerDependencies = {
|
|
|
836
835
|
* @example
|
|
837
836
|
* ```ts
|
|
838
837
|
* const stage = new LintStage('/srv/checkout')
|
|
839
|
-
* const check = await stage.inspect(subject)
|
|
838
|
+
* const check = await stage.inspect(subject, { signal: AbortSignal.timeout(30_000) })
|
|
840
839
|
* await stage.destroy()
|
|
841
840
|
* ```
|
|
842
841
|
*/
|
|
843
842
|
var LintStage = class {
|
|
844
843
|
#workspace;
|
|
845
844
|
#deadline = 2e3;
|
|
845
|
+
#documents = /* @__PURE__ */ new Set();
|
|
846
846
|
#warmth;
|
|
847
|
-
#
|
|
848
|
-
#
|
|
849
|
-
#documents = /* @__PURE__ */ new Map();
|
|
850
|
-
#publishes = /* @__PURE__ */ new Map();
|
|
851
|
-
#refusals = /* @__PURE__ */ new Map();
|
|
852
|
-
#child;
|
|
853
|
-
#buffer = Buffer.alloc(0);
|
|
854
|
-
#sequence = 0;
|
|
847
|
+
#client;
|
|
848
|
+
#ending;
|
|
855
849
|
#closing;
|
|
856
850
|
#progress = 0;
|
|
851
|
+
#revision = 0;
|
|
857
852
|
#destroyed = false;
|
|
858
853
|
/**
|
|
859
854
|
* Starts warming the target workspace's Oxlint language server.
|
|
@@ -871,8 +866,8 @@ var LintStage = class {
|
|
|
871
866
|
get progress() {
|
|
872
867
|
return this.#progress;
|
|
873
868
|
}
|
|
874
|
-
inspect(subject) {
|
|
875
|
-
return guardStage(this.stage, this.#inspect(subject));
|
|
869
|
+
inspect(subject, options) {
|
|
870
|
+
return guardStage(this.stage, this.#inspect(subject, options));
|
|
876
871
|
}
|
|
877
872
|
destroy() {
|
|
878
873
|
if (this.#closing !== void 0) return this.#closing;
|
|
@@ -880,13 +875,18 @@ var LintStage = class {
|
|
|
880
875
|
this.#closing = guardStage(this.stage, this.#destroy());
|
|
881
876
|
return this.#closing;
|
|
882
877
|
}
|
|
883
|
-
async #inspect(subject) {
|
|
878
|
+
async #inspect(subject, options) {
|
|
884
879
|
if (this.#destroyed) throw createDestroyedError("lint stage");
|
|
880
|
+
if (options === void 0) throw new ProbeError("The lint stage inspects only under a bound its caller supplies", {
|
|
881
|
+
origin: "claimant",
|
|
882
|
+
code: "refused",
|
|
883
|
+
context: { stage: this.stage }
|
|
884
|
+
});
|
|
885
885
|
const started = performance.now();
|
|
886
|
-
await this.#
|
|
886
|
+
const client = await this.#warmed();
|
|
887
887
|
if (this.#destroyed) throw createDestroyedError("lint stage");
|
|
888
888
|
const issues = [];
|
|
889
|
-
for (const draft of [...subject.files, subject.test]) issues.push(...await this.#document(draft));
|
|
889
|
+
for (const draft of [...subject.files, subject.test]) issues.push(...await this.#document(client, draft, options.signal));
|
|
890
890
|
return {
|
|
891
891
|
stage: this.stage,
|
|
892
892
|
elapsed: Math.round(performance.now() - started),
|
|
@@ -894,118 +894,86 @@ var LintStage = class {
|
|
|
894
894
|
};
|
|
895
895
|
}
|
|
896
896
|
async #destroy() {
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
const
|
|
901
|
-
|
|
902
|
-
|
|
897
|
+
await this.#client?.destroy();
|
|
898
|
+
}
|
|
899
|
+
async #warm() {
|
|
900
|
+
const binary = resolveWorkspaceBinary(this.#workspace, "oxlint");
|
|
901
|
+
const client = createLSPClient({
|
|
902
|
+
transport: createStdioTransport({
|
|
903
|
+
server: {
|
|
904
|
+
command: [
|
|
905
|
+
process.execPath,
|
|
906
|
+
binary,
|
|
907
|
+
"--lsp"
|
|
908
|
+
],
|
|
909
|
+
directory: this.#workspace
|
|
910
|
+
},
|
|
911
|
+
grace: this.#deadline / 2
|
|
912
|
+
}),
|
|
913
|
+
workspace: pathToFileURL(this.#workspace).href,
|
|
914
|
+
timeout: this.#deadline
|
|
903
915
|
});
|
|
904
|
-
|
|
916
|
+
this.#client = client;
|
|
917
|
+
client.emitter.on("exit", (exit) => this.#retire(exit));
|
|
918
|
+
await client.start();
|
|
919
|
+
return client;
|
|
905
920
|
}
|
|
906
921
|
async #warmed() {
|
|
907
|
-
const timeout = createTimeout({ ms: this.#deadline });
|
|
908
|
-
timeout.start();
|
|
909
922
|
try {
|
|
910
|
-
return await
|
|
911
|
-
} catch {
|
|
912
|
-
|
|
913
|
-
} finally {
|
|
914
|
-
timeout.clear();
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
async #release(child, released) {
|
|
918
|
-
const timeout = createTimeout({ ms: this.#deadline });
|
|
919
|
-
timeout.start();
|
|
920
|
-
try {
|
|
921
|
-
await Promise.race([this.#retire(child).then(() => released), this.#expiry(timeout)]);
|
|
922
|
-
} catch {
|
|
923
|
-
child.kill("SIGKILL");
|
|
924
|
-
await released;
|
|
925
|
-
} finally {
|
|
926
|
-
timeout.clear();
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
async #retire(child) {
|
|
930
|
-
try {
|
|
931
|
-
await this.#request("shutdown", void 0);
|
|
932
|
-
this.#notify("exit", void 0);
|
|
933
|
-
} catch {
|
|
934
|
-
child.kill("SIGKILL");
|
|
923
|
+
return await this.#warmth;
|
|
924
|
+
} catch (error) {
|
|
925
|
+
throw this.#translate(error);
|
|
935
926
|
}
|
|
936
927
|
}
|
|
937
|
-
#
|
|
938
|
-
|
|
939
|
-
timeout.signal.addEventListener("abort", () => reject(new ProbeError(`The Oxlint language server did not exit within ${timeout.ms} ms`, {
|
|
940
|
-
origin: "instrument",
|
|
941
|
-
code: "deadline",
|
|
942
|
-
context: {
|
|
943
|
-
stage: this.stage,
|
|
944
|
-
deadline: timeout.ms
|
|
945
|
-
}
|
|
946
|
-
})), { once: true });
|
|
947
|
-
});
|
|
948
|
-
}
|
|
949
|
-
async #warm() {
|
|
950
|
-
const binary = resolveWorkspaceBinary(this.#workspace, "oxlint");
|
|
951
|
-
const child = spawn(process.execPath, [binary, "--lsp"], {
|
|
952
|
-
cwd: this.#workspace,
|
|
953
|
-
stdio: "pipe"
|
|
954
|
-
});
|
|
955
|
-
this.#child = child;
|
|
956
|
-
child.stderr.resume();
|
|
957
|
-
child.stdout.on("data", (chunk) => this.#read(chunk));
|
|
958
|
-
child.stdin.on("error", (error) => this.#fail(error));
|
|
959
|
-
child.on("error", (error) => this.#fail(error));
|
|
960
|
-
child.on("exit", (code, signal) => this.#exit(code, signal));
|
|
961
|
-
await this.#request("initialize", {
|
|
962
|
-
processId: process.pid,
|
|
963
|
-
rootUri: pathToFileURL(this.#workspace).href,
|
|
964
|
-
capabilities: {},
|
|
965
|
-
workspaceFolders: [{
|
|
966
|
-
uri: pathToFileURL(this.#workspace).href,
|
|
967
|
-
name: "workspace"
|
|
968
|
-
}]
|
|
969
|
-
});
|
|
970
|
-
this.#notify("initialized", {});
|
|
971
|
-
return child;
|
|
928
|
+
#retire(exit) {
|
|
929
|
+
this.#ending = exit.signal === null ? `code ${exit.code}` : `signal ${exit.signal}`;
|
|
972
930
|
}
|
|
973
|
-
#document(draft) {
|
|
931
|
+
async #document(client, draft, signal) {
|
|
974
932
|
const uri = pathToFileURL(resolveWorkspaceFile(this.#workspace, draft.path)).href;
|
|
975
|
-
if (this.#
|
|
933
|
+
if (this.#documents.has(uri)) throw new ProbeError(`The lint stage is already inspecting ${draft.path}`, {
|
|
976
934
|
origin: "claimant",
|
|
977
935
|
code: "refused",
|
|
978
936
|
context: {
|
|
979
937
|
stage: this.stage,
|
|
980
938
|
path: draft.path
|
|
981
939
|
}
|
|
982
|
-
})
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
this.#refusals.set(uri, reject);
|
|
987
|
-
}).finally(() => this.#close(uri));
|
|
940
|
+
});
|
|
941
|
+
this.#documents.add(uri);
|
|
942
|
+
this.#progress += 1;
|
|
943
|
+
this.#revision += 1;
|
|
988
944
|
try {
|
|
989
|
-
|
|
945
|
+
const diagnostics = await client.open({
|
|
990
946
|
uri,
|
|
991
947
|
languageId: inferDocumentLanguage(draft.path),
|
|
992
|
-
version: this.#
|
|
948
|
+
version: this.#revision,
|
|
993
949
|
text: draft.text
|
|
994
|
-
} });
|
|
995
|
-
this.#
|
|
950
|
+
}, { signal });
|
|
951
|
+
return this.#issues(normalizePath(draft.path), diagnostics);
|
|
996
952
|
} catch (error) {
|
|
997
|
-
|
|
953
|
+
if (signal.aborted) throw this.#abandoned(draft.path);
|
|
954
|
+
throw this.#translate(error, draft.path);
|
|
955
|
+
} finally {
|
|
956
|
+
this.#progress -= 1;
|
|
957
|
+
this.#documents.delete(uri);
|
|
958
|
+
await client.close(uri).catch(() => void 0);
|
|
998
959
|
}
|
|
999
|
-
return inspected;
|
|
1000
960
|
}
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
961
|
+
#abandoned(path) {
|
|
962
|
+
return new ProbeError("The lint stage inspection stopped at the bound its caller supplied", {
|
|
963
|
+
origin: "claimant",
|
|
964
|
+
code: "deadline",
|
|
965
|
+
context: {
|
|
966
|
+
stage: this.stage,
|
|
967
|
+
path
|
|
968
|
+
}
|
|
969
|
+
});
|
|
1006
970
|
}
|
|
1007
|
-
#
|
|
1008
|
-
|
|
971
|
+
#translate(error, path) {
|
|
972
|
+
if (this.#destroyed) return createDestroyedError("lint stage");
|
|
973
|
+
const ending = this.#ending;
|
|
974
|
+
if (ending !== void 0) return this.#fault(`The Oxlint language server exited with ${ending}`, error, path);
|
|
975
|
+
if (error instanceof Error) return error;
|
|
976
|
+
return this.#fault(describeUnknown(error), error, path);
|
|
1009
977
|
}
|
|
1010
978
|
#fault(message, cause, path) {
|
|
1011
979
|
return new ProbeError(message, {
|
|
@@ -1018,153 +986,22 @@ var LintStage = class {
|
|
|
1018
986
|
...cause === void 0 ? {} : { cause }
|
|
1019
987
|
});
|
|
1020
988
|
}
|
|
1021
|
-
|
|
1022
|
-
return
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
this.#responses.set(id, resolve);
|
|
1036
|
-
this.#failures.set(id, reject);
|
|
1037
|
-
});
|
|
1038
|
-
try {
|
|
1039
|
-
this.#send({
|
|
1040
|
-
jsonrpc: "2.0",
|
|
1041
|
-
id,
|
|
1042
|
-
method,
|
|
1043
|
-
params
|
|
1044
|
-
});
|
|
1045
|
-
} catch (error) {
|
|
1046
|
-
const reject = this.#failures.get(id);
|
|
1047
|
-
this.#responses.delete(id);
|
|
1048
|
-
this.#failures.delete(id);
|
|
1049
|
-
reject?.(this.#fault(describeUnknown(error), error));
|
|
1050
|
-
}
|
|
1051
|
-
return response;
|
|
1052
|
-
}
|
|
1053
|
-
#notify(method, params) {
|
|
1054
|
-
this.#sequence += 1;
|
|
1055
|
-
this.#send({
|
|
1056
|
-
jsonrpc: "2.0",
|
|
1057
|
-
method,
|
|
1058
|
-
params
|
|
1059
|
-
});
|
|
1060
|
-
}
|
|
1061
|
-
#send(message) {
|
|
1062
|
-
const child = this.#child;
|
|
1063
|
-
if (this.#ending !== void 0) throw this.#fault(`The Oxlint language server exited with ${this.#ending}`);
|
|
1064
|
-
if (child === void 0) throw this.#fault("The Oxlint language server is not running");
|
|
1065
|
-
if (!child.stdin.writable) throw this.#fault("The Oxlint language server closed its input");
|
|
1066
|
-
const content = JSON.stringify(message);
|
|
1067
|
-
const header = `Content-Length: ${Buffer.byteLength(content)}\r\n\r\n`;
|
|
1068
|
-
child.stdin.write(header + content);
|
|
1069
|
-
}
|
|
1070
|
-
#read(chunk) {
|
|
1071
|
-
this.#buffer = Buffer.concat([this.#buffer, chunk]);
|
|
1072
|
-
while (this.#frame());
|
|
1073
|
-
}
|
|
1074
|
-
#frame() {
|
|
1075
|
-
const boundary = this.#buffer.indexOf("\r\n\r\n");
|
|
1076
|
-
if (boundary < 0) return false;
|
|
1077
|
-
const length = parseContentLength(this.#buffer.subarray(0, boundary).toString("ascii"));
|
|
1078
|
-
if (length === void 0) {
|
|
1079
|
-
this.#fail(this.#fault("Oxlint sent an invalid JSON-RPC frame header"));
|
|
1080
|
-
return false;
|
|
1081
|
-
}
|
|
1082
|
-
const start = boundary + 4;
|
|
1083
|
-
const end = start + length;
|
|
1084
|
-
if (this.#buffer.length < end) return false;
|
|
1085
|
-
const content = this.#buffer.subarray(start, end).toString("utf8");
|
|
1086
|
-
this.#buffer = this.#buffer.subarray(end);
|
|
1087
|
-
try {
|
|
1088
|
-
const message = JSON.parse(content);
|
|
1089
|
-
this.#receive(message);
|
|
1090
|
-
} catch (error) {
|
|
1091
|
-
this.#fail(this.#fault(`Oxlint sent invalid JSON: ${describeUnknown(error)}`, error));
|
|
1092
|
-
}
|
|
1093
|
-
return true;
|
|
1094
|
-
}
|
|
1095
|
-
#receive(message) {
|
|
1096
|
-
if (typeof message !== "object" || message === null) return;
|
|
1097
|
-
if ("id" in message && typeof message.id === "number") {
|
|
1098
|
-
const id = message.id;
|
|
1099
|
-
const resolve = this.#responses.get(id);
|
|
1100
|
-
const reject = this.#failures.get(id);
|
|
1101
|
-
this.#responses.delete(id);
|
|
1102
|
-
this.#failures.delete(id);
|
|
1103
|
-
if ("error" in message && message.error !== void 0) reject?.(this.#fault(describeUnknown(message.error)));
|
|
1104
|
-
else resolve?.("result" in message ? message.result : void 0);
|
|
1105
|
-
return;
|
|
1106
|
-
}
|
|
1107
|
-
if (!("method" in message) || message.method !== "textDocument/publishDiagnostics") return;
|
|
1108
|
-
if (!("params" in message) || typeof message.params !== "object" || message.params === null) return;
|
|
1109
|
-
const params = message.params;
|
|
1110
|
-
if (!("uri" in params) || typeof params.uri !== "string") return;
|
|
1111
|
-
if (!("diagnostics" in params) || !Array.isArray(params.diagnostics)) return;
|
|
1112
|
-
const publish = this.#publishes.get(params.uri);
|
|
1113
|
-
if (publish === void 0) return;
|
|
1114
|
-
publish(this.#issues(params.uri, params.diagnostics));
|
|
1115
|
-
}
|
|
1116
|
-
#issues(uri, diagnostics) {
|
|
1117
|
-
const path = this.#documents.get(uri);
|
|
1118
|
-
if (path === void 0) return [];
|
|
1119
|
-
const issues = [];
|
|
1120
|
-
for (const diagnostic of diagnostics) {
|
|
1121
|
-
if (typeof diagnostic !== "object" || diagnostic === null) continue;
|
|
1122
|
-
if (!("message" in diagnostic) || typeof diagnostic.message !== "string") continue;
|
|
1123
|
-
if (!("range" in diagnostic) || typeof diagnostic.range !== "object" || diagnostic.range === null) {
|
|
1124
|
-
issues.push({
|
|
1125
|
-
origin: "claimant",
|
|
1126
|
-
path,
|
|
1127
|
-
message: diagnostic.message
|
|
1128
|
-
});
|
|
1129
|
-
continue;
|
|
1130
|
-
}
|
|
1131
|
-
const range = diagnostic.range;
|
|
1132
|
-
if (!("start" in range) || typeof range.start !== "object" || range.start === null) {
|
|
1133
|
-
issues.push({
|
|
1134
|
-
origin: "claimant",
|
|
1135
|
-
path,
|
|
1136
|
-
message: diagnostic.message
|
|
1137
|
-
});
|
|
1138
|
-
continue;
|
|
1139
|
-
}
|
|
1140
|
-
const start = range.start;
|
|
1141
|
-
if (!("line" in start) || typeof start.line !== "number") {
|
|
1142
|
-
issues.push({
|
|
1143
|
-
origin: "claimant",
|
|
1144
|
-
path,
|
|
1145
|
-
message: diagnostic.message
|
|
1146
|
-
});
|
|
1147
|
-
continue;
|
|
989
|
+
#issues(path, diagnostics) {
|
|
990
|
+
return diagnostics.map((diagnostic) => ({
|
|
991
|
+
origin: "claimant",
|
|
992
|
+
path,
|
|
993
|
+
message: diagnostic.message,
|
|
994
|
+
range: {
|
|
995
|
+
start: {
|
|
996
|
+
line: diagnostic.range.start.line,
|
|
997
|
+
character: diagnostic.range.start.character
|
|
998
|
+
},
|
|
999
|
+
end: {
|
|
1000
|
+
line: diagnostic.range.end.line,
|
|
1001
|
+
character: diagnostic.range.end.character
|
|
1002
|
+
}
|
|
1148
1003
|
}
|
|
1149
|
-
|
|
1150
|
-
origin: "claimant",
|
|
1151
|
-
path,
|
|
1152
|
-
message: diagnostic.message,
|
|
1153
|
-
line: start.line + 1
|
|
1154
|
-
});
|
|
1155
|
-
}
|
|
1156
|
-
return issues;
|
|
1157
|
-
}
|
|
1158
|
-
#fail(error) {
|
|
1159
|
-
for (const reject of this.#failures.values()) reject(error);
|
|
1160
|
-
for (const reject of this.#refusals.values()) reject(error);
|
|
1161
|
-
this.#responses.clear();
|
|
1162
|
-
this.#failures.clear();
|
|
1163
|
-
this.#publishes.clear();
|
|
1164
|
-
this.#refusals.clear();
|
|
1165
|
-
}
|
|
1166
|
-
#exit(code, signal) {
|
|
1167
|
-
this.#fail(this.#fault(`The Oxlint language server exited with ${this.#describe(code, signal)}`));
|
|
1004
|
+
}));
|
|
1168
1005
|
}
|
|
1169
1006
|
};
|
|
1170
1007
|
//#endregion
|
|
@@ -1795,11 +1632,19 @@ var RuntimeStage = class {
|
|
|
1795
1632
|
path,
|
|
1796
1633
|
message
|
|
1797
1634
|
};
|
|
1635
|
+
const character = "column" in stack && typeof stack.column === "number" ? stack.column - 1 : 0;
|
|
1636
|
+
const position = {
|
|
1637
|
+
line: stack.line - 1,
|
|
1638
|
+
character
|
|
1639
|
+
};
|
|
1798
1640
|
return {
|
|
1799
1641
|
origin: "claimant",
|
|
1800
1642
|
path,
|
|
1801
1643
|
message,
|
|
1802
|
-
|
|
1644
|
+
range: {
|
|
1645
|
+
start: position,
|
|
1646
|
+
end: position
|
|
1647
|
+
}
|
|
1803
1648
|
};
|
|
1804
1649
|
}
|
|
1805
1650
|
return {
|
|
@@ -2141,7 +1986,10 @@ var TypeStage = class {
|
|
|
2141
1986
|
origin: "claimant",
|
|
2142
1987
|
path,
|
|
2143
1988
|
message,
|
|
2144
|
-
|
|
1989
|
+
range: {
|
|
1990
|
+
start: diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start),
|
|
1991
|
+
end: diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start + (diagnostic.length ?? 0))
|
|
1992
|
+
}
|
|
2145
1993
|
};
|
|
2146
1994
|
}
|
|
2147
1995
|
};
|
|
@@ -2434,16 +2282,18 @@ var Probe = class {
|
|
|
2434
2282
|
const release = await this.#admitType();
|
|
2435
2283
|
try {
|
|
2436
2284
|
const stage = this.#type;
|
|
2437
|
-
return await this.#inspectStage(stage, stage.progress, stage.inspect(inspection.subject, inspection.claim.project), inspection.claim);
|
|
2285
|
+
return await this.#inspectStage(stage, stage.progress, () => stage.inspect(inspection.subject, inspection.claim.project), inspection.claim);
|
|
2438
2286
|
} finally {
|
|
2439
2287
|
release();
|
|
2440
2288
|
}
|
|
2441
2289
|
}
|
|
2442
2290
|
#inspectLint(inspection) {
|
|
2443
|
-
|
|
2291
|
+
const stage = this.#lint;
|
|
2292
|
+
return this.#inspectStage(stage, stage.progress, (signal) => stage.inspect(inspection.subject, { signal }), inspection.claim);
|
|
2444
2293
|
}
|
|
2445
2294
|
#inspectRuntime(inspection) {
|
|
2446
|
-
|
|
2295
|
+
const stage = this.#runtime;
|
|
2296
|
+
return this.#inspectStage(stage, stage.progress, () => stage.inspect(inspection.subject), inspection.claim);
|
|
2447
2297
|
}
|
|
2448
2298
|
async #inspectStage(stage, progress, operation, claim) {
|
|
2449
2299
|
try {
|
|
@@ -2456,12 +2306,14 @@ var Probe = class {
|
|
|
2456
2306
|
async #bound(operation, message, stage, progress) {
|
|
2457
2307
|
const timeout = createTimeout({ ms: this.#deadline });
|
|
2458
2308
|
timeout.start();
|
|
2309
|
+
const expiry = this.#expiry(timeout, message, stage, progress);
|
|
2310
|
+
const refusal = expiry.catch((error) => error);
|
|
2459
2311
|
try {
|
|
2460
|
-
return await Promise.race([operation
|
|
2312
|
+
return await Promise.race([operation(timeout.signal), expiry]);
|
|
2461
2313
|
} catch (error) {
|
|
2462
2314
|
if (!timeout.expired) throw error;
|
|
2463
2315
|
await this.#recycle(stage);
|
|
2464
|
-
throw
|
|
2316
|
+
throw await refusal;
|
|
2465
2317
|
} finally {
|
|
2466
2318
|
timeout.clear();
|
|
2467
2319
|
}
|
|
@@ -2502,7 +2354,7 @@ var Probe = class {
|
|
|
2502
2354
|
try {
|
|
2503
2355
|
const stage = this.#type;
|
|
2504
2356
|
try {
|
|
2505
|
-
return await this.#bound(stage.resolve(claim.project), `The type stage project resolution exceeded ${this.#deadline} ms`, stage, stage.progress);
|
|
2357
|
+
return await this.#bound(() => stage.resolve(claim.project), `The type stage project resolution exceeded ${this.#deadline} ms`, stage, stage.progress);
|
|
2506
2358
|
} catch (error) {
|
|
2507
2359
|
this.#emitExpiry(stage, claim);
|
|
2508
2360
|
throw error;
|
|
@@ -2543,7 +2395,7 @@ var Probe = class {
|
|
|
2543
2395
|
}
|
|
2544
2396
|
async #destroyStage(stage) {
|
|
2545
2397
|
try {
|
|
2546
|
-
await this.#bound(stage.destroy(), `The ${stage.stage} stage teardown exceeded ${this.#deadline} ms`, stage, stage.progress);
|
|
2398
|
+
await this.#bound(() => stage.destroy(), `The ${stage.stage} stage teardown exceeded ${this.#deadline} ms`, stage, stage.progress);
|
|
2547
2399
|
} catch (error) {
|
|
2548
2400
|
if (!(error instanceof ProbeError) || !this.#deadlines.has(error)) throw error;
|
|
2549
2401
|
}
|
|
@@ -2731,6 +2583,6 @@ var ProbeServer = class {
|
|
|
2731
2583
|
}
|
|
2732
2584
|
};
|
|
2733
2585
|
//#endregion
|
|
2734
|
-
export { LintStage, Overlay, Probe, ProbeServer, RuntimeStage, TypeStage, captureListeners, computeDigest, createRevisionFile, describeUnknown, findRefusedPaths, guardStage, inferDocumentLanguage, inferTestProject, inferTypeProject, isRefusedName, loadWorkspaceModule, matchesWorkspaceModule, normalizePath, normalizeValue, overwriteFile,
|
|
2586
|
+
export { LintStage, Overlay, Probe, ProbeServer, RuntimeStage, TypeStage, captureListeners, computeDigest, createRevisionFile, describeUnknown, findRefusedPaths, guardStage, inferDocumentLanguage, inferTestProject, inferTypeProject, isRefusedName, loadWorkspaceModule, matchesWorkspaceModule, normalizePath, normalizeValue, overwriteFile, readWorkspaceManifest, relativeWorkspaceFile, relativeWorkspaceMessage, releaseListeners, resolveWorkspaceBinary, resolveWorkspaceFile, resolveWorkspaceModule };
|
|
2735
2587
|
|
|
2736
2588
|
//# sourceMappingURL=index.js.map
|