History

Fix keybindings parse error wrapping behavior

Julius Marminge committed 8 months ago

Commit e52db0b1 parent 71d8f742 files · +38 −5Browse files

Unified · Split

2 files
  1. apps/server/src/keybindings.test.ts +25 −0
  2. apps/server/src/keybindings.ts +13 −5
apps/server/src/keybindings.test.ts+25−0
@@ -171,6 +171,31 @@ describe("server keybindings", () => { · 170 unmodified lines
171 expect(fs.readFileSync(configPath, "utf8")).toBe("{ not-json");171 expect(fs.readFileSync(configPath, "utf8")).toBe("{ not-json");
172 });172 });
173 173
174 it("reports non-array config parse errors without duplicate prefix", () => {
175 const fakeHome = makeTempDir("t3code-keybindings-non-array-");
176 const configDir = path.join(fakeHome, ".t3");
177 fs.mkdirSync(configDir, { recursive: true });
178 const configPath = path.join(configDir, "keybindings.json");
179 fs.writeFileSync(configPath, JSON.stringify({ key: "mod+j", command: "terminal.toggle" }), "utf8");
180 vi.spyOn(os, "homedir").mockReturnValue(fakeHome);
181
182 expect(() =>
183 upsertKeybindingRule(logger, {
184 key: "mod+shift+r",
185 command: "script.run-tests.run",
186 }),
187 ).toThrow(new RegExp(`Unable to parse keybindings config at ${configPath}: expected JSON array`));
188
189 expect(() =>
190 upsertKeybindingRule(logger, {
191 key: "mod+shift+r",
192 command: "script.run-tests.run",
193 }),
194 ).not.toThrow(
195 new RegExp(`Unable to parse keybindings config at ${configPath}: Unable to parse keybindings config at`),
196 );
197 });
198
174 it("cleans up temp files when atomic keybinding write fails", () => {199 it("cleans up temp files when atomic keybinding write fails", () => {
175 const fakeHome = makeTempDir("t3code-keybindings-atomic-");200 const fakeHome = makeTempDir("t3code-keybindings-atomic-");
176 const configDir = path.join(fakeHome, ".t3");201 const configDir = path.join(fakeHome, ".t3");
apps/server/src/keybindings.ts+13−5
@@ -292,6 +292,12 @@ const DEFAULT_RESOLVED_KEYBINDINGS = compileDefaultKeybindings(); · 291 unmodified lines
292const KEYBINDINGS_CONFIG_PATH = path.join(".t3", "keybindings.json");292const KEYBINDINGS_CONFIG_PATH = path.join(".t3", "keybindings.json");
293const MAX_KEYBINDINGS = 256;293const MAX_KEYBINDINGS = 256;
294 294
295class KeybindingsConfigParseError extends Error {
296 constructor(configPath: string, detail: string, options?: { cause?: unknown }) {
297 super(`Unable to parse keybindings config at ${configPath}: ${detail}`, options);
298 }
299}
300
295function resolveKeybindingsConfigPath(): string {301function resolveKeybindingsConfigPath(): string {
296 return path.join(os.homedir(), KEYBINDINGS_CONFIG_PATH);302 return path.join(os.homedir(), KEYBINDINGS_CONFIG_PATH);
297}303}
@@ -308,7 +314,7 @@ function loadCustomKeybindingsConfig( · 10 unmodified lines
308 const parsed = JSON.parse(raw) as unknown;314 const parsed = JSON.parse(raw) as unknown;
309 if (!Array.isArray(parsed)) {315 if (!Array.isArray(parsed)) {
310 if (options?.throwOnUnreadableConfig) {316 if (options?.throwOnUnreadableConfig) {
311 throw new Error(`Unable to parse keybindings config at ${configPath}: expected JSON array`);317 throw new KeybindingsConfigParseError(configPath, "expected JSON array");
312 }318 }
313 logger.warn("ignoring keybindings config with unsupported format; expected array", {319 logger.warn("ignoring keybindings config with unsupported format; expected array", {
314 path: configPath,320 path: configPath,
@@ -343,10 +349,12 @@ function loadCustomKeybindingsConfig( · 28 unmodified lines
343 return [];349 return [];
344 }350 }
345 if (options?.throwOnUnreadableConfig) {351 if (options?.throwOnUnreadableConfig) {
346 throw new Error(352 if (error instanceof KeybindingsConfigParseError) {
347 `Unable to parse keybindings config at ${configPath}: ${353 throw error;
348 error instanceof Error ? error.message : String(error)354 }
349 }`,355 throw new KeybindingsConfigParseError(
356 configPath,
357 error instanceof Error ? error.message : String(error),
350 { cause: error },358 { cause: error },
351 );359 );
352 }360 }