@optique/core 1.0.0-dev.1122 → 1.0.0-dev.1136

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.
@@ -114,17 +114,25 @@ function _${programName} () {
114
114
  # Generate file completions based on type
115
115
  case "$type" in
116
116
  file)
117
- # Complete files only
117
+ # Complete files and directories (directories for navigation)
118
118
  if [[ -n "$extensions" ]]; then
119
- # Complete with extension filtering
119
+ # Files with extension filtering + directories
120
120
  local ext_pattern="\${extensions//,/|}"
121
- for file in "$__glob_current"*; do
122
- [[ -f "$file" && "$file" =~ \\.($ext_pattern)$ ]] && COMPREPLY+=("$file")
121
+ for item in "$__glob_current"*; do
122
+ if [[ -d "$item" ]]; then
123
+ COMPREPLY+=("$item/")
124
+ elif [[ -f "$item" && "$item" =~ \\.($ext_pattern)$ ]]; then
125
+ COMPREPLY+=("$item")
126
+ fi
123
127
  done
124
128
  else
125
- # Complete files only, exclude directories
129
+ # Complete files and directories for navigation
126
130
  for item in "$__glob_current"*; do
127
- [[ -f "$item" ]] && COMPREPLY+=("$item")
131
+ if [[ -d "$item" ]]; then
132
+ COMPREPLY+=("$item/")
133
+ elif [[ -f "$item" ]]; then
134
+ COMPREPLY+=("$item")
135
+ fi
128
136
  done
129
137
  fi
130
138
  ;;
@@ -194,7 +202,7 @@ function _${programName} () {
194
202
  done < <(${programName} ${escapedArgs} "\${prev[@]}" "$current" 2>/dev/null)
195
203
  }
196
204
 
