@@ -49,6 +49,27 @@ test('parse shell commands', function (t) {
4949 t . end ( ) ;
5050} ) ;
5151
52+ test ( 'single quotes are literal' , function ( t ) {
53+ t . same ( parse ( "'\\'\\'" ) , [ "\\'" ] , 'close-escape-reopen produces a quote after a quoted backslash' ) ;
54+ t . same ( parse ( "'a'\\''b'" ) , [ "a'b" ] , 'close-escape-reopen embeds a quote mid-word' ) ;
55+ t . same ( parse ( "'\\'x" ) , [ '\\x' ] , 'bareword joins a preceding quoted backslash' ) ;
56+ t . same ( parse ( "a'\\'b" ) , [ 'a\\b' ] , 'quoted backslash joins surrounding barewords' ) ;
57+ t . same ( parse ( "''" ) , [ '' ] , 'empty single quotes produce an empty token' ) ;
58+ t . same ( parse ( "''a''" ) , [ 'a' ] , 'empty single quotes join adjacent content' ) ;
59+ t . same ( parse ( "'*'" ) , [ '*' ] , 'quoted glob char is a plain string, not a glob' ) ;
60+
61+ t . end ( ) ;
62+ } ) ;
63+
64+ test ( 'unmatched single quotes' , function ( t ) {
65+ // real shells reject unterminated quotes; parse is lenient, and these pin the shape of that leniency
66+ t . same ( parse ( "'" ) , [ ] , 'a lone quote is dropped' ) ;
67+ t . same ( parse ( "'a" ) , [ 'a' ] , 'an unterminated quote keeps its content' ) ;
68+ t . same ( parse ( "a'b" ) , [ 'a' , 'b' ] , 'an unmatched quote mid-word splits the token' ) ;
69+
70+ t . end ( ) ;
71+ } ) ;
72+
5273test ( 'parse stays linear in token count (GHSA-395f-4hp3-45gv)' , function ( t ) {
5374 // the old concat-in-reduce finalizer was O(n^2): this many tokens took
5475 // ~minutes, so under the unfixed code this test hangs rather than passes
0 commit comments