@@ -3,7 +3,6 @@ const {promisify} = require('util');
33const path = require ( 'path' ) ;
44const childProcess = require ( 'child_process' ) ;
55const fs = require ( 'fs' ) ;
6- const url = require ( 'url' ) ;
76const isWsl = require ( 'is-wsl' ) ;
87const isDocker = require ( 'is-docker' ) ;
98
@@ -28,30 +27,19 @@ module.exports = async (target, options) => {
2827 options = {
2928 wait : false ,
3029 background : false ,
31- url : false ,
3230 allowNonzeroExitCode : false ,
3331 ...options
3432 } ;
3533
3634 let command ;
35+ let app ;
3736 let appArguments = [ ] ;
3837 const cliArguments = [ ] ;
3938 const childProcessOptions = { } ;
4039
4140 if ( Array . isArray ( options . app ) ) {
4241 appArguments = options . app . slice ( 1 ) ;
43- options . app = options . app [ 0 ] ;
44- }
45-
46- // Encodes the target as if it were an URL. Especially useful to get
47- // double-quotes through the “double-quotes on Windows caveat”, but it
48- // can be used on any platform.
49- if ( options . url ) {
50- target = new url . URL ( target ) . href ;
51-
52- if ( isWsl ) {
53- target = target . replace ( / & / g, '^&' ) ;
54- }
42+ app = options . app [ 0 ] ;
5543 }
5644
5745 if ( process . platform === 'darwin' ) {
@@ -65,49 +53,53 @@ module.exports = async (target, options) => {
6553 cliArguments . push ( '--background' ) ;
6654 }
6755
68- if ( options . app ) {
69- cliArguments . push ( '-a' , options . app ) ;
56+ if ( app ) {
57+ cliArguments . push ( '-a' , app ) ;
7058 }
7159 } else if ( process . platform === 'win32' || ( isWsl && ! isDocker ( ) ) ) {
72- command = 'cmd' + ( isWsl ? '.exe' : '' ) ;
73- cliArguments . push ( '/s' , '/c' , 'start' , '""' , '/b' ) ;
60+ command = 'powershell' + ( isWsl ? '.exe' : '' ) ;
61+ cliArguments . push (
62+ '-NoProfile' ,
63+ '-NonInteractive' ,
64+ '–ExecutionPolicy' ,
65+ 'Bypass' ,
66+ '-EncodedCommand'
67+ ) ;
7468
7569 if ( ! isWsl ) {
76- // Always quoting target allows for URLs/paths to have spaces and unmarked characters, as `cmd.exe` will
77- // interpret them as plain text to be forwarded as one unique argument. Enabling `windowsVerbatimArguments`
78- // disables Node.js's default quotes and escapes handling (https://git.io/fjdem).
79- // References:
80- // - Issues #17, #44, #55, #77, #101, #115
81- // - Pull requests: #74, #98
82- //
83- // As a result, all double-quotes are stripped from the `target` and do not get to your desired destination.
84- target = `"${ target } "` ;
8570 childProcessOptions . windowsVerbatimArguments = true ;
86-
87- if ( options . app ) {
88- options . app = `"${ options . app } "` ;
89- }
9071 }
9172
73+ const encodedArguments = [ 'Start' ] ;
74+
9275 if ( options . wait ) {
93- cliArguments . push ( '/wait ' ) ;
76+ encodedArguments . push ( '-Wait ' ) ;
9477 }
9578
96- if ( options . app ) {
97- if ( isWsl && options . app . startsWith ( '/mnt/' ) ) {
98- const windowsPath = await wslToWindowsPath ( options . app ) ;
99- options . app = windowsPath ;
79+ if ( app ) {
80+ if ( isWsl && app . startsWith ( '/mnt/' ) ) {
81+ const windowsPath = await wslToWindowsPath ( app ) ;
82+ app = windowsPath ;
10083 }
10184
102- cliArguments . push ( options . app ) ;
85+ // Double quote with double quotes to ensure the inner quotes are passed through.
86+ // Inner quotes are delimited for PowerShell interpretation with backticks.
87+ encodedArguments . push ( `"\`"${ app } \`""` , '-ArgumentList' ) ;
88+ appArguments . unshift ( target ) ;
89+ } else {
90+ encodedArguments . push ( `"\`"${ target } \`""` ) ;
10391 }
10492
10593 if ( appArguments . length > 0 ) {
106- cliArguments . push ( ...appArguments ) ;
94+ appArguments = appArguments . map ( arg => `"\`"${ arg } \`""` ) ;
95+ encodedArguments . push ( appArguments . join ( ',' ) ) ;
10796 }
97+
98+ // Using Base64-encoded command, accepted by PowerShell, to allow special characters.
99+ target = Buffer . from ( encodedArguments . join ( ' ' ) , 'utf16le' ) . toString ( 'base64' ) ;
108100 } else {
109- if ( options . app ) {
110- command = options . app ;
101+ if ( app ) {
102+ command = app ;
111103 } else {
112104 // When bundled by Webpack, there's no actual package file path and no local `xdg-open`.
113105 const isBundled = ! __dirname || __dirname === '/' ;
0 commit comments