index.js 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. 'use strict';
  2. const path = require('path');
  3. const childProcess = require('child_process');
  4. const isWsl = require('is-wsl');
  5. module.exports = (target, opts) => {
  6. if (typeof target !== 'string') {
  7. return Promise.reject(new Error('Expected a `target`'));
  8. }
  9. opts = Object.assign({wait: true}, opts);
  10. let cmd;
  11. let appArgs = [];
  12. let args = [];
  13. const cpOpts = {};
  14. if (Array.isArray(opts.app)) {
  15. appArgs = opts.app.slice(1);
  16. opts.app = opts.app[0];
  17. }
  18. if (process.platform === 'darwin') {
  19. cmd = 'open';
  20. if (opts.wait) {
  21. args.push('-W');
  22. }
  23. if (opts.app) {
  24. args.push('-a', opts.app);
  25. }
  26. } else if (process.platform === 'win32' || isWsl) {
  27. cmd = 'cmd' + (isWsl ? '.exe' : '');
  28. args.push('/c', 'start', '""', '/b');
  29. target = target.replace(/&/g, '^&');
  30. if (opts.wait) {
  31. args.push('/wait');
  32. }
  33. if (opts.app) {
  34. args.push(opts.app);
  35. }
  36. if (appArgs.length > 0) {
  37. args = args.concat(appArgs);
  38. }
  39. } else {
  40. if (opts.app) {
  41. cmd = opts.app;
  42. } else {
  43. cmd = process.platform === 'android' ? 'xdg-open' : path.join(__dirname, 'xdg-open');
  44. }
  45. if (appArgs.length > 0) {
  46. args = args.concat(appArgs);
  47. }
  48. if (!opts.wait) {
  49. // `xdg-open` will block the process unless
  50. // stdio is ignored and it's detached from the parent
  51. // even if it's unref'd
  52. cpOpts.stdio = 'ignore';
  53. cpOpts.detached = true;
  54. }
  55. }
  56. args.push(target);
  57. if (process.platform === 'darwin' && appArgs.length > 0) {
  58. args.push('--args');
  59. args = args.concat(appArgs);
  60. }
  61. const cp = childProcess.spawn(cmd, args, cpOpts);
  62. if (opts.wait) {
  63. return new Promise((resolve, reject) => {
  64. cp.once('error', reject);
  65. cp.once('close', code => {
  66. if (code > 0) {
  67. reject(new Error('Exited with code ' + code));
  68. return;
  69. }
  70. resolve(cp);
  71. });
  72. });
  73. }
  74. cp.unref();
  75. return Promise.resolve(cp);
  76. };