1 |
|
2 |
|
3 |
|
4 |
|
5 | const Table = require('cli-table2');
|
6 | const chalk = require('chalk');
|
7 | const path = require('path');
|
8 | const fs = require('fs');
|
9 | const txtfile = require('read-text-file');
|
10 | const manifest = require('./api/qnamaker');
|
11 | const windowSize = require('window-size');
|
12 | const { getServiceManifest } = require('../lib/utils/argsUtil');
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | module.exports = async function help(args, output) {
|
21 | if (!output)
|
22 | output = process.stderr;
|
23 |
|
24 | output.write('QnA Maker Command line interface - © 2018 Microsoft Corporation\n\n');
|
25 | const helpContents = await getHelpContents(args, output);
|
26 | let width = windowSize ? windowSize.width : 250;
|
27 |
|
28 | let leftColWidth = 0;
|
29 | for (let hc of helpContents) {
|
30 | if (hc.table && hc.table[0].length > 0) {
|
31 | const rows = hc.table[0].length;
|
32 | for (let row in hc.table) {
|
33 | let len = hc.table[row][0].length;
|
34 | if (len > leftColWidth) {
|
35 | leftColWidth = Math.min(len, Math.floor(width / 3));
|
36 | }
|
37 | }
|
38 | let i = rows - 1;
|
39 | }
|
40 | }
|
41 |
|
42 | helpContents.forEach(helpContent => {
|
43 | output.write(chalk.white.bold(helpContent.head + '\n'));
|
44 | if (helpContent.table && helpContent.table[0].length > 0) {
|
45 | const rows = helpContent.table[0].length;
|
46 | let i = rows - 1;
|
47 |
|
48 | const colWidthsFor2On = ((width * .85) - leftColWidth) / i;
|
49 | const colWidths = [leftColWidth];
|
50 |
|
51 | while (i--) {
|
52 | colWidths.push(~~colWidthsFor2On);
|
53 | }
|
54 |
|
55 | const table = new Table({
|
56 |
|
57 | chars: {
|
58 | 'top': '', 'top-mid': '', 'top-left': '', 'top-right': '',
|
59 | 'bottom': '', 'bottom-mid': '', 'bottom-left': '', 'bottom-right': '',
|
60 | 'left': '', 'left-mid': '', 'right': '', 'right-mid': '',
|
61 | 'mid': '', 'mid-mid': '', 'middle': ''
|
62 | },
|
63 | colWidths,
|
64 | style: { 'padding-left': 1, 'padding-right': 1 },
|
65 | wordWrap: true
|
66 | });
|
67 | table.push(...helpContent.table);
|
68 | output.write(table.toString());
|
69 | }
|
70 | output.write('\n\n');
|
71 | });
|
72 | }
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 | async function getHelpContents(args, output) {
|
82 | if ('!' in args) {
|
83 | return getAllCommands(output);
|
84 | }
|
85 |
|
86 | if (args._.length == 0) {
|
87 | return getGeneralHelpContents(output);
|
88 | }
|
89 | else if (args._.length == 1) {
|
90 | return getVerbHelp(args._[0], output);
|
91 | } else if (args._.length >= 2) {
|
92 | const serviceManifest = getServiceManifest(args);
|
93 | if (serviceManifest) {
|
94 | const { operation } = serviceManifest;
|
95 |
|
96 | output.write(`${operation.description}\n\n`);
|
97 | output.write(`Usage:\n${chalk.cyan.bold(operation.command)}\n\n`);
|
98 | } else {
|
99 | return getVerbHelp(args._[0], output);
|
100 | }
|
101 | }
|
102 |
|
103 | const serviceManifest = getServiceManifest(args);
|
104 | if (serviceManifest) {
|
105 | return getHelpContentsForService(serviceManifest, output);
|
106 | }
|
107 |
|
108 | return getGeneralHelpContents(output);
|
109 | }
|
110 |
|
111 |
|
112 | let configSection = {
|
113 | head: 'Configuration and Overrides:',
|
114 | table: [
|
115 | [chalk.cyan.bold('--subscriptionKey <key>'), 'Specifies the qnamaker subscription key/access keys (found on the Cognitive Services Azure portal page under "access keys"). Overrides the .qnamakerrc value and the QNAMAKER_SUBSCRIPTION_KEY environment variable.'],
|
116 | [chalk.cyan.bold('--hostname <url>'), 'Specifies the url for your private QnA service. Overrides the .qnamakerrc value and the QNAMAKER_HOSTNAME environment variable.'],
|
117 | [chalk.cyan.bold('--endpointKey <key>'), 'Specifies the endpoint key for your private QnA service.(from qnamaker.ai portal user settings page). Overrides the .qnamakerrc value and the QNAMAKER_ENDPOINTKEY environment variable.'],
|
118 | [chalk.cyan.bold('--kbId <kbId>'), 'Specifies the active qnamaker knowledgebase id. Overrides the .qnamakerrc value and the QNAMAKER_KBID environment variable.'],
|
119 | ]
|
120 | };
|
121 |
|
122 | let globalArgs = {
|
123 | head: 'Global Arguments:',
|
124 | table: [
|
125 | [chalk.cyan.bold('--help, -h'), 'Prints this help file.'],
|
126 | [chalk.cyan.bold('--version, -v'), 'Prints the version of this cli tool'],
|
127 | [chalk.cyan.bold('--! '), 'Dumps all documented commands to the console with descriptions']
|
128 | ]
|
129 | };
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 | function getGeneralHelpContents(output) {
|
137 | let operation;
|
138 | let verbs = [];
|
139 | let options = {
|
140 | head: chalk.bold(`Available actions are:`),
|
141 | table: [
|
142 | [chalk.cyan.bold("create"), "create a resource"],
|
143 | [chalk.cyan.bold("delete"), "delete a resource"],
|
144 | [chalk.cyan.bold("export"), "export resources"],
|
145 | [chalk.cyan.bold("get"), "get a resource"],
|
146 | [chalk.cyan.bold('init'), 'Initializes the .qnamakerrc file with settings'],
|
147 | [chalk.cyan.bold("list"), "list resources"],
|
148 | [chalk.cyan.bold("publish"), "publish resource"],
|
149 | [chalk.cyan.bold("query"), "query model for prediction"],
|
150 | [chalk.cyan.bold("refresh"), "refresh resources"],
|
151 | [chalk.cyan.bold("set"), "change the .qnamakerrc settings"],
|
152 | [chalk.cyan.bold("update"), "update resources"],
|
153 | [chalk.cyan.bold("replace"), "replace a resource"]
|
154 |
|
155 | ]
|
156 | };
|
157 |
|
158 | let sections = [];
|
159 | sections.push(options);
|
160 | sections.push(configSection);
|
161 | sections.push(globalArgs);
|
162 | return sections;
|
163 | }
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 |
|
170 | function getVerbHelp(verb, output) {
|
171 | let operation;
|
172 | let targets = [];
|
173 | let options = {
|
174 | head: `Available resources for ${chalk.bold(verb)}:`,
|
175 | table: []
|
176 | };
|
177 |
|
178 |
|
179 | let sections = [];
|
180 | switch (verb) {
|
181 | case "query":
|
182 | output.write(chalk.cyan.bold("qnamaker query --question <querytext>\n\n"));
|
183 | options.table.push([chalk.cyan.bold("--question <query>"), "query to get a prediction for"]);
|
184 | sections.push(options);
|
185 | sections.push(configSection);
|
186 | sections.push(globalArgs);
|
187 | return sections;
|
188 |
|
189 | case "set":
|
190 | output.write(chalk.cyan.bold("qnamaker set <.qnamakerrcSetting> <value>\n\n"));
|
191 | options.table.push([chalk.cyan.bold("kbid <kbid>"), "change the active knowledgebase id "]);
|
192 | options.table.push([chalk.cyan.bold("subscriptionkey <subscriptionkey>"), "change the active subscriptionkey"]);
|
193 | sections.push(options);
|
194 | sections.push(globalArgs);
|
195 | return sections;
|
196 | case "init":
|
197 | output.write(chalk.cyan.bold("qnamaker init\n\n"));
|
198 | sections.push(globalArgs);
|
199 | return sections;
|
200 | }
|
201 |
|
202 | for (let apiGroupName in manifest) {
|
203 | const category = manifest[apiGroupName];
|
204 |
|
205 | for (let iOperation in category.operations) {
|
206 | let operation = category.operations[iOperation];
|
207 | if (operation.methodAlias == verb) {
|
208 | let target = operation.target[0];
|
209 | if (targets.indexOf(target) < 0) {
|
210 | targets.push(target);
|
211 | }
|
212 | }
|
213 | }
|
214 | }
|
215 |
|
216 | if (targets.length == 0)
|
217 | return getGeneralHelpContents(output);
|
218 |
|
219 | targets.sort();
|
220 | for (let verb of targets) {
|
221 | options.table.push([chalk.cyan.bold(verb), '']);
|
222 | }
|
223 | sections.push(options);
|
224 | sections.push(configSection);
|
225 | sections.push(globalArgs);
|
226 | return sections;
|
227 | }
|
228 |
|
229 |
|
230 |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 | function getAllCommands() {
|
236 | const table = [];
|
237 | let resourceTypes = [];
|
238 | let tables = {};
|
239 | Object.keys(manifest).forEach(key => {
|
240 | const { [key]: category } = manifest;
|
241 | Object.keys(category.operations).forEach((operationKey, index) => {
|
242 | let operation = category.operations[operationKey];
|
243 | let opCategory = operation.target[0] || operation.methodAlias;
|
244 | if (resourceTypes.indexOf(opCategory) < 0) {
|
245 | resourceTypes.push(opCategory);
|
246 | tables[opCategory] = [];
|
247 | }
|
248 | tables[opCategory].push([chalk.cyan.bold(operation.command), operation.description]);
|
249 | });
|
250 | });
|
251 |
|
252 | resourceTypes.sort();
|
253 |
|
254 | let sections = [];
|
255 | for (resourceType of resourceTypes) {
|
256 | tables[resourceType].sort((a, b) => a[0].localeCompare(b[0]));
|
257 | sections.push({
|
258 | head: chalk.white.bold(resourceType),
|
259 | table: tables[resourceType]
|
260 | });
|
261 | }
|
262 |
|
263 | return sections;
|
264 | }
|
265 |
|
266 |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 |
|
273 |
|
274 |
|
275 |
|
276 | function getHelpContentsForService(serviceManifest, output) {
|
277 | const { operation } = serviceManifest;
|
278 | const operations = serviceManifest.operation ? [operation] : serviceManifest.operations;
|
279 |
|
280 | const sections = [];
|
281 |
|
282 |
|
283 | if (serviceManifest.operation) {
|
284 | let paramsHelp = { head: '', table: [] };
|
285 | if (serviceManifest.operation.params) {
|
286 | const { params } = operation;
|
287 | paramsHelp = {
|
288 | head: `Command arguments are:`,
|
289 | table: params.map(param => [chalk.cyan.bold(`--${param.alias || param.name} <${param.type}>${param.required ? ' (required)' : ''}`), param.description])
|
290 | };
|
291 | if (operation.entityName) {
|
292 | paramsHelp.table.unshift([chalk.cyan.bold(`--in ${operation.entityType}.json`), `The ${operation.entityType} object to send in the body of the request`],
|
293 | ['', chalk.dim(getEntityTypeExample(operation.entityType))]);
|
294 | }
|
295 | } else if (operation.entityName) {
|
296 | paramsHelp = {
|
297 | head: `Command arguments are:`,
|
298 | table: [
|
299 | [chalk.cyan.bold(`--in ${operation.entityType}.json`), `The ${operation.entityType} object to send in the body of the request`],
|
300 | ['', chalk.dim(getEntityTypeExample(operation.entityType))]
|
301 | ]
|
302 | };
|
303 | }
|
304 | if (operation.name == 'createKnowledgebase' || operation.name == 'getKnowledgebaseDetails') {
|
305 | paramsHelp.table.push([chalk.cyan.bold(`--msbot`), `(OPTIONAL) Format the output as json for piping into msbot connect qna command`]);
|
306 | }
|
307 | if (paramsHelp.table.length > 0)
|
308 | sections.push(paramsHelp);
|
309 | }
|
310 | sections.push(configSection);
|
311 | sections.push(globalArgs);
|
312 | return sections;
|
313 | }
|
314 |
|
315 |
|
316 | function getEntityTypeExample(entityType) {
|
317 | try {
|
318 | var examplePath = path.join(__dirname, `../examples/${entityType}.json`);
|
319 | let json = txtfile.readSync(examplePath).replace(/[\r\f]+/g, '\n');
|
320 | return json;
|
321 | } catch (error) {
|
322 | return `{/*example for ${entityType} missing*/}`;
|
323 | }
|
324 | } |
\ | No newline at end of file |