Skip to content

Commit 1ea9c44

Browse files
committed
🐛 Fix lambda.unregister incorrectly removing non-lambda methods
Previously, lambda.unregister could unintentionally delete non-lambda methods of the dispatcher. This commit ensures that only methods with IDs beginning with "lambda:" are unregistered, and that passing a non-lambda method ID will do nothing and return false. Additional tests have been added to verify this behavior.
1 parent 5f8e7f4 commit 1ea9c44

File tree

2 files changed

+35
-3
lines changed

2 files changed

+35
-3
lines changed

lambda/mod.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export function unregister(
143143
denops: Denops,
144144
id: Identifier,
145145
): boolean {
146-
if (id in denops.dispatcher) {
146+
if (isRegisteredFnId(id) && id in denops.dispatcher) {
147147
delete denops.dispatcher[id];
148148
return true;
149149
}
@@ -293,3 +293,7 @@ const isFnWrapperArgs = isTupleOf([
293293
isLiteralOneOf(["notify", "request"] as const),
294294
isArray,
295295
]) satisfies Predicate<FnWrapperArgs>;
296+
297+
function isRegisteredFnId(id: unknown): id is Identifier {
298+
return typeof id === "string" && id.startsWith("lambda:");
299+
}

lambda/mod_test.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ test({
150150
await t.step("does not unregister lambda functions", async () => {
151151
const fn = spy(returnsNext(["foo"]));
152152
const id = lambda.register(denops, fn);
153-
lambda.unregister(denops, "not-registered-id");
153+
lambda.unregister(denops, "lambda:not-registered-id");
154154

155155
assertSpyCalls(fn, 0);
156156
assertEquals(
@@ -161,7 +161,35 @@ test({
161161
assertSpyCalls(fn, 1);
162162
});
163163
await t.step("returns `false`", () => {
164-
assertEquals(lambda.unregister(denops, "not-registered-id"), false);
164+
assertEquals(
165+
lambda.unregister(denops, "lambda:not-registered-id"),
166+
false,
167+
);
168+
});
169+
});
170+
await t.step("if 'id' is not a lambda identifier", async (t) => {
171+
await t.step("does not unregister method", async () => {
172+
const fn = spy(returnsNext(["foo"]));
173+
const notLambdaId = "not-lambda-id";
174+
denops.dispatcher = {
175+
[notLambdaId]: fn,
176+
};
177+
lambda.unregister(denops, notLambdaId);
178+
179+
assertSpyCalls(fn, 0);
180+
assertEquals(
181+
await denops.dispatch(denops.name, notLambdaId),
182+
"foo",
183+
"The method is available",
184+
);
185+
assertSpyCalls(fn, 1);
186+
});
187+
await t.step("returns `false`", () => {
188+
const notLambdaId = "not-lambda-id";
189+
denops.dispatcher = {
190+
[notLambdaId]: () => "foo",
191+
};
192+
assertEquals(lambda.unregister(denops, notLambdaId), false);
165193
});
166194
});
167195
});

0 commit comments

Comments
 (0)