@pixlcore/xycli 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +32 -17
- package/package.json +1 -1
- package/test/help.test.js +25 -4
- package/test/helpers/crlf-help.js +18 -0
package/index.js
CHANGED
|
@@ -198,6 +198,34 @@ const app = {
|
|
|
198
198
|
return;
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
+
// Validate local command routing before requiring a configured server. This
|
|
202
|
+
// keeps help and typo diagnostics available during initial CLI setup. Export
|
|
203
|
+
// is excluded because it also supports portable resource types that do not
|
|
204
|
+
// have their own complete command routers yet.
|
|
205
|
+
if (!('export' in args) && !this['cmd_' + cmd]) {
|
|
206
|
+
// Allow the user to swap the first two args if the second is a known command.
|
|
207
|
+
if (this['cmd_' + args.other[0]]) {
|
|
208
|
+
var new_cmd = args.other[0];
|
|
209
|
+
args.other[0] = cmd;
|
|
210
|
+
cmd = new_cmd;
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
var suggestion = this.findClosestString(cmd, TOP_LEVEL_COMMANDS);
|
|
214
|
+
this.die(
|
|
215
|
+
"Unknown command: " + cmd + (suggestion ? '. Did you mean "' + suggestion + '"?' : ''),
|
|
216
|
+
"Available Commands: " + TOP_LEVEL_COMMANDS.join(', ') + "\n\n"
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Help is entirely local, so it should work before a user has configured an
|
|
222
|
+
// API key or server URL, and should never make a network request.
|
|
223
|
+
if (cmd == 'help') {
|
|
224
|
+
await this.cmd_help();
|
|
225
|
+
print("\n");
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
201
229
|
delete args.debug;
|
|
202
230
|
delete args.echo;
|
|
203
231
|
delete args.quiet;
|
|
@@ -273,22 +301,6 @@ const app = {
|
|
|
273
301
|
return;
|
|
274
302
|
}
|
|
275
303
|
|
|
276
|
-
if (!this['cmd_' + cmd]) {
|
|
277
|
-
// allow user to swap first two args, if 2nd is known command
|
|
278
|
-
if (this['cmd_' + args.other[0]]) {
|
|
279
|
-
var new_cmd = args.other[0];
|
|
280
|
-
args.other[0] = cmd;
|
|
281
|
-
cmd = new_cmd;
|
|
282
|
-
}
|
|
283
|
-
else {
|
|
284
|
-
var suggestion = this.findClosestString(cmd, TOP_LEVEL_COMMANDS);
|
|
285
|
-
this.die(
|
|
286
|
-
"Unknown command: " + cmd + (suggestion ? '. Did you mean "' + suggestion + '"?' : ''),
|
|
287
|
-
"Available Commands: " + TOP_LEVEL_COMMANDS.join(', ') + "\n\n"
|
|
288
|
-
);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
304
|
// merge in config from xyops
|
|
293
305
|
await this.cacheConfig();
|
|
294
306
|
|
|
@@ -368,7 +380,10 @@ const app = {
|
|
|
368
380
|
printHelp(heading) {
|
|
369
381
|
// print named section from help file
|
|
370
382
|
heading = heading.toLowerCase();
|
|
371
|
-
|
|
383
|
+
// Git may check this file out with CRLF on Windows. Normalize it before
|
|
384
|
+
// matching headings so the parser behaves identically on every platform.
|
|
385
|
+
var md = fs.readFileSync(Path.join(__dirname, 'docs', 'help.md'), 'utf8')
|
|
386
|
+
.replace(/\r\n?/g, '\n').trim() + "\n\n# end sentinel\n";
|
|
372
387
|
var re = new RegExp( "(^|\\n)(\\#+)\\s+(" + Tools.escapeRegExp(heading) + ")\\n([\\s\\S]*?)\\n\#+\\s+" );
|
|
373
388
|
var matches = md.match(re);
|
|
374
389
|
if (!matches) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixlcore/xycli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "A complete command-line interface for the xyOps workflow automation system.",
|
|
5
5
|
"author": "Joseph Huckaby <jhuckaby@pixlcore.com>",
|
|
6
6
|
"homepage": "https://github.com/pixlcore/xycli",
|
package/test/help.test.js
CHANGED
|
@@ -1,26 +1,47 @@
|
|
|
1
1
|
const { test } = require('node:test');
|
|
2
2
|
const assert = require('node:assert/strict');
|
|
3
|
+
const Path = require('node:path');
|
|
3
4
|
const { xy } = require('./helpers/common.js');
|
|
4
5
|
|
|
6
|
+
// Deliberately shadow any developer-machine configuration. Help and command
|
|
7
|
+
// diagnostics must remain useful before the user connects the CLI to xyOps.
|
|
8
|
+
const offlineEnv = {
|
|
9
|
+
XYOPS_API_KEY: '',
|
|
10
|
+
XYOPS_BASE_URL: ''
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const offlineFailure = { fail: true, env: offlineEnv };
|
|
14
|
+
const crlfHelpPreload = Path.join(__dirname, 'helpers', 'crlf-help.js');
|
|
15
|
+
|
|
16
|
+
test('help is available without server credentials', () => {
|
|
17
|
+
const output = xy(['help'], { env: offlineEnv });
|
|
18
|
+
assert.match(output, /HELP: OVERVIEW/);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('help parses a document with Windows line endings', () => {
|
|
22
|
+
const output = xy(['help'], { env: offlineEnv, preload: crlfHelpPreload });
|
|
23
|
+
assert.match(output, /HELP: OVERVIEW/);
|
|
24
|
+
});
|
|
25
|
+
|
|
5
26
|
test('help suggests the closest chapter for a typo', () => {
|
|
6
|
-
const output = xy(['help', 'event', 'udpate'],
|
|
27
|
+
const output = xy(['help', 'event', 'udpate'], offlineFailure);
|
|
7
28
|
assert.match(output, /Could not find help chapter for "event udpate"\. Did you mean "event update"\?/);
|
|
8
29
|
});
|
|
9
30
|
|
|
10
31
|
test('help does not suggest an unrelated chapter', () => {
|
|
11
|
-
const output = xy(['help', 'completely', 'unrelated', 'words'],
|
|
32
|
+
const output = xy(['help', 'completely', 'unrelated', 'words'], offlineFailure);
|
|
12
33
|
assert.match(output, /Could not find help chapter for "completely unrelated words"\./);
|
|
13
34
|
assert.doesNotMatch(output, /Did you mean/);
|
|
14
35
|
});
|
|
15
36
|
|
|
16
37
|
test('unknown top-level command suggests the closest command', () => {
|
|
17
|
-
const output = xy(['evnets'],
|
|
38
|
+
const output = xy(['evnets'], offlineFailure);
|
|
18
39
|
assert.match(output, /Unknown command: evnets\. Did you mean "events"\?/);
|
|
19
40
|
assert.match(output, /Available Commands:.*events/);
|
|
20
41
|
});
|
|
21
42
|
|
|
22
43
|
test('unknown top-level command does not suggest an unrelated command', () => {
|
|
23
|
-
const output = xy(['completely_unrelated'],
|
|
44
|
+
const output = xy(['completely_unrelated'], offlineFailure);
|
|
24
45
|
assert.match(output, /Unknown command: completely_unrelated/);
|
|
25
46
|
assert.doesNotMatch(output, /Did you mean/);
|
|
26
47
|
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Force the help document through the same CRLF checkout transformation Git
|
|
2
|
+
// commonly applies on Windows, so this regression is covered on every runner.
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const Path = require('node:path');
|
|
5
|
+
const readFileSync = fs.readFileSync;
|
|
6
|
+
|
|
7
|
+
fs.readFileSync = function(file) {
|
|
8
|
+
var contents = readFileSync.apply(this, arguments);
|
|
9
|
+
var filename = String(file);
|
|
10
|
+
var is_help = (Path.basename(filename) == 'help.md') &&
|
|
11
|
+
(Path.basename(Path.dirname(filename)) == 'docs');
|
|
12
|
+
|
|
13
|
+
if (is_help && (typeof(contents) == 'string')) {
|
|
14
|
+
return contents.replace(/\r?\n/g, '\r\n');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return contents;
|
|
18
|
+
};
|