summaryrefslogtreecommitdiffhomepage
path: root/js/src
diff options
context:
space:
mode:
authorDax Raad <[email protected]>2025-05-26 14:52:38 -0400
committerDax Raad <[email protected]>2025-05-26 14:52:38 -0400
commitb87ba57819a3dfa458b34c9cec9362c7028adf6e (patch)
treee12932e8dd7ac54c92ca337b9c975d7b4b143561 /js/src
parent802389a90eaa9a173a98305003b9e58b95584cd1 (diff)
downloadopencode-b87ba57819a3dfa458b34c9cec9362c7028adf6e.tar.gz
opencode-b87ba57819a3dfa458b34c9cec9362c7028adf6e.zip
shutdown
Diffstat (limited to 'js/src')
-rw-r--r--js/src/app/index.ts28
-rw-r--r--js/src/id/id.ts17
-rw-r--r--js/src/lsp/client.ts5
-rw-r--r--js/src/lsp/index.ts36
-rw-r--r--js/src/lsp/language.ts2
5 files changed, 63 insertions, 25 deletions
diff --git a/js/src/app/index.ts b/js/src/app/index.ts
index 363c398d8..f0d371a34 100644
--- a/js/src/app/index.ts
+++ b/js/src/app/index.ts
@@ -22,7 +22,13 @@ export namespace App {
log.info("created", { path: dataDir });
- const services = new Map<any, any>();
+ const services = new Map<
+ any,
+ {
+ state: any;
+ shutdown?: (input: any) => Promise<void>;
+ }
+ >();
const result = {
get services() {
@@ -39,15 +45,22 @@ export namespace App {
return result;
}
- export function state<T extends (app: Info) => any>(key: any, init: T) {
+ export function state<State>(
+ key: any,
+ init: (app: Info) => State,
+ shutdown?: (state: Awaited<State>) => Promise<void>,
+ ) {
return () => {
const app = ctx.use();
const services = app.services;
if (!services.has(key)) {
log.info("registering service", { name: key });
- services.set(key, init(app));
+ services.set(key, {
+ state: init(app),
+ shutdown: shutdown,
+ });
}
- return services.get(key) as ReturnType<T>;
+ return services.get(key)?.state as State;
};
}
@@ -62,7 +75,12 @@ export namespace App {
const app = await create(input);
return ctx.provide(app, async () => {
- return cb(app);
+ const result = await cb(app);
+ for (const [key, entry] of app.services.entries()) {
+ log.info("shutdown", { name: key });
+ await entry.shutdown?.(await entry.state);
+ }
+ return result;
});
}
}
diff --git a/js/src/id/id.ts b/js/src/id/id.ts
index 0cb1afe9d..62c6a12bf 100644
--- a/js/src/id/id.ts
+++ b/js/src/id/id.ts
@@ -30,11 +30,20 @@ export namespace Identifier {
descending: boolean,
given?: string,
): string {
- if (given) {
- if (given.startsWith(prefixes[prefix])) return given;
+ if (!given) {
+ return generateNewID(prefix, descending);
+ }
+
+ if (!given.startsWith(prefixes[prefix])) {
throw new Error(`ID ${given} does not start with ${prefixes[prefix]}`);
}
+ return given;
+ }
+ function generateNewID(
+ prefix: keyof typeof prefixes,
+ descending: boolean,
+ ): string {
const currentTimestamp = Date.now();
if (currentTimestamp !== lastTimestamp) {
@@ -45,9 +54,7 @@ export namespace Identifier {
let now = BigInt(currentTimestamp) * BigInt(0x1000) + BigInt(counter);
- if (descending) {
- now = ~now;
- }
+ now = descending ? ~now : now;
const timeBytes = Buffer.alloc(6);
for (let i = 0; i < 6; i++) {
diff --git a/js/src/lsp/client.ts b/js/src/lsp/client.ts
index f07b21c7f..0c9f9d06c 100644
--- a/js/src/lsp/client.ts
+++ b/js/src/lsp/client.ts
@@ -178,6 +178,11 @@ export namespace LSPClient {
}),
]);
},
+ async shutdown() {
+ log.info("shutting down");
+ connection.end();
+ connection.dispose();
+ },
};
return result;
diff --git a/js/src/lsp/index.ts b/js/src/lsp/index.ts
index f20a15e70..80503fb1f 100644
--- a/js/src/lsp/index.ts
+++ b/js/src/lsp/index.ts
@@ -5,22 +5,30 @@ import { LSPClient } from "./client";
export namespace LSP {
const log = Log.create({ service: "lsp" });
- const state = App.state("lsp", async () => {
- const clients = new Map<string, LSPClient.Info>();
+ const state = App.state(
+ "lsp",
+ async () => {
+ const clients = new Map<string, LSPClient.Info>();
- // QUESTION: how lazy should lsp auto discovery be? should it not initialize until a file is opened?
- clients.set(
- "typescript",
- await LSPClient.create({
- cmd: ["bun", "x", "typescript-language-server", "--stdio"],
- }),
- );
+ // QUESTION: how lazy should lsp auto discovery be? should it not initialize until a file is opened?
+ clients.set(
+ "typescript",
+ await LSPClient.create({
+ cmd: ["bun", "x", "typescript-language-server", "--stdio"],
+ }),
+ );
- return {
- clients,
- diagnostics: new Map<string, any>(),
- };
- });
+ return {
+ clients,
+ diagnostics: new Map<string, any>(),
+ };
+ },
+ async (state) => {
+ for (const client of state.clients.values()) {
+ await client.shutdown();
+ }
+ },
+ );
export async function run<T>(
input: (client: LSPClient.Info) => Promise<T>,
diff --git a/js/src/lsp/language.ts b/js/src/lsp/language.ts
index 964ebc803..14b32edfa 100644
--- a/js/src/lsp/language.ts
+++ b/js/src/lsp/language.ts
@@ -1,4 +1,4 @@
-export const LANGUAGE_EXTENSIONS = {
+export const LANGUAGE_EXTENSIONS: Record<string, string> = {
".abap": "abap",
".bat": "bat",
".bib": "bibtex",