Skip to content

Commit 15aa936

Browse files
edmundhungpenalosa
andauthored
fix(wrangler): keypress event name is optional (#7345)
* fix(wrangler): keypress event name is optional * Create poor-chefs-kneel.md * add additional tests --------- Co-authored-by: Somhairle MacLeòid <[email protected]>
1 parent d4626f1 commit 15aa936

File tree

4 files changed

+78
-29
lines changed

4 files changed

+78
-29
lines changed

.changeset/poor-chefs-kneel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"wrangler": patch
3+
---
4+
5+
fix(wrangler): keypress event name is optional

packages/wrangler/src/__tests__/cli-hotkeys.test.ts

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,21 @@ import registerHotKeys from "../cli-hotkeys";
44
import { logger } from "../logger";
55
import { mockConsoleMethods } from "./helpers/mock-console";
66
import { useMockIsTTY } from "./helpers/mock-istty";
7-
import type { KeypressEvent } from "../utils/onKeyPress";
8-
9-
const writeToMockedStdin = (input: string) =>
10-
_internalKeyPressCallback({
11-
name: input,
12-
sequence: input,
13-
ctrl: false,
14-
meta: false,
15-
shift: false,
16-
});
17-
let _internalKeyPressCallback: (input: KeypressEvent) => void;
7+
import type { Key } from "node:readline";
8+
9+
const writeToMockedStdin = (input: string | Key) =>
10+
_internalKeyPressCallback(
11+
typeof input === "string"
12+
? {
13+
name: input,
14+
sequence: input,
15+
ctrl: false,
16+
meta: false,
17+
shift: false,
18+
}
19+
: input
20+
);
21+
let _internalKeyPressCallback: (input: Key) => void;
1822
vitest.mock("../utils/onKeyPress", async () => {
1923
return {
2024
onKeyPress(callback: () => void) {
@@ -81,6 +85,48 @@ describe("Hot Keys", () => {
8185
handlerA.mockClear();
8286
});
8387

88+
it("handles meta keys", async () => {
89+
const handlerCtrl = vi.fn();
90+
const handlerMeta = vi.fn();
91+
const handlerShift = vi.fn();
92+
const options = [
93+
{ keys: ["ctrl+a"], label: "ctrl option", handler: handlerCtrl },
94+
{ keys: ["meta+a"], label: "meta option", handler: handlerMeta },
95+
{ keys: ["shift+a"], label: "shift option", handler: handlerShift },
96+
];
97+
98+
registerHotKeys(options);
99+
100+
writeToMockedStdin("a");
101+
expect(handlerCtrl).not.toHaveBeenCalled();
102+
103+
writeToMockedStdin("ctrl+a");
104+
expect(handlerCtrl).toHaveBeenCalled();
105+
handlerCtrl.mockClear();
106+
107+
writeToMockedStdin("meta+a");
108+
expect(handlerMeta).toHaveBeenCalled();
109+
handlerMeta.mockClear();
110+
111+
writeToMockedStdin("shift+a");
112+
expect(handlerShift).toHaveBeenCalled();
113+
handlerShift.mockClear();
114+
});
115+
116+
it("ignores missing key names", async () => {
117+
const handlerA = vi.fn();
118+
const options = [
119+
{ keys: ["a"], label: "first option", handler: handlerA },
120+
];
121+
122+
registerHotKeys(options);
123+
124+
writeToMockedStdin({
125+
shift: false,
126+
});
127+
expect(handlerA).not.toHaveBeenCalled();
128+
});
129+
84130
it("ignores unbound keys", async () => {
85131
const handlerA = vi.fn();
86132
const handlerD = vi.fn();

packages/wrangler/src/cli-hotkeys.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,22 @@ export default function (
6262
}
6363

6464
const unregisterKeyPress = onKeyPress(async (key) => {
65-
let char = key.name.toLowerCase();
65+
const entries: string[] = [];
6666

67-
if (key?.meta) {
68-
char = "meta+" + char;
67+
if (key.name) {
68+
entries.push(key.name.toLowerCase());
6969
}
70-
if (key?.ctrl) {
71-
char = "ctrl+" + char;
70+
if (key.meta) {
71+
entries.unshift("meta");
7272
}
73-
if (key?.shift) {
74-
char = "shift+" + char;
73+
if (key.ctrl) {
74+
entries.unshift("ctrl");
7575
}
76+
if (key.shift) {
77+
entries.unshift("shift");
78+
}
79+
80+
const char = entries.join("+");
7681

7782
for (const { keys, handler, disabled } of options) {
7883
if (unwrapHook(disabled)) {

packages/wrangler/src/utils/onKeyPress.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
1-
import readline from "readline";
1+
import readline from "node:readline";
22
import { PassThrough } from "stream";
33
import isInteractive from "../is-interactive";
4+
import type { Key } from "node:readline";
45

5-
export type KeypressEvent = {
6-
name: string;
7-
sequence: string;
8-
ctrl: boolean;
9-
meta: boolean;
10-
shift: boolean;
11-
};
12-
13-
export function onKeyPress(callback: (key: KeypressEvent) => void) {
6+
export function onKeyPress(callback: (key: Key) => void) {
147
// Listening for events on process.stdin (eg .on('keypress')) causes it to go into 'old mode'
158
// which keeps this nodejs process alive even after calling .off('keypress')
169
// WORKAROUND: piping stdin via a transform stream allows us to call stream.destroy()
@@ -24,7 +17,7 @@ export function onKeyPress(callback: (key: KeypressEvent) => void) {
2417
process.stdin.setRawMode(true);
2518
}
2619

27-
const handler = async (_char: string, key: KeypressEvent) => {
20+
const handler = async (_char: string, key: Key) => {
2821
if (key) {
2922
callback(key);
3023
}

0 commit comments

Comments
 (0)