Commit eff2d70

Anton Golub <antongolub@antongolub.com>
2025-03-01 18:13:33
fix: enhance quote to handle empty args (#1113)
closes #999 closes #1112
1 parent f4b0328
src/cli.ts
@@ -31,7 +31,7 @@ import {
 } from './index.ts'
 import { installDeps, parseDeps } from './deps.ts'
 import { startRepl } from './repl.ts'
-import { randomId, bufToString } from './util.ts'
+import { randomId } from './util.ts'
 import { transformMarkdown } from './md.ts'
 import { createRequire, type minimist } from './vendor.ts'
 
src/util.ts
@@ -123,9 +123,9 @@ export function preferLocalBin(
 // }
 
 export function quote(arg: string): string {
-  if (/^[\w/.\-@:=]+$/.test(arg) || arg === '') {
-    return arg
-  }
+  if (arg === '') return `$''`
+  if (/^[\w/.\-@:=]+$/.test(arg)) return arg
+
   return (
     `$'` +
     arg
@@ -142,9 +142,9 @@ export function quote(arg: string): string {
 }
 
 export function quotePowerShell(arg: string): string {
-  if (/^[\w/.\-]+$/.test(arg) || arg === '') {
-    return arg
-  }
+  if (arg === '') return `''`
+  if (/^[\w/.\-]+$/.test(arg)) return arg
+
   return `'` + arg.replace(/'/g, "''") + `'`
 }
 
test/core.test.js
@@ -156,8 +156,14 @@ describe('core', () => {
     })
 
     test('can use array as an argument', async () => {
-      const args = ['-n', 'foo']
-      assert.equal((await $`echo ${args}`).toString(), 'foo')
+      const _$ = $({ prefix: '', postfix: '' })
+      const p1 = _$`echo ${['-n', 'foo']}`
+      assert.equal(p1.cmd, 'echo -n foo')
+      assert.equal((await p1).toString(), 'foo')
+
+      const p2 = _$`echo ${[1, '', '*', '2']}`
+      assert.equal(p2.cmd, `echo 1 $'' $'*' 2`)
+      assert.equal((await p2).toString(), `1  * 2\n`)
     })
 
     test('requires $.shell to be specified', async () => {
test/util.test.js
@@ -62,12 +62,14 @@ describe('util', () => {
 
   test('quote()', () => {
     assert.ok(quote('string') === 'string')
+    assert.ok(quote('') === `$''`)
     assert.ok(quote(`'\f\n\r\t\v\0`) === `$'\\'\\f\\n\\r\\t\\v\\0'`)
   })
 
   test('quotePowerShell()', () => {
     assert.equal(quotePowerShell('string'), 'string')
     assert.equal(quotePowerShell(`'`), `''''`)
+    assert.equal(quotePowerShell(''), `''`)
   })
 
   test('duration parsing works', () => {
.size-limit.json
@@ -30,7 +30,7 @@
   {
     "name": "all",
     "path": "build/*",
-    "limit": "850.25 kB",
+    "limit": "850.3 kB",
     "brotli": false,
     "gzip": false
   }
package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "zx",
-  "version": "8.4.0",
+  "version": "8.3.3",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "zx",
-      "version": "8.4.0",
+      "version": "8.3.3",
       "license": "Apache-2.0",
       "bin": {
         "zx": "build/cli.js"
package.json
@@ -1,6 +1,6 @@
 {
   "name": "zx",
-  "version": "8.4.0",
+  "version": "8.3.3",
   "description": "A tool for writing better scripts",
   "type": "module",
   "main": "./build/index.cjs",