@trenskow/arguments-parser 0.3.130 → 0.3.133

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/README.md CHANGED
@@ -80,40 +80,20 @@ Options:
80
80
 
81
81
  > The validation schema is described in package [isvalid](https://github.com/trenskow/isvalid).
82
82
 
83
- ## Autocomplete
83
+ ## Autocompletion
84
84
 
85
- This supports Bash and ZSH autocomplete of the box.
85
+ The library supports Bash and ZSH autocompletion out of the box.
86
86
 
87
- > In both examples below replace `my_script` with the actual name of the script.
87
+ To generate the completion scripts to install for the current shell - use the command below...
88
88
 
89
- ### Bash
90
-
91
- The completion script for Bash should be installed as below.
92
-
93
- ````bash
94
- _my_script() {
95
- eval "$(AUTOCOMPLETE=bash my_script "${COMP_WORDS[@]}")"
96
- }
97
-
98
- complete -F _my_script my_script
89
+ ````
90
+ ./my_script _completion
99
91
  ````
100
92
 
101
- #### ZSH
102
-
103
- The completion script for ZSH should be installed as below.
104
-
105
- ````zsh
106
- #compdef my_script
107
-
108
- _my_script() {
109
-
110
- local -a completions
111
-
112
- eval "$(AUTOCOMPLETE=zsh my_script ${words[@]})"
113
-
114
- }
93
+ ...or if you need to generate for another shell than the current one.
115
94
 
116
- _my_script
95
+ ````
96
+ ./my_script _completion [bash|zsh]
117
97
  ````
118
98
 
119
99
  # License
package/index.js CHANGED
@@ -6,7 +6,14 @@
6
6
  // See license in LICENSE.
7
7
  //
8
8
 
9
- import { plugins } from 'isvalid';
9
+ import {
10
+ basename,
11
+ extname
12
+ } from 'path';
13
+
14
+ import {
15
+ plugins
16
+ } from 'isvalid';
10
17
 
11
18
  import argumentsParser from './lib/index.js';
12
19
  import autocomplete from './lib/autocomplete/index.js';
@@ -65,4 +72,18 @@ plugins.use('argumentsParser.autocomplete', () => ({
65
72
  }
66
73
  }));
67
74
 
68
- export default autocomplete(process.env.AUTOCOMPLETE) || argumentsParser;
75
+ if (process.argv[2] === '_completion') {
76
+
77
+ const path = process.env.COMPLETION_PATH || process.argv[1];
78
+
79
+ autocomplete.script({
80
+ shell: process.argv[3],
81
+ command: basename(path)
82
+ .slice(0, -extname(path).length)
83
+ });
84
+
85
+ process.exit(0);
86
+
87
+ }
88
+
89
+ export default typeof process.env.AUTOCOMPLETE_INDEX !== 'undefined' ? autocomplete() : argumentsParser;
@@ -6,7 +6,7 @@
6
6
  // See license in LICENSE.
7
7
  //
8
8
 
9
- export default (items) => {
9
+ const bash = (items) => {
10
10
 
11
11
  const keys = Object.keys(items);
12
12
 
@@ -52,13 +52,25 @@ export default (items) => {
52
52
  });
53
53
 
54
54
  process.stdout.write(')\n');
55
-
55
+
56
56
  }
57
57
 
58
58
  if (files) {
59
- process.stdout.write('COMPREPLY+=($(compgen -f -- "${COMP_WORDS[COMP_CWORD]}"))\n');
59
+ process.stdout.write('COMPREPLY+=($(compgen -f -- "${COMP_WORDS[COMP_CWORD]}"))\n');
60
60
  }
61
61
 
62
62
  process.exit(0);
63
63
 
64
64
  };
65
+
66
+ bash.script = ({
67
+ command
68
+ }) => `_${command}() {
69
+ eval "$(AUTOCOMPLETE_INDEX=$COMP_CWORD ${command} "\${COMP_WORDS[@]}")"
70
+ }
71
+
72
+ complete -F _${command} ${command}`;
73
+
74
+ bash.autocompleteIndexOffset = 1;
75
+
76
+ export default bash;
@@ -25,14 +25,14 @@ const supported = {
25
25
  zsh
26
26
  };
27
27
 
