Skip to content

Commit fb6ec65

Browse files
authored
feat: Adds pagination to the OpenAPI command (#353)
* feat: add more option to oas prompt * feat: add pagination functionality to openapi
1 parent e622ea2 commit fb6ec65

File tree

5 files changed

+123
-29
lines changed

5 files changed

+123
-29
lines changed

__tests__/lib/prompts.test.js

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ const specList = [
2121
},
2222
];
2323

24+
const getSpecs = () => {
25+
return [
26+
{
27+
_id: 'spec3',
28+
title: 'spec3_title',
29+
},
30+
];
31+
};
32+
2433
describe('prompt test bed', () => {
2534
let enquirer;
2635

@@ -70,23 +79,31 @@ describe('prompt test bed', () => {
7079
await prompt.keypress(null, { name: 'down' });
7180
await prompt.submit();
7281
});
73-
const answer = await enquirer.prompt(promptHandler.createOasPrompt([{}]));
82+
const answer = await enquirer.prompt(promptHandler.createOasPrompt([{}], null, 1, null));
7483

7584
expect(answer.option).toBe('create');
76-
expect(answer.specId).toBe('');
7785
});
7886

7987
it('should return specId if user chooses to update file', async () => {
88+
jest.mock('enquirer');
8089
enquirer.on('prompt', async prompt => {
8190
await prompt.keypress(null, { name: 'down' });
8291
await prompt.keypress(null, { name: 'up' });
8392
await prompt.submit();
84-
await prompt.submit();
8593
});
86-
const answer = await enquirer.prompt(promptHandler.createOasPrompt(specList));
94+
enquirer.prompt = jest.fn();
95+
enquirer.prompt.mockReturnValue('spec1');
96+
const parsedDocs = {
97+
next: {
98+
page: null,
99+
},
100+
prev: {
101+
page: null,
102+
},
103+
};
104+
const answer = await enquirer.prompt(promptHandler.createOasPrompt(specList, parsedDocs, 1, getSpecs));
87105

88-
expect(answer.option).toBe('update');
89-
expect(answer.specId).toBe('spec1');
106+
expect(answer).toBe('spec1');
90107
});
91108
});
92109

package-lock.json

Lines changed: 18 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"oas": "^14.0.0",
4646
"oas-normalize": "^3.0.4",
4747
"open": "^8.2.1",
48+
"parse-link-header": "^1.0.1",
4849
"read": "^1.0.7",
4950
"semver": "^7.0.0",
5051
"table-layout": "^1.0.0"

src/cmds/openapi.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const APIError = require('../lib/apiError');
88
const { getProjectVersion } = require('../lib/versionSelect');
99
const fetch = require('node-fetch');
1010
const FormData = require('form-data');
11+
const parse = require('parse-link-header');
1112

