Skip to content

Commit

Permalink
feat: enhance support for multiline cmd args (#753)
Browse files Browse the repository at this point in the history
* feat: enhance support for multiline cmd args

closes #539

* chore: fix `raw` ref in tpl pieces normalizer

* chore: lint
  • Loading branch information
antongolub authored Mar 29, 2024
1 parent fe24b7a commit 9d5b3e4
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 6 deletions.
7 changes: 4 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"@types/node": ">=20.11.30",
"@types/which": "^3.0.3",
"@webpod/ps": "^0.0.0-beta.2",
"@webpod/ingrid": "^0.0.0-beta.3",
"c8": "^9.1.0",
"chalk": "^5.3.0",
"depseek": "^0.4.1",
Expand Down
4 changes: 2 additions & 2 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
formatCmd,
getCallerLocation,
noop,
normalizeMultilinePieces,
parseDuration,
quote,
quotePowerShell,
Expand Down Expand Up @@ -137,10 +138,9 @@ export const $: Shell & Options = new Proxy<Shell & Options>(
const promise = new ProcessPromise((...args) => ([resolve, reject] = args))
const cmd = buildCmd(
$.quote,
pieces as TemplateStringsArray,
normalizeMultilinePieces(pieces as TemplateStringsArray),
args
) as string

const snapshot = getStore()
const sync = snapshot[syncExec]
const callback = () => promise.isHalted || promise.run()
Expand Down
20 changes: 19 additions & 1 deletion src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { chalk } from './vendor.js'
import { chalk, parseLine } from './vendor.js'

export function noop() {}

Expand All @@ -24,6 +24,24 @@ export function isString(obj: any) {
return typeof obj === 'string'
}

export function normalizeMultilinePieces(
pieces: TemplateStringsArray
): TemplateStringsArray {
return Object.assign(
pieces.map((p, i) =>
p.trim()
? parseLine(p)
.words.map(({ w, e }) => {
if (w === '\\') return ''
return w.trim() + (p[e + 1] === ' ' ? ' ' : '')
})
.join(' ')
: pieces[i]
),
{ raw: pieces.raw }
)
}

export function quote(arg: string) {
if (/^[a-z0-9/_.\-@:=]+$/i.test(arg) || arg === '') {
return arg
Expand Down
1 change: 1 addition & 0 deletions src/vendor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,4 @@ export { default as chalk, type ChalkInstance } from 'chalk'
export { default as which } from 'which'
export { default as minimist } from 'minimist'
export { default as ps } from '@webpod/ps'
export { parseLine } from '@webpod/ingrid'
22 changes: 22 additions & 0 deletions test/core.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,28 @@ describe('core', () => {
assert.equal((await $`echo -n ${''}`).toString(), '')
})

test('handles multiline literals', async () => {
assert.equal(
(
await $`echo foo
bar
"baz
qux"
`
).toString(),
'foo bar baz\n qux\n'
)
assert.equal(
(
await $`echo foo \
bar \
baz \
`
).toString(),
'foo bar baz\n'
)
})

test('can create a dir with a space in the name', async () => {
let name = 'foo bar'
try {
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/js-project/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9d5b3e4

Please sign in to comment.