diff --git a/packages/client/lib/commands/COMMAND_DOCS.spec.ts b/packages/client/lib/commands/COMMAND_DOCS.spec.ts index 75688452d4..5ed481ecd1 100644 --- a/packages/client/lib/commands/COMMAND_DOCS.spec.ts +++ b/packages/client/lib/commands/COMMAND_DOCS.spec.ts @@ -4,7 +4,7 @@ import { transformArguments } from './COMMAND_DOCS'; describe('COMMAND DOCS', () => { testUtils.isVersionGreaterThanHook([7, 0]); - + it('transformArguments', () => { assert.deepEqual( transformArguments('SORT'), @@ -13,18 +13,35 @@ describe('COMMAND DOCS', () => { }); testUtils.testWithClient('client.commandDocs', async client => { - assert.deepEqual( - await client.commandDocs('sort'), - [[ - 'sort', - { - summary: 'Sort the elements in a list, set or sorted set', - since: '1.0.0', - group: 'generic', - complexity: 'O(N+M*log(M)) where N is the number of elements in the list or set to sort, and M the number of returned elements. When the elements are not sorted, complexity is O(N).', - history: null + const docs = await client.commandDocs() + assert.equal(typeof docs, 'object'); + + for (const item of Object.values(docs)) { + if (item.summary) assert.equal(typeof item.summary, 'string'); + if (item.since) assert.equal(typeof item.since, 'string'); + if (item.group) assert.equal(typeof item.group, 'string'); + if (item.complexity) assert.equal(typeof item.complexity, 'string'); + if (item.history) assert.ok(Array.isArray(item.history)); + if (item.arguments) { + assert.equal(typeof item.arguments, 'object'); + for (const argument of Object.values(item.arguments)) { + if (argument.keySpecIndex) assert.equal(typeof argument.keySpecIndex, 'number'); + if (argument.type) assert.equal(typeof argument.type, 'string'); + if (argument.token) assert.equal(typeof argument.token, 'string'); + if (argument.summary) assert.equal(typeof argument.summary, 'string'); + if (argument.flags) assert.ok(Array.isArray(argument.flags)); } - ]] - ); + } + if (item.subCommands) assert.equal(typeof item.subCommands, 'object'); + } + + // check with commands names + const specifiedDocs = await client.commandDocs('sort', 'get', 'cluster') + assert.equal(typeof specifiedDocs, 'object'); + + // check with non existing command + const nonExistingCommandDocs = await client.commandDocs('foo') + assert.equal(typeof specifiedDocs, 'object'); + }, GLOBAL.SERVERS.OPEN); }); diff --git a/packages/client/lib/commands/COMMAND_DOCS.ts b/packages/client/lib/commands/COMMAND_DOCS.ts index 2444cdc062..175a3e79e9 100644 --- a/packages/client/lib/commands/COMMAND_DOCS.ts +++ b/packages/client/lib/commands/COMMAND_DOCS.ts @@ -3,36 +3,126 @@ import { pushVerdictArguments } from './generic-transformers'; export const IS_READ_ONLY = true; -export function transformArguments(keys: string | Array): RedisCommandArguments { - return pushVerdictArguments(['COMMAND', 'DOCS'], keys); -} +export function transformArguments(...commandNames: Array): RedisCommandArguments { + const args = ['COMMAND', 'DOCS']; -type CommandDocumentation = { - summary: string; - since: string; - group: string; - complexity: string; - history?: Array<[version: string, feature: string]>; -}; - -type CommandDocsReply = Array<[CommandName: string, CommandDocumentation: CommandDocumentation]>; - -export function transformReply(rawReply: Array): CommandDocsReply { - const replyArray:CommandDocsReply = []; - - for (let i = 0; i < rawReply.length; i++) { - - replyArray.push([ - rawReply[i++], // The name of the command - { - summary: rawReply[i][1], - since: rawReply[i][3], - group: rawReply[i][5], - complexity: rawReply[i][7], - history: rawReply[i][8] == 'history' ? rawReply[i][9] : null - } - ]); + if (commandNames) { + pushVerdictArguments(args, commandNames); } - return replyArray; + return args; +} + +interface ArgumentsDoc { + keySpecIndex?: number; + type?: string; + token?: string; + summary?: string; + flags?: Array; +} + +interface ArgumentsDocsReply { + [name: string]: ArgumentsDoc; +} + +interface Doc { + summary?: string; + since?: string; + group?: string; + complexity?: string; + history?: Array<{ + version: string; + description: string; + }>; + arguments?: ArgumentsDocsReply; + subCommands?: CommandDocsReply; +} + +interface CommandDocsReply { + [command: string]: Doc; +} + +export function transformReply(rawReply: Array): CommandDocsReply { + const reply:CommandDocsReply = {}; + + for (let i = 0; i < rawReply.length; i++) { + reply[rawReply[i++]] = createDocumentationInterface(rawReply[i]); + } + + return reply; +} + +function createDocumentationInterface(rawDocumentation: Array): Doc { + const doc:Doc = {} + + for (let j = 0; j < rawDocumentation.length; j++) { + switch (rawDocumentation[j++]) { + case 'summary': + doc['summary'] = rawDocumentation[j]; + break; + case 'since': + doc['since'] = rawDocumentation[j]; + break; + case 'group': + doc['group'] = rawDocumentation[j]; + break; + case 'complexity': + doc['complexity'] = rawDocumentation[j]; + break; + case 'history': + const historyArray = [] + for (let k = 0; k < rawDocumentation[j].length; k++) { + historyArray.push({ + version: rawDocumentation[j][k][0], + description: rawDocumentation[j][k][1] + }); + } + doc['history'] = historyArray; + break; + case 'arguments': + doc['arguments'] = createArgumentsDocumentation(rawDocumentation[j]); + break; + case 'subcommands': + doc['subCommands'] = transformReply(rawDocumentation[j]); + break; + } + } + + return doc; +} + +function createArgumentsDocumentation(rawDocumentation: Array): ArgumentsDocsReply { + const doc:ArgumentsDocsReply = {} + + for (let k = 0; k < rawDocumentation.length; k++) { + let argumentName = ""; + const argumentData:ArgumentsDoc = {}; + + for (let l = 0; l < rawDocumentation[k].length; l++) { + switch (rawDocumentation[k][l++]) { + case 'name': + argumentName = rawDocumentation[k][l]; + break; + case 'type': + argumentData['type'] = rawDocumentation[k][l]; + break; + case 'token': + argumentData['token'] = rawDocumentation[k][l]; + break; + case 'summary': + argumentData['summary'] = rawDocumentation[k][l]; + break; + case 'flags': + argumentData['flags'] = rawDocumentation[k][l]; + break; + case 'key_spec_index': + argumentData['keySpecIndex'] = rawDocumentation[k][l]; + break; + } + } + + doc[argumentName] = argumentData; + } + + return doc; }