1'use strict'
2
3// eslint-disable-next-line max-len
4// this code adapted from: https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
5const cmd = (input, doubleEscape) => {
6  if (!input.length) {
7    return '""'
8  }
9
10  let result
11  if (!/[ \t\n\v"]/.test(input)) {
12    result = input
13  } else {
14    result = '"'
15    for (let i = 0; i <= input.length; ++i) {
16      let slashCount = 0
17      while (input[i] === '\\') {
18        ++i
19        ++slashCount
20      }
21
22      if (i === input.length) {
23        result += '\\'.repeat(slashCount * 2)
24        break
25      }
26
27      if (input[i] === '"') {
28        result += '\\'.repeat(slashCount * 2 + 1)
29        result += input[i]
30      } else {
31        result += '\\'.repeat(slashCount)
32        result += input[i]
33      }
34    }
35    result += '"'
36  }
37
38  // and finally, prefix shell meta chars with a ^
39  result = result.replace(/[ !%^&()<>|"]/g, '^$&')
40  if (doubleEscape) {
41    result = result.replace(/[ !%^&()<>|"]/g, '^$&')
42  }
43
44  return result
45}
46
47const sh = (input) => {
48  if (!input.length) {
49    return `''`
50  }
51
52  if (!/[\t\n\r "#$&'()*;<>?\\`|~]/.test(input)) {
53    return input
54  }
55
56  // replace single quotes with '\'' and wrap the whole result in a fresh set of quotes
57  const result = `'${input.replace(/'/g, `'\\''`)}'`
58    // if the input string already had single quotes around it, clean those up
59    .replace(/^(?:'')+(?!$)/, '')
60    .replace(/\\'''/g, `\\'`)
61
62  return result
63}
64
65module.exports = {
66  cmd,
67  sh,
68}
69