28
- const argumentsParser = (shell) => {
28
+ const argumentsParser = () => {
29
29
 
30
- if (!shell) return;
30
+ const currentShell = basename(process.env.SHELL || '');
31
31
 
32
- shell = supported[shell];
32
+ const writer = supported[currentShell];
33
33
 
34
- if (!shell) {
35
- process.stderr.write(`Unsupported shell: ${shell}\n`);
34
+ if (!writer) {
35
+ process.stderr.write(`Unsupported shell: ${currentShell}\n`);
36
36
  process.exit(1);
37
37
  }
38
38
 
@@ -64,7 +64,7 @@ const argumentsParser = (shell) => {
64
64
  });
65
65
  };
66
66
 
67
- const output = (items) => shell(
67
+ const output = (items) => writer(
68
68
  normalize(items)
69
69
  .reduce((grouped, item) => {
70
70
 
@@ -85,7 +85,7 @@ const argumentsParser = (shell) => {
85
85
 
86
86
  const argumentsParser = (
87
87
  {
88
- args = process.argv.slice(shell.argsOffset || 3),
88
+ args = process.argv.slice(3),
89
89
  argvLevel = 0,
90
90
  placeholder = '<>',
91
91
  command,
@@ -100,6 +100,10 @@ const argumentsParser = (shell) => {
100
100
  } = {}
101
101
  ) => {
102
102
 
103
+ let autocompleteIndex = process.env.AUTOCOMPLETE_INDEX;
104
+
105
+ autocompleteIndex = parseInt(autocompleteIndex) - argvLevel - writer.autocompleteIndexOffset;
106
+
103
107
  const base = `${process.argv.slice(1, argvLevel + 2).map(((arg) => basename(arg))).join(' ')}`;
104
108
 
105
109
  const next = async (identifier, command) => {
@@ -114,7 +118,8 @@ const argumentsParser = (shell) => {
114
118
  placeholder,
115
119
  command: command,
116
120
  options,
117
- parameters
121
+ parameters,
122
+ autocompleteIndex: autocompleteIndex - 1
118
123
  }),
119
124
  parameters
120
125
  });
@@ -129,6 +134,18 @@ const argumentsParser = (shell) => {
129
134
 
130
135
  const tool = caseit(args[0] || '');
131
136
 
137
+ if (autocompleteIndex === 0) {
138
+
139
+ return output(Object.keys(commands)
140
+ .filter((command) => command.startsWith(tool))
141
+ .map((command) => ({
142
+ type: 'command',
143
+ argument: caseit(command, 'kebab'),
144
+ description: commands[command].description
145
+ })));
146
+
147
+ }
148
+
132
149
  if (commands[tool]) {
133
150
 
134
151
  onCommand?.(tool, args.slice(1));
@@ -139,13 +156,7 @@ const argumentsParser = (shell) => {
139
156
 
140
157
  }
141
158
 
142
- return output(Object.keys(commands)
143
- .filter((command) => command.startsWith(tool))
144
- .map((command) => ({
145
- type: 'command',
146
- argument: caseit(command, 'kebab'),
147
- description: commands[command].description
148
- })));
159
+ process.exit(0);
149
160
 
150
161
  },
151
162
  parameter: async ({
@@ -153,10 +164,10 @@ const argumentsParser = (shell) => {
153
164
  autocomplete
154
165
  }, command) => {
155
166
 
156
- const available = filter(await autocomplete?.(args[0] || '') || [], args[0]);
157
-
158
- if (available.length) {
159
- return output(available);
167
+ if (autocompleteIndex === 0) {
168
+ return output(
169
+ filter(
170
+ await autocomplete?.(args[0] || '') || [], args[0]));
160
171
  }
161
172
 
162
173
  parameters[identifier] = args[0];
@@ -203,6 +214,10 @@ const argumentsParser = (shell) => {
203
214
  }]
204
215
  } = options.validationOptions;
205
216
 
217
+ const variadicOnly = args
218
+ .slice(0, autocompleteIndex)
219
+ .some((arg) => arg === '--');
220
+
206
221
  const allKeyPaths = keyPaths(options.schema)
207
222
  .all()
208
223
  .filter((keyPath) => keyPath);
@@ -221,7 +236,7 @@ const argumentsParser = (shell) => {
221
236
 
222
237
  key = caseit(key);
223
238
 
224
- if (schemas[idx]) {
239
+ if (!variadicOnly && schemas[idx]) {
225
240
 
226
241
  if (schemas[idx].enum) {
227
242
  return Object.keys(schemas[idx].enum)
@@ -244,36 +259,46 @@ const argumentsParser = (shell) => {
244
259
 
245
260
  let items = [];
246
261
 
247
- if (!current.startsWith('--')) {
262
+ if (variadic === 'allow') {
263
+ items = items.concat(
264
+ filter(await autocomplete?.(current) || [], current));
265
+ }
266
+
267
+ if (!variadicOnly) {
268
+
269
+ if (!current.startsWith('--')) {
270
+
271
+ items = items.concat(
272
+ allKeyPaths
273
+ .filter((keyPath) => !spent.includes(keyPath))
274
+ .filter((keyPath) => key !== keyPath && keyPath.startsWith(key) && keyPaths(options.schema).get(keyPath).short)
275
+ .map((keyPath) => ({
276
+ type: 'option',
277
+ argument: `-${caseit(keyPaths(options.schema).get(keyPath).short, 'kebab')}`,
278
+ description: keyPaths(options.schema).get(keyPath).description
279
+ })));
248
280
 
249
- if (!current.startsWith('-')) {
250
- if (variadic === 'allow') {
251
- items = items.concat(
252
- filter(await autocomplete?.(current) || [], current));
253
- }
254
281
  }
255
282
 
283
+
256
284
  items = items.concat(
257
285
  allKeyPaths
258
286
  .filter((keyPath) => !spent.includes(keyPath))
259
- .filter((keyPath) => key !== keyPath && keyPath.startsWith(key) && keyPaths(options.schema).get(keyPath).short)
287
+ .filter((keyPath) => key !== keyPath && keyPath.startsWith(key))
260
288
  .map((keyPath) => ({
261
289
  type: 'option',
262
- argument: `-${caseit(keyPaths(options.schema).get(keyPath).short, 'kebab')}`,
290
+ argument: `--${caseit(keyPath, 'kebab')}`,
263
291
  description: keyPaths(options.schema).get(keyPath).description
264
292
  })));
265
293
 
266
294
  }
267
295
 
268
- items = items.concat(
269
- allKeyPaths
270
- .filter((keyPath) => !spent.includes(keyPath))
271
- .filter((keyPath) => key !== keyPath && keyPath.startsWith(key))
272
- .map((keyPath) => ({
273
- type: 'option',
274
- argument: `--${caseit(keyPath, 'kebab')}`,
275
- description: keyPaths(options.schema).get(keyPath).description
276
- })));
296
+ if (variadic === 'allow' && !variadicOnly && current === Array(current.length).fill('-').join('')) {
297
+ items = items.concat([{
298
+ type: 'option',
299
+ argument: '--'.slice(0, -current.length)
300
+ }]);
301
+ }
277
302
 
278
303
  return items;
279
304
 
@@ -286,13 +311,12 @@ const argumentsParser = (shell) => {
286
311
  await complete(-1));
287
312
  }
288
313
 
289
- for (idx = 0; idx < args.length; idx++) {
314
+ for (idx = 0; idx < autocompleteIndex || idx < args.length; idx++) {
290
315
 
291
316
  if (!schemas[idx]) {
292
317
 
293
- if (!args[idx].startsWith('-')) {
294
- return output(
295
- await complete(idx, args[idx]));
318
+ if (variadicOnly || !args[idx].startsWith('-')) {
319
+ continue;
296
320
  }
297
321
 
298
322
  const [keyPath, schema] = allKeyPaths
@@ -312,15 +336,8 @@ const argumentsParser = (shell) => {
312
336
 
313
337
  }
314
338
 
315
- const current = await complete(idx - 1, args[idx - 1]);
316
-
317
- if (current.length) {
318
- return output(current);
319
- }
320
-
321
339
  return output(
322
- await complete(idx));
323
-
340
+ await complete(autocompleteIndex));
324
341
 
325
342
  })().then(...resultArguments);
326
343
  }
@@ -334,4 +351,23 @@ const argumentsParser = (shell) => {
334
351
 
335
352
  };
336
353
 
354
+ argumentsParser.script = ({
355
+ shell = currentShell,
356
+ command
357
+ }) => {
358
+
359
+ const writer = supported[shell || currentShell];
360
+
361
+ if (!writer) {
362
+ process.stderr.write(`Unsupported shell: ${shell}\n`);
363
+ process.exit(1);
364
+ }
365
+
366
+ process.stdout.write(
367
+ writer.script({
368
+ command
369
+ }));
370
+
371
+ };
372
+
337
373
  export default argumentsParser;
@@ -6,7 +6,12 @@
6
6
  // See license in LICENSE.
7
7
  //
8
8
 
9
- export default (items) => {
9
+ import {
10
+ basename,
11
+ extname
12
+ } from 'path';
13
+
14
+ const zsh = (items) => {
10
15
 
11
16
  const keys = Object.keys(items);
12
17
 
@@ -49,3 +54,17 @@ export default (items) => {
49
54
  process.exit(0);
50
55
 
51
56
  };
57
+
58
+ zsh.script = ({
59
+ command
60
+ }) => `#compdef ${command}
61
+
62
+ _${command}() {
63
+ eval "$(AUTOCOMPLETE_INDEX=$CURRENT ${command} "\${words[@]}")"
64
+ }
65
+
66
+ _${command}`;
67
+
68
+ zsh.autocompleteIndexOffset = 2;
69
+
70
+ export default zsh;
package/lib/index.js CHANGED
@@ -6,7 +6,9 @@
6
6
  // See license in LICENSE.
7
7
  //
8
8
 
9
- import { basename } from 'path';
9
+ import {
10
+ basename
11
+ } from 'path';
10
12
 
11
13
  import caseit from '@trenskow/caseit';
12
14
  import { default as isvalid, merge, keyPaths } from 'isvalid';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trenskow/arguments-parser",
3
- "version": "0.3.130",
3
+ "version": "0.3.133",
4
4
  "description": "Yet another arguments parser.",
5
5
  "main": "index.js",
6
6
  "type": "module",