197
- complete -F _${programName} ${programName}
205
+ complete -F _${programName} -- ${programName}
198
206
  `;
199
207
  },
200
208
  *encodeSuggestions(suggestions) {
@@ -271,11 +279,11 @@ function _${programName.replace(/[^a-zA-Z0-9]/g, "_")} () {
271
279
  case "\$type" in
272
280
  file)
273
281
  if [[ -n "\$extensions" ]]; then
274
- # Complete files with extension filtering
282
+ # Complete files with extension filtering + directories for navigation
275
283
  local ext_pattern="*.(\$\{extensions//,/|\})"
276
- _files -g "\$ext_pattern"
284
+ _files -g "\$ext_pattern"; _directories
277
285
  else
278
- _files -g "*"
286
+ _files
279
287
  fi
280
288
  ;;
281
289
  directory)
@@ -285,7 +293,7 @@ function _${programName.replace(/[^a-zA-Z0-9]/g, "_")} () {
285
293
  if [[ -n "\$extensions" ]]; then
286
294
  # Complete both files and directories, with extension filtering for files
287
295
  local ext_pattern="*.(\$\{extensions//,/|\})"
288
- _files -g "\$ext_pattern" && _directories
296
+ _files -g "\$ext_pattern"; _directories
289
297
  else
290
298
  _files
291
299
  fi
@@ -375,9 +383,11 @@ ${escapedArgs ? ` set -l output (${programName} ${escapedArgs} $prev $current
375
383
  set -l items
376
384
  switch $type
377
385
  case file
378
- # Complete files only
386
+ # Complete files and directories (directories for navigation)
379
387
  for item in $current*
380
- if test -f $item
388
+ if test -d $item
389
+ set -a items $item/
390
+ else if test -f $item
381
391
  set -a items $item
382
392
  end
383
393
  end
@@ -390,7 +400,9 @@ ${escapedArgs ? ` set -l output (${programName} ${escapedArgs} $prev $current
390
400
  if test "$hidden" = "1"
391
401
  if test -z "$current"; or string match -q '*/' -- "$current"
392
402
  for item in $current.*
393
- if test -f $item
403
+ if test -d $item
404
+ set -a items $item/
405
+ else if test -f $item
394
406
  set -a items $item
395
407
  end
396
408
  end
@@ -630,13 +642,16 @@ ${escapedArgs ? ` ^${programName} ${escapedArgs} ...$final_args | complete |
630
642
  match $type {
631
643
  "file" => {
632
644
  if ($extensions | is-empty) {
633
- (if $hidden { ls -a $ls_pattern } else { ls $ls_pattern }) | where type == file
645
+ (if $hidden { ls -a $ls_pattern } else { ls $ls_pattern }) | where type == file or type == dir
634
646
  } else {
635
647
  let ext_list = ($extensions | split row ',')
636
- (if $hidden { ls -a $ls_pattern } else { ls $ls_pattern }) | where type == file | where {|f|
648
+ let all_items = (if $hidden { ls -a $ls_pattern } else { ls $ls_pattern })
649
+ let dirs = $all_items | where type == dir
650
+ let files = $all_items | where type == file | where {|f|
637
651
  let ext = ($f.name | path parse | get extension)
638
652
  $ext in $ext_list
639
653
  }
654
+ $dirs | append $files
640
655
  }
641
656
  },
642
657
  "directory" => {
@@ -647,8 +662,9 @@ ${escapedArgs ? ` ^${programName} ${escapedArgs} ...$final_args | complete |
647
662
  if $hidden { ls -a $ls_pattern } else { ls $ls_pattern }
648
663
  } else {
649
664
  let ext_list = ($extensions | split row ',')
650
- let dirs = (if $hidden { ls -a $ls_pattern } else { ls $ls_pattern }) | where type == dir
651
- let files = (if $hidden { ls -a $ls_pattern } else { ls $ls_pattern }) | where type == file | where {|f|
665
+ let all_items = (if $hidden { ls -a $ls_pattern } else { ls $ls_pattern })
666
+ let dirs = $all_items | where type == dir
667
+ let files = $all_items | where type == file | where {|f|
652
668
  let ext = ($f.name | path parse | get extension)
653
669
  $ext in $ext_list
654
670
  }
@@ -828,15 +844,16 @@ ${escapedArgs ? ` \$completionArgs += @(${escapedArgs})
828
844
  switch (\$type) {
829
845
  'file' {
830
846
  if (\$extensions) {
831
- # Filter by extensions
847
+ # Filter by extensions, always include directories
832
848
  \$extList = \$extensions -split ','
833
- \$items = Get-ChildItem @forceParam -File -Path "\${prefix}*" -ErrorAction SilentlyContinue |
849
+ \$items = Get-ChildItem @forceParam -Path "\${prefix}*" -ErrorAction SilentlyContinue |
834
850
  Where-Object {
851
+ if (\$_.PSIsContainer) { return \$true }
835
852
  \$ext = \$_.Extension
836
853
  \$extList | ForEach-Object { if (\$ext -eq ".\$_") { return \$true } }
837
854
  }
838
855
  } else {
839
- \$items = Get-ChildItem @forceParam -File -Path "\${prefix}*" -ErrorAction SilentlyContinue
856
+ \$items = Get-ChildItem @forceParam -Path "\${prefix}*" -ErrorAction SilentlyContinue
840
857
  }
841
858
  }
842
859
  'directory' {
@@ -844,15 +861,14 @@ ${escapedArgs ? ` \$completionArgs += @(${escapedArgs})
844
861
  }
845
862
  'any' {
846
863
  if (\$extensions) {
847
- # Get directories and filtered files
848
- \$dirs = Get-ChildItem @forceParam -Directory -Path "\${prefix}*" -ErrorAction SilentlyContinue
864
+ # Filter by extensions, always include directories
849
865
  \$extList = \$extensions -split ','
850
- \$files = Get-ChildItem @forceParam -File -Path "\${prefix}*" -ErrorAction SilentlyContinue |
866
+ \$items = Get-ChildItem @forceParam -Path "\${prefix}*" -ErrorAction SilentlyContinue |
851
867
  Where-Object {
868
+ if (\$_.PSIsContainer) { return \$true }
852
869
  \$ext = \$_.Extension
853
870
  \$extList | ForEach-Object { if (\$ext -eq ".\$_") { return \$true } }
854
871
  }
855
- \$items = \$dirs + \$files
856
872
  } else {
857
873
  \$items = Get-ChildItem @forceParam -Path "\${prefix}*" -ErrorAction SilentlyContinue
858
874
  }
@@ -114,17 +114,25 @@ function _${programName} () {
114
114
  # Generate file completions based on type
115
115
  case "$type" in
116
116
  file)
117
- # Complete files only
117
+ # Complete files and directories (directories for navigation)
118
118
  if [[ -n "$extensions" ]]; then
119
- # Complete with extension filtering
119
+ # Files with extension filtering + directories
120
120
  local ext_pattern="\${extensions//,/|}"
121
- for file in "$__glob_current"*; do
122
- [[ -f "$file" && "$file" =~ \\.($ext_pattern)$ ]] && COMPREPLY+=("$file")
121
+ for item in "$__glob_current"*; do
122
+ if [[ -d "$item" ]]; then
123
+ COMPREPLY+=("$item/")
124
+ elif [[ -f "$item" && "$item" =~ \\.($ext_pattern)$ ]]; then
125
+ COMPREPLY+=("$item")
126
+ fi
123
127
  done
124
128
  else
125
- # Complete files only, exclude directories
129
+ # Complete files and directories for navigation
126
130
  for item in "$__glob_current"*; do
127
- [[ -f "$item" ]] && COMPREPLY+=("$item")
131
+ if [[ -d "$item" ]]; then
132
+ COMPREPLY+=("$item/")
133
+ elif [[ -f "$item" ]]; then
134
+ COMPREPLY+=("$item")
135
+ fi
128
136
  done
129
137
  fi
130
138
  ;;
@@ -194,7 +202,7 @@ function _${programName} () {
194
202
  done < <(${programName} ${escapedArgs} "\${prev[@]}" "$current" 2>/dev/null)
195
203
  }
196
204
 
197
- complete -F _${programName} ${programName}
205
+ complete -F _${programName} -- ${programName}
198
206
  `;
199
207
  },
200
208
  *encodeSuggestions(suggestions) {
@@ -271,11 +279,11 @@ function _${programName.replace(/[^a-zA-Z0-9]/g, "_")} () {
271
279
  case "\$type" in
272
280
  file)
273
281
  if [[ -n "\$extensions" ]]; then
274
- # Complete files with extension filtering
282
+ # Complete files with extension filtering + directories for navigation
275
283
  local ext_pattern="*.(\$\{extensions//,/|\})"
276
- _files -g "\$ext_pattern"
284
+ _files -g "\$ext_pattern"; _directories
277
285
  else
278
- _files -g "*"
286
+ _files
279
287
  fi
280
288
  ;;
281
289
  directory)
@@ -285,7 +293,7 @@ function _${programName.replace(/[^a-zA-Z0-9]/g, "_")} () {
285
293
  if [[ -n "\$extensions" ]]; then
286
294
  # Complete both files and directories, with extension filtering for files
287
295
  local ext_pattern="*.(\$\{extensions//,/|\})"
288
- _files -g "\$ext_pattern" && _directories
296
+ _files -g "\$ext_pattern"; _directories
289
297
  else
290
298
  _files
291
299
  fi
@@ -375,9 +383,11 @@ ${escapedArgs ? ` set -l output (${programName} ${escapedArgs} $prev $current
375
383
  set -l items
376
384
  switch $type
377
385
  case file
378
- # Complete files only
386
+ # Complete files and directories (directories for navigation)
379
387
  for item in $current*
380
- if test -f $item
388
+ if test -d $item
389
+ set -a items $item/
390
+ else if test -f $item
381
391
  set -a items $item
382
392
  end
383
393
  end
@@ -390,7 +400,9 @@ ${escapedArgs ? ` set -l output (${programName} ${escapedArgs} $prev $current
390
400
  if test "$hidden" = "1"
391
401
  if test -z "$current"; or string match -q '*/' -- "$current"
392
402
  for item in $current.*
393
- if test -f $item
403
+ if test -d $item
404
+ set -a items $item/
405
+ else if test -f $item
394
406
  set -a items $item
395
407
  end
396
408
  end
@@ -630,13 +642,16 @@ ${escapedArgs ? ` ^${programName} ${escapedArgs} ...$final_args | complete |
630
642
  match $type {
631
643
  "file" => {
632
644
  if ($extensions | is-empty) {
633
- (if $hidden { ls -a $ls_pattern } else { ls $ls_pattern }) | where type == file
645
+ (if $hidden { ls -a $ls_pattern } else { ls $ls_pattern }) | where type == file or type == dir
634
646
  } else {
635
647
  let ext_list = ($extensions | split row ',')
636
- (if $hidden { ls -a $ls_pattern } else { ls $ls_pattern }) | where type == file | where {|f|
648
+ let all_items = (if $hidden { ls -a $ls_pattern } else { ls $ls_pattern })
649
+ let dirs = $all_items | where type == dir
650
+ let files = $all_items | where type == file | where {|f|
637
651
  let ext = ($f.name | path parse | get extension)
638
652
  $ext in $ext_list
639
653
  }
654
+ $dirs | append $files
640
655
  }
641
656
  },
642
657
  "directory" => {
@@ -647,8 +662,9 @@ ${escapedArgs ? ` ^${programName} ${escapedArgs} ...$final_args | complete |
647
662
  if $hidden { ls -a $ls_pattern } else { ls $ls_pattern }
648
663
  } else {
649
664
  let ext_list = ($extensions | split row ',')
650
- let dirs = (if $hidden { ls -a $ls_pattern } else { ls $ls_pattern }) | where type == dir
651
- let files = (if $hidden { ls -a $ls_pattern } else { ls $ls_pattern }) | where type == file | where {|f|
665
+ let all_items = (if $hidden { ls -a $ls_pattern } else { ls $ls_pattern })
666
+ let dirs = $all_items | where type == dir
667
+ let files = $all_items | where type == file | where {|f|
652
668
  let ext = ($f.name | path parse | get extension)
653
669
  $ext in $ext_list
654
670
  }
@@ -828,15 +844,16 @@ ${escapedArgs ? ` \$completionArgs += @(${escapedArgs})
828
844
  switch (\$type) {
829
845
  'file' {
830
846
  if (\$extensions) {
831
- # Filter by extensions
847
+ # Filter by extensions, always include directories
832
848
  \$extList = \$extensions -split ','
833
- \$items = Get-ChildItem @forceParam -File -Path "\${prefix}*" -ErrorAction SilentlyContinue |
849
+ \$items = Get-ChildItem @forceParam -Path "\${prefix}*" -ErrorAction SilentlyContinue |
834
850
  Where-Object {
851
+ if (\$_.PSIsContainer) { return \$true }
835
852
  \$ext = \$_.Extension
836
853
  \$extList | ForEach-Object { if (\$ext -eq ".\$_") { return \$true } }
837
854
  }
838
855
  } else {
839
- \$items = Get-ChildItem @forceParam -File -Path "\${prefix}*" -ErrorAction SilentlyContinue
856
+ \$items = Get-ChildItem @forceParam -Path "\${prefix}*" -ErrorAction SilentlyContinue
840
857
  }
841
858
  }
842
859
  'directory' {
@@ -844,15 +861,14 @@ ${escapedArgs ? ` \$completionArgs += @(${escapedArgs})
844
861
  }
845
862
  'any' {
846
863
  if (\$extensions) {
847
- # Get directories and filtered files
848
- \$dirs = Get-ChildItem @forceParam -Directory -Path "\${prefix}*" -ErrorAction SilentlyContinue
864
+ # Filter by extensions, always include directories
849
865
  \$extList = \$extensions -split ','
850
- \$files = Get-ChildItem @forceParam -File -Path "\${prefix}*" -ErrorAction SilentlyContinue |
866
+ \$items = Get-ChildItem @forceParam -Path "\${prefix}*" -ErrorAction SilentlyContinue |
851
867
  Where-Object {
868
+ if (\$_.PSIsContainer) { return \$true }
852
869
  \$ext = \$_.Extension
853
870
  \$extList | ForEach-Object { if (\$ext -eq ".\$_") { return \$true } }
854
871
  }
855
- \$items = \$dirs + \$files
856
872
  } else {
857
873
  \$items = Get-ChildItem @forceParam -Path "\${prefix}*" -ErrorAction SilentlyContinue
858
874
  }
package/dist/facade.cjs CHANGED
@@ -710,6 +710,23 @@ function handleCompletion(completionArgs, programName, parser, completionParser,
710
710
  return callOnCompletion(0);
711
711
  });
712
712
  }
713
+ /**
714
+ * Validates the configured version value.
715
+ *
716
+ * @param value Runtime version value from configuration.
717
+ * @returns The validated version string.
718
+ * @throws {TypeError} If the value is not a string, is empty, or contains
719
+ * ASCII control characters.
720
+ */
721
+ function validateVersionValue(value$1) {
722
+ if (typeof value$1 !== "string") {
723
+ const type = Array.isArray(value$1) ? "array" : typeof value$1;
724
+ throw new TypeError(`Expected version value to be a string, but got ${type}.`);
725
+ }
726
+ if (value$1 === "") throw new TypeError("Version value must not be empty.");
727
+ if (/[\x00-\x1f\x7f]/.test(value$1)) throw new TypeError("Version value must not contain control characters.");
728
+ return value$1;
729
+ }
713
730
  function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsParam) {
714
731
  const isProgram = typeof programNameOrArgs !== "string";
715
732
  let parser;
@@ -746,7 +763,7 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
746
763
  const onHelp = options.help?.onShow ?? (() => ({}));
747
764
  const versionCommandConfig = norm(options.version?.command);
748
765
  const versionOptionConfig = norm(options.version?.option);
749
- const versionValue = options.version?.value ?? "";
766
+ const versionValue = options.version ? validateVersionValue(options.version.value) : void 0;
750
767
  const onVersion = options.version?.onShow ?? (() => ({}));
751
768
  const completionCommandConfig = norm(options.completion?.command);
752
769
  const completionOptionConfig = norm(options.completion?.option);
package/dist/facade.d.cts CHANGED
@@ -272,6 +272,8 @@ interface RunOptions<THelp, TError> {
272
272
  * @param options Configuration options for output formatting and callbacks.
273
273
  * @returns The parsed result value, or the return value of `onHelp`/`onError`
274
274
  * callbacks.
275
+ * @throws {TypeError} If `options.version.value` is not a non-empty string
276
+ * without ASCII control characters.
275
277
  * @throws {RunParserError} When parsing fails and no `onError` callback is
276
278
  * provided.
277
279
  * @since 0.10.0 Added support for {@link Program} objects.
package/dist/facade.d.ts CHANGED
@@ -272,6 +272,8 @@ interface RunOptions<THelp, TError> {
272
272
  * @param options Configuration options for output formatting and callbacks.
273
273
  * @returns The parsed result value, or the return value of `onHelp`/`onError`
274
274
  * callbacks.
275
+ * @throws {TypeError} If `options.version.value` is not a non-empty string
276
+ * without ASCII control characters.
275
277
  * @throws {RunParserError} When parsing fails and no `onError` callback is
276
278
  * provided.
277
279
  * @since 0.10.0 Added support for {@link Program} objects.
package/dist/facade.js CHANGED
@@ -710,6 +710,23 @@ function handleCompletion(completionArgs, programName, parser, completionParser,
710
710
  return callOnCompletion(0);
711
711
  });
712
712
  }
713
+ /**
714
+ * Validates the configured version value.
715
+ *
716
+ * @param value Runtime version value from configuration.
717
+ * @returns The validated version string.
718
+ * @throws {TypeError} If the value is not a string, is empty, or contains
719
+ * ASCII control characters.
720
+ */
721
+ function validateVersionValue(value$1) {
722
+ if (typeof value$1 !== "string") {
723
+ const type = Array.isArray(value$1) ? "array" : typeof value$1;
724
+ throw new TypeError(`Expected version value to be a string, but got ${type}.`);
725
+ }
726
+ if (value$1 === "") throw new TypeError("Version value must not be empty.");
727
+ if (/[\x00-\x1f\x7f]/.test(value$1)) throw new TypeError("Version value must not contain control characters.");
728
+ return value$1;
729
+ }
713
730
  function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsParam) {
714
731
  const isProgram = typeof programNameOrArgs !== "string";
715
732
  let parser;
@@ -746,7 +763,7 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
746
763
  const onHelp = options.help?.onShow ?? (() => ({}));
747
764
  const versionCommandConfig = norm(options.version?.command);
748
765
  const versionOptionConfig = norm(options.version?.option);
749
- const versionValue = options.version?.value ?? "";
766
+ const versionValue = options.version ? validateVersionValue(options.version.value) : void 0;
750
767
  const onVersion = options.version?.onShow ?? (() => ({}));
751
768
  const completionCommandConfig = norm(options.completion?.command);
752
769
  const completionOptionConfig = norm(options.completion?.option);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.0.0-dev.1122+85e536cf",
3
+ "version": "1.0.0-dev.1136+00dc9aa5",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",