1213
exports.command = 'openapi';
1314
exports.usage = 'openapi [file] [options]';
@@ -159,19 +160,28 @@ exports.run = async function (opts) {
159160
- If found, prompt user to either create a new spec or update an existing one
160161
*/
161162

162-
if (!id) {
163-
const apiSettings = await fetch(`${config.host}/api/v1/api-specification`, {
163+
function getSpecs(url) {
164+
return fetch(`${config.host}${url}`, {
164165
method: 'get',
165166
headers: {
166167
'x-readme-version': versionCleaned,
167168
Authorization: `Basic ${encodedString}`,
168169
},
169-
}).then(res => res.json());
170+
});
171+
}
172+
173+
if (!id) {
174+
const apiSettings = await getSpecs(`/api/v1/api-specification`);
175+
176+
const totalPages = Math.ceil(apiSettings.headers.get('x-total-count') / 10);
177+
const parsedDocs = parse(apiSettings.headers.get('link'));
170178

171-
if (!apiSettings.length) return createSpec();
179+
const apiSettingsBody = await apiSettings.json();
180+
if (!apiSettingsBody.length) return createSpec();
172181

173-
const { option, specId } = await prompt(promptOpts.createOasPrompt(apiSettings));
174-
return option === 'create' ? createSpec() : updateSpec(specId);
182+
const { option } = await prompt(promptOpts.createOasPrompt(apiSettingsBody, parsedDocs, totalPages, getSpecs));
183+
if (!option) return null;
184+
return option === 'create' ? createSpec() : updateSpec(option);
175185
}
176186

177187
/*

src/lib/prompts.js

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
const semver = require('semver');
2+
const { prompt } = require('enquirer');
3+
const parse = require('parse-link-header');
24

35
exports.generatePrompts = (versionList, selectOnly = false) => [
46
{
@@ -38,7 +40,59 @@ exports.generatePrompts = (versionList, selectOnly = false) => [
3840
},
3941
];
4042

41-
exports.createOasPrompt = specList => [
43+
function specOptions(specList, parsedDocs, currPage, totalPages) {
44+
const specs = specList.map(s => {
45+
return {
46+
message: s.title,
47+
value: s._id, // eslint-disable-line no-underscore-dangle
48+
};
49+
});
50+
if (parsedDocs.prev.page) specs.push({ message: `< Prev (page ${currPage - 1} of ${totalPages})`, value: 'prev' });
51+
if (parsedDocs.next.page) {
52+
specs.push({ message: `Next (page ${currPage + 1} of ${totalPages}) >`, value: 'next' });
53+
}
54+
return specs;
55+
}
56+
57+
const updateOasPrompt = (specList, parsedDocs, currPage, totalPages, getSpecs) => [
58+
{
59+
type: 'select',
60+
name: 'specId',
61+
message: 'Select your desired file to update',
62+
choices: specOptions(specList, parsedDocs, currPage, totalPages),
63+
async result(spec) {
64+
if (spec === 'prev') {
65+
try {
66+
const newSpecs = await getSpecs(`${parsedDocs.prev.url}`);
67+
const newParsedDocs = parse(newSpecs.headers.get('link'));
68+
const newSpecList = await newSpecs.json();
69+
const { specId } = await prompt(
70+
updateOasPrompt(newSpecList, newParsedDocs, currPage - 1, totalPages, getSpecs)
71+
);
72+
return specId;
73+
} catch (e) {
74+
return null;
75+
}
76+
}
77+
if (spec === 'next') {
78+
try {
79+
const newSpecs = await getSpecs(`${parsedDocs.next.url}`);
80+
const newParsedDocs = parse(newSpecs.headers.get('link'));
81+
const newSpecList = await newSpecs.json();
82+
const { specId } = await prompt(
83+
updateOasPrompt(newSpecList, newParsedDocs, currPage + 1, totalPages, getSpecs)
84+
);
85+
return specId;
86+
} catch (e) {
87+
return null;
88+
}
89+
}
90+
return spec;
91+
},
92+
},
93+
];
94+
95+
exports.createOasPrompt = (specList, parsedDocs, totalPages, getSpecs) => [
4296
{
4397
type: 'select',
4498
name: 'option',
@@ -47,20 +101,17 @@ exports.createOasPrompt = specList => [
47101
{ message: 'Update existing', value: 'update' },
48102
{ message: 'Create a new spec', value: 'create' },
49103
],
50-
},
51-
{
52-
type: 'select',
53-
name: 'specId',
54-
message: 'Select your desired file to update',
55-
skip() {
56-
return this.enquirer.answers.option !== 'update';
104+
async result(picked) {
105+
if (picked === 'update') {
106+
try {
107+
const { specId } = await prompt(updateOasPrompt(specList, parsedDocs, 1, totalPages, getSpecs));
108+
return specId;
109+
} catch (e) {
110+
return null;
111+
}
112+
}
113+
return picked;
57114
},
58-
choices: specList.map(s => {
59-
return {
60-
message: s.title,
61-
value: s._id, // eslint-disable-line no-underscore-dangle
62-
};
63-
}),
64115
},
65116
];
66117

0 commit comments

Comments
 (0)