escape.js 1.5 KB

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