diff --git a/packages/lib/src/command.ts b/packages/lib/src/command.ts index 2a55c22e..9b375175 100644 --- a/packages/lib/src/command.ts +++ b/packages/lib/src/command.ts @@ -146,6 +146,22 @@ export class CommandTree { } +/** + * Resolve a string with either an id or a name to the id of an entry + * + * An integer like string is treated as an id if an entry with that id + * exists, otherwise it is looked up as a name. + */ +function resolveId(entries: { id: number, name: string }[], idOrName: string) { + if (/^-?\d+$/.test(idOrName)) { + const id = parseInt(idOrName, 10); + if (entries.some(entry => entry.id === id)) { + return id; + } + } + return entries.find(entry => entry.name === idOrName)?.id; +} + /** * Resolve a string into a host ID * @@ -157,23 +173,11 @@ export class CommandTree { * @returns host ID. */ export async function resolveHost(client: Link, hostName: string) { - let hostId: number | undefined; - if (/^-?\d+$/.test(hostName)) { - hostId = parseInt(hostName, 10); - } else { - let hosts = await client.sendTo("controller", new libData.HostListRequest()); - for (let host of hosts) { - if (host.name === hostName) { - hostId = host.id; - break; - } - } - - if (hostId === undefined) { - throw new libErrors.CommandError(`No host named ${hostName}`); - } + const hosts = await client.sendTo("controller", new libData.HostListRequest()); + const hostId = resolveId(hosts, hostName); + if (hostId === undefined) { + throw new libErrors.CommandError(`No host named ${hostName}`); } - return hostId; } @@ -188,23 +192,11 @@ export async function resolveHost(client: Link, hostName: string) { * @returns instance ID. */ export async function resolveInstance(client: Link, instanceName: string) { - let instanceId: number | undefined; - if (/^-?\d+$/.test(instanceName)) { - instanceId = parseInt(instanceName, 10); - } else { - let instances = await client.sendTo("controller", new libData.InstanceDetailsListRequest()); - for (let instance of instances) { - if (instance.name === instanceName) { - instanceId = instance.id; - break; - } - } - - if (instanceId === undefined) { - throw new libErrors.CommandError(`No instance named ${instanceName}`); - } + const instances = await client.sendTo("controller", new libData.InstanceDetailsListRequest()); + const instanceId = resolveId(instances, instanceName); + if (instanceId === undefined) { + throw new libErrors.CommandError(`No instance named ${instanceName}`); } - return instanceId; } @@ -220,23 +212,11 @@ export async function resolveInstance(client: Link, instanceName: string) { * @returns mod pack ID. */ export async function resolveModPack(client: Link, modPackName: string) { - let modPackId: number | undefined; - if (/^-?\d+/.test(modPackName)) { - modPackId = parseInt(modPackName, 10); - } else { - let modPacks = await client.sendTo("controller", new libData.ModPackListRequest()); - for (let modPack of modPacks) { - if (modPack.name === modPackName) { - modPackId = modPack.id; - break; - } - } - - if (modPackId === undefined) { - throw new libErrors.CommandError(`No mod pack named ${modPackName}`); - } + const modPacks = await client.sendTo("controller", new libData.ModPackListRequest()); + const modPackId = resolveId(modPacks, modPackName); + if (modPackId === undefined) { + throw new libErrors.CommandError(`No mod pack named ${modPackName}`); } - return modPackId; } @@ -251,27 +231,9 @@ export async function resolveModPack(client: Link, modPackName: string) { * @returns Role info. */ export async function retrieveRole(client: Link, roleName: string) { - let roles = await client.sendTo("controller", new libData.RoleListRequest()); - - let resolvedRole: libData.Role | undefined; - if (/^-?\d+$/.test(roleName)) { - let roleId = parseInt(roleName, 10); - for (let role of roles) { - if (role.id === roleId) { - resolvedRole = role; - break; - } - } - - } else { - for (let role of roles) { - if (role.name === roleName) { - resolvedRole = role; - break; - } - } - } - + const roles = await client.sendTo("controller", new libData.RoleListRequest()); + const roleId = resolveId(roles, roleName); + const resolvedRole = roles.find(role => role.id === roleId); if (!resolvedRole) { throw new libErrors.CommandError(`No role named ${roleName}`); } diff --git a/test/lib/command.js b/test/lib/command.js index 86e299c6..40c658e0 100644 --- a/test/lib/command.js +++ b/test/lib/command.js @@ -16,39 +16,68 @@ describe("lib/command", function() { let testControl = new mock.MockControl(controlConnector); let testController = new lib.Link(controllerConnector); testController.handle( - lib.HostListRequest, () => [new lib.HostDetails("0.1", "Test Host", 11, false)] + lib.HostListRequest, () => [ + new lib.HostDetails("0.1", "Test Host", 11, false), + new lib.HostDetails("0.1", "22", 12, false), + new lib.HostDetails("0.1", "12", 13, false), + ] ); testController.handle( - lib.InstanceDetailsListRequest, () => [new lib.InstanceDetails("Test Instance", 57, 4, undefined, "stopped")] + lib.InstanceDetailsListRequest, () => [ + new lib.InstanceDetails("Test Instance", 57, 4, undefined, "stopped"), + new lib.InstanceDetails("10", 58, 4, undefined, "stopped"), + new lib.InstanceDetails("58", 59, 4, undefined, "stopped"), + ] ); - testController.handle(lib.RoleListRequest, () => [testRole.toJSON()]); + let numericRole = lib.Role.fromJSON({ id: 29, name: "77", description: "Test", permissions: [] }); + testController.handle(lib.RoleListRequest, () => [testRole.toJSON(), numericRole.toJSON()]); describe("resolveHost", function() { - it("should pass an integer like string back", async function() { - assert.equal(await lib.resolveHost(null, "123"), 123); + it("should resolve an integer like string as an id", async function() { + assert.equal(await lib.resolveHost(testControl, "11"), 11); }); it("should resolve a host name with the controller", async function() { assert.equal(await lib.resolveHost(testControl, "Test Host"), 11); }); + it("should resolve an integer like name if no host has that id", async function() { + assert.equal(await lib.resolveHost(testControl, "22"), 12); + }); + it("should prefer the id over an integer like name", async function() { + assert.equal(await lib.resolveHost(testControl, "12"), 12); + }); it("should throw if host is not found", async function() { await assert.rejects( lib.resolveHost(testControl, "invalid"), new lib.CommandError("No host named invalid") ); + await assert.rejects( + lib.resolveHost(testControl, "123"), + new lib.CommandError("No host named 123") + ); }); }); describe("resolveInstance", function() { - it("should pass an integer like string back", async function() { - assert.equal(await lib.resolveInstance(null, "123"), 123); + it("should resolve an integer like string as an id", async function() { + assert.equal(await lib.resolveInstance(testControl, "57"), 57); }); it("should resolve an instance name with the controller", async function() { assert.equal(await lib.resolveInstance(testControl, "Test Instance"), 57); }); + it("should resolve an integer like name if no instance has that id", async function() { + assert.equal(await lib.resolveInstance(testControl, "10"), 58); + }); + it("should prefer the id over an integer like name", async function() { + assert.equal(await lib.resolveInstance(testControl, "58"), 58); + }); it("should throw if instance is not found", async function() { await assert.rejects( lib.resolveInstance(testControl, "invalid"), new lib.CommandError("No instance named invalid") ); + await assert.rejects( + lib.resolveInstance(testControl, "123"), + new lib.CommandError("No instance named 123") + ); }); }); describe("retrieveRole", function() { @@ -58,6 +87,10 @@ describe("lib/command", function() { it("should retrieve a role by name from a string", async function() { assert.deepEqual(await lib.retrieveRole(testControl, "Test Role"), testRole); }); + it("should retrieve a role by an integer like name if no role has that id", async function() { + assert.deepEqual(await lib.retrieveRole(testControl, "28"), testRole); + assert.deepEqual(await lib.retrieveRole(testControl, "77"), numericRole); + }); it("should throw if role is not found", async function() { await assert.rejects( lib.retrieveRole(testControl, "invalid"),