@@ -600,11 +600,14 @@ export class YargsParser {
600
600
601
601
function processValue ( key : string , val : any ) {
602
602
// strings may be quoted, clean this up as we assign values.
603
- if ( typeof val === 'string' &&
604
- ( val [ 0 ] === "'" || val [ 0 ] === '"' ) &&
605
- val [ val . length - 1 ] === val [ 0 ]
606
- ) {
607
- val = val . substring ( 1 , val . length - 1 )
603
+ if ( typeof val === 'string' ) {
604
+ if ( ( val [ 0 ] === "'" || val [ 0 ] === '"' ) &&
605
+ val [ val . length - 1 ] === val [ 0 ]
606
+ ) {
607
+ val = val . substring ( 1 , val . length - 1 )
608
+ } else if ( val . slice ( 0 , 2 ) === "$'" && val [ val . length - 1 ] === "'" ) {
609
+ val = parseAnsiCQuote ( val )
610
+ }
608
611
}
609
612
610
613
// handle parsing boolean arguments --foo=true --bar false.
@@ -629,6 +632,59 @@ export class YargsParser {
629
632
return value
630
633
}
631
634
635
+ // ANSI-C quoted string are a bash-only feature and have the form $'some text'
636
+ // https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html
637
+ function parseAnsiCQuote ( str : string ) : string {
638
+ function unescapeChar ( x : string ) : string {
639
+ switch ( x . slice ( 0 , 2 ) ) {
640
+ case '\\\\' :
641
+ return '\\'
642
+ case '\\a' :
643
+ return '\a' // eslint-disable-line
644
+ case '\\b' :
645
+ return '\b'
646
+ case '\\e' :
647
+ return '\u001b'
648
+ case '\\E' :
649
+ return '\u001b'
650
+ case '\\f' :
651
+ return '\f'
652
+ case '\\n' :
653
+ return '\n'
654
+ case '\\r' :
655
+ return '\r'
656
+ case '\\t' :
657
+ return '\t'
658
+ case '\\v' :
659
+ return '\v'
660
+ case "\\'" :
661
+ return "'"
662
+ case '\\"' :
663
+ return '"'
664
+ case '\\?' :
665
+ return '?'
666
+ case '\\c' :
667
+ // Control codes
668
+ // "\c1" -> 11, "\c2" -> 12 and so on
669
+ if ( x . match ( / \\ c [ 0 - 9 ] / ) ) {
670
+ return String . fromCharCode ( parseInt ( x . slice ( 2 ) , 10 ) + 16 )
671
+ }
672
+ // "\ca" -> 01, "\cb" -> 02 and so on
673
+ return String . fromCharCode ( x . toLowerCase ( ) . charCodeAt ( 2 ) - 'a' . charCodeAt ( 0 ) + 1 )
674
+ case '\\x' :
675
+ case '\\u' :
676
+ case '\\U' :
677
+ // Hexadecimal character literal
678
+ return String . fromCharCode ( parseInt ( x . slice ( 2 ) , 16 ) )
679
+ }
680
+ // Octal character literal
681
+ return String . fromCharCode ( parseInt ( x . slice ( 1 ) , 8 ) )
682
+ }
683
+
684
+ const ANSI_BACKSLASHES = / \\ ( \\ | a | b | e | E | f | n | r | t | v | ' | " | \? | [ 0 - 7 ] { 1 , 3 } | x [ 0 - 9 A - F a - f ] { 1 , 2 } | u [ 0 - 9 A - F a - f ] { 1 , 4 } | U [ 0 - 9 A - F a - f ] { 1 , 8 } | c [ 0 - 9 a - z A - Z ] ) / g
685
+ return str . slice ( 2 , - 1 ) . replace ( ANSI_BACKSLASHES , unescapeChar )
686
+ }
687
+
632
688
function maybeCoerceNumber ( key : string , value : string | number | null | undefined ) {
633
689
if ( ! configuration [ 'parse-positional-numbers' ] && key === '_' ) return value
634
690
if ( ! checkAllAliases ( key , flags . strings ) && ! checkAllAliases ( key , flags . bools ) && ! Array . isArray ( value ) ) {
0 commit comments