@sap/cds-dk 4.6.4 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -1
- package/bin/activate.js +5 -1
- package/bin/add.js +2 -1
- package/bin/bind.js +121 -48
- package/bin/cds.js +8 -0
- package/bin/env.js +0 -2
- package/bin/repl.js +5 -2
- package/bin/watch.js +10 -7
- package/lib/bind/bindingResolver.js +26 -14
- package/lib/bind/bindingUtil.js +144 -0
- package/lib/bind/cfKeyProvider.js +2 -80
- package/lib/bind/kubernetesCredentialsProvider.js +157 -0
- package/lib/bind/userCdsrcJsonStorageProvider.js +7 -7
- package/lib/client/activate.js +16 -13
- package/lib/client/base_command.js +5 -1
- package/lib/client/helper/cf_helper.js +5 -2
- package/lib/client/params.js +16 -2
- package/lib/client/settings_manager.js +15 -8
- package/lib/compile/openapi/csdl2openapi.js +6 -8
- package/lib/compile/to-xsuaa.js +0 -14
- package/lib/import/utils/MetadataConverter.js +6 -4
- package/lib/import/utils/MultiMap.js +1 -0
- package/lib/import/v2parser.js +150 -64
- package/lib/import/v4parser.js +118 -56
- package/lib/index.js +6 -5
- package/lib/init/constants.js +11 -5
- package/lib/init/index.js +14 -7
- package/lib/init/template/_merging/existences.js +161 -0
- package/lib/init/template/approuter/files/default-env.json +9 -0
- package/lib/init/template/approuter/files/mta.yaml.hbs +48 -0
- package/lib/init/template/approuter/files/package.json +9 -0
- package/lib/init/template/approuter/files/xs-app.json +8 -0
- package/lib/init/template/approuter/index.js +66 -0
- package/lib/init/template/auditlog/files/dependencies.package.json +5 -0
- package/lib/init/template/auditlog/files/mta.yaml.hbs +13 -0
- package/lib/init/template/auditlog/index.js +38 -0
- package/lib/init/template/cf-manifest/index.js +1 -1
- package/lib/init/template/data/index.js +18 -6
- package/lib/init/template/hana/files/common/undeploy.json +5 -0
- package/lib/init/template/hana/files/java/package.json +3 -0
- package/lib/init/template/hana/files/mta.yaml.hbs +42 -0
- package/lib/init/template/hana/files/nodejs/dependencies.package.json +5 -0
- package/lib/init/template/hana/index.js +53 -24
- package/lib/init/template/java/index.js +1 -5
- package/lib/init/template/lint/index.js +17 -1
- package/lib/init/template/mta/files/mta.yaml.hbs +27 -216
- package/lib/init/template/mta/index.js +25 -17
- package/lib/init/template/mtx/files/cds.package.json +24 -0
- package/lib/init/template/mtx/files/dependencies.package.json +5 -0
- package/lib/init/template/mtx/files/mta.yaml.hbs +74 -0
- package/lib/init/template/mtx/files/xs-security.json.hbs +23 -9
- package/lib/init/template/mtx/index.js +126 -29
- package/lib/init/template/templateBase.js +14 -0
- package/lib/init/template/xsuaa/files/cds.package.json +9 -0
- package/lib/init/template/xsuaa/files/dependencies.package.json +6 -0
- package/lib/init/template/xsuaa/files/mta.yaml.hbs +17 -0
- package/lib/init/template/xsuaa/index.js +75 -0
- package/lib/init/util/fsUtil.js +18 -4
- package/lib/init/util/logger.js +3 -1
- package/lib/init/util/mvnArchetypeUtil.js +3 -1
- package/lib/init/{template/mta → util}/projectReader.js +26 -11
- package/lib/init/util/templateUtil.js +267 -3
- package/lib/lint/Linter.js +1 -2
- package/lib/lint/io.js +3 -12
- package/lib/util/exec.d.ts +54 -0
- package/lib/util/exec.js +210 -0
- package/lib/watch/livereload-server.js +43 -31
- package/lib/watch/node-watch.js +46 -20
- package/lib/watch/open.js +1 -1
- package/npm-shrinkwrap.json +3382 -9106
- package/package.json +8 -9
- package/readme.md +1 -1
- package/lib/init/template/mtx/package/cds.package.json +0 -29
- package/lib/init/template/mtx/package/dependencies.package.json +0 -9
package/lib/util/exec.js
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
const { spawn, spawnSync } = require('child_process');
|
|
2
|
+
|
|
3
|
+
const cds = require('@sap/cds/lib');
|
|
4
|
+
const log = cds.log('exec');
|
|
5
|
+
|
|
6
|
+
function* commandIterator(strs, ...args) {
|
|
7
|
+
for (let i=0; i<strs.length; i++) {
|
|
8
|
+
const str = strs[i];
|
|
9
|
+
const regex = /((\s+)|(["'])|$)/g;
|
|
10
|
+
let match;
|
|
11
|
+
let lastIndex = 0;
|
|
12
|
+
do {
|
|
13
|
+
match = regex.exec(str);
|
|
14
|
+
if (match.index > lastIndex) {
|
|
15
|
+
yield { type: 'WORD', value: str.substr(lastIndex, match.index - lastIndex) };
|
|
16
|
+
}
|
|
17
|
+
if (match[2]) {
|
|
18
|
+
yield { type: 'SPACE', value: match[2] };
|
|
19
|
+
}
|
|
20
|
+
if (match[3]) {
|
|
21
|
+
yield { type: 'QUOTE', value: match[3] }
|
|
22
|
+
}
|
|
23
|
+
lastIndex = match.index + match[0].length;
|
|
24
|
+
} while (lastIndex < str.length);
|
|
25
|
+
|
|
26
|
+
if (args[i]) {
|
|
27
|
+
if (Array.isArray(args[i])) {
|
|
28
|
+
let sep = false;
|
|
29
|
+
for (const value of args[i]) {
|
|
30
|
+
if (sep) yield { type: 'SPACE', value: ' '};
|
|
31
|
+
yield { type: 'WORD', value };
|
|
32
|
+
sep = true;
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
yield { type: 'WORD', value: args[i] };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function processTemplate(strs, args) {
|
|
42
|
+
let quote;
|
|
43
|
+
const result = [];
|
|
44
|
+
let index = 0;
|
|
45
|
+
|
|
46
|
+
const append = str => result[index] = (result[index] || '') + str;
|
|
47
|
+
const push = () => { if (index < result.length) index++; };
|
|
48
|
+
|
|
49
|
+
for (const token of commandIterator(strs, args)) {
|
|
50
|
+
switch (token.type) {
|
|
51
|
+
case 'WORD':
|
|
52
|
+
append(token.value);
|
|
53
|
+
break;
|
|
54
|
+
case 'SPACE':
|
|
55
|
+
if (quote) {
|
|
56
|
+
append(token.value);
|
|
57
|
+
} else {
|
|
58
|
+
push();
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
case 'QUOTE':
|
|
62
|
+
if (quote === token.value) {
|
|
63
|
+
quote = undefined;
|
|
64
|
+
} else if (quote) {
|
|
65
|
+
append(token.value);
|
|
66
|
+
} else {
|
|
67
|
+
quote = token.value;
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function fetchOptions(cmd) {
|
|
77
|
+
const { options, args } = cmd;
|
|
78
|
+
if (typeof args[0] === 'object' && !Array.isArray(args[0])) {
|
|
79
|
+
const newOptions = args[0];
|
|
80
|
+
cmd.options = {...options, ...newOptions};
|
|
81
|
+
cmd.args = args.slice(1);
|
|
82
|
+
return true;
|
|
83
|
+
} else {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function exec_func(...args) {
|
|
89
|
+
const cmd = { options: {
|
|
90
|
+
log,
|
|
91
|
+
acceptStatuses: [ 0 ],
|
|
92
|
+
stdio: 'inherit',
|
|
93
|
+
shell: false,
|
|
94
|
+
encoding: 'utf-8'
|
|
95
|
+
}, args };
|
|
96
|
+
|
|
97
|
+
let hasOptions = false;
|
|
98
|
+
while (fetchOptions(cmd)) hasOptions = true;
|
|
99
|
+
if (hasOptions && cmd.args.length === 0) {
|
|
100
|
+
return (...args) => exec_func(cmd.options, ...args);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (Array.isArray(cmd.args[0])) cmd.args = processTemplate(...cmd.args);
|
|
104
|
+
return cmd.options.executer(cmd.options, ...cmd.args);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function getExecOptions(options) {
|
|
108
|
+
const execOptions = {...options};
|
|
109
|
+
[ 'acceptStatuses', 'appendEnv', 'exec', 'log', 'result' ].forEach( name => delete execOptions[name] );
|
|
110
|
+
|
|
111
|
+
const { appendEnv, result } = options;
|
|
112
|
+
if (appendEnv) {
|
|
113
|
+
execOptions.env = {...(options.env || process.env),...appendEnv};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
switch (result) {
|
|
117
|
+
case 'stdout':
|
|
118
|
+
execOptions.stdio = [ 'inherit', 'pipe', 'inherit' ];
|
|
119
|
+
break;
|
|
120
|
+
case 'stderr':
|
|
121
|
+
execOptions.stdio = [ 'inherit', 'inherit', 'pipe' ];
|
|
122
|
+
break;
|
|
123
|
+
case undefined:
|
|
124
|
+
break;
|
|
125
|
+
|
|
126
|
+
default:
|
|
127
|
+
throw new Error `Unexpected "result" option: "${result}"`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return execOptions;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function toString(a) {
|
|
134
|
+
return typeof a === 'string' ? a : Buffer.from(a).toString('utf-8');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function processResult(result, options) {
|
|
138
|
+
switch (options.result) {
|
|
139
|
+
case 'stdout':
|
|
140
|
+
return toString(result.stdout);
|
|
141
|
+
case 'stderr':
|
|
142
|
+
return toString(result.stderr);
|
|
143
|
+
case undefined:
|
|
144
|
+
return result;
|
|
145
|
+
|
|
146
|
+
default:
|
|
147
|
+
throw new Error(`Unexpected "result" option: "${result}"`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
function executeSync(options = {}, command, ...args) {
|
|
153
|
+
const { acceptStatuses } = options;
|
|
154
|
+
const execOptions = getExecOptions(options);
|
|
155
|
+
|
|
156
|
+
log.debug(`exec: ${command} ${args.map( v => v.match(/\s/) ? `"${v}"` : v ).join(' ')}`);
|
|
157
|
+
const result = spawnSync(command, args, execOptions);
|
|
158
|
+
|
|
159
|
+
if (acceptStatuses !== '*' && acceptStatuses.indexOf(result.status) === -1) throw new Error(`Command returned with status code ${result.status}`);
|
|
160
|
+
return processResult(result, options);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async function executeAsync(options = {}, command, ...args) {
|
|
164
|
+
const { acceptStatuses } = options;
|
|
165
|
+
const execOptions = getExecOptions(options);
|
|
166
|
+
|
|
167
|
+
// ctx.log(`exec: ${command} ${args.map( v => v.match(/\s/) ? `"${v}"` : v ).join(' ')}`);
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
const result = await new Promise( (resolve, reject) => {
|
|
171
|
+
const child = spawn(command, args, execOptions);
|
|
172
|
+
const stdoutChunks = [];
|
|
173
|
+
const stderrChunks = [];
|
|
174
|
+
|
|
175
|
+
if (child.stdout) {
|
|
176
|
+
child.stdout.on('data', data => {
|
|
177
|
+
stdoutChunks.push(Buffer.from(data));
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (child.stderr) {
|
|
182
|
+
child.stderr.on('data', data => {
|
|
183
|
+
stderrChunks.push(Buffer.from(data));
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const exit = status => {
|
|
188
|
+
if (acceptStatuses !== '*' && acceptStatuses.indexOf(status) === -1) reject(new Error(`Command returned with status code ${status}`))
|
|
189
|
+
else resolve({
|
|
190
|
+
status,
|
|
191
|
+
stdout: child.stdout ? Buffer.concat(stdoutChunks).toString("utf-8") : undefined,
|
|
192
|
+
stderr: child.stderr ? Buffer.concat(stderrChunks).toString("utf-8") : undefined
|
|
193
|
+
})
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
child.on('close', exit);
|
|
197
|
+
child.on('exit', exit);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
return processResult(result, options);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const exec = exec_func({ executer: executeAsync });
|
|
204
|
+
const execSync = exec_func({ executer: executeSync });
|
|
205
|
+
|
|
206
|
+
module.exports = {
|
|
207
|
+
exec,
|
|
208
|
+
execSync,
|
|
209
|
+
$ : execSync
|
|
210
|
+
}
|
|
@@ -14,46 +14,58 @@ module.exports = class LiveReload {
|
|
|
14
14
|
app.use('/livereload.js', express.static(require.resolve('livereload-js')))
|
|
15
15
|
|
|
16
16
|
return new Promise ((resolve, reject) => {
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
server.on('error', reject)
|
|
20
|
-
server.on('listening', async () => {
|
|
17
|
+
let server
|
|
18
|
+
const listening = async () => {
|
|
21
19
|
const {address,port} = server.address()
|
|
20
|
+
startWs(server)
|
|
22
21
|
this.url = await livereloadURL(address, port)
|
|
23
22
|
debug && debug(`[cds] - live reload available at ${this.url}`)
|
|
24
23
|
resolve(this.url)
|
|
24
|
+
}
|
|
25
|
+
// start server
|
|
26
|
+
server = app.listen (port,'localhost')
|
|
27
|
+
server.once('listening', listening)
|
|
28
|
+
server.on('error', e => {
|
|
29
|
+
// try once more w/ ephemeral port 0
|
|
30
|
+
if (e.code === 'EADDRINUSE') {
|
|
31
|
+
server = app.listen (0,'localhost')
|
|
32
|
+
server.once('listening', listening)
|
|
33
|
+
server.on('error', reject)
|
|
34
|
+
}
|
|
35
|
+
else reject(e)
|
|
25
36
|
})
|
|
26
37
|
|
|
27
38
|
// start websocket
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
39
|
+
const startWs = (server) => {
|
|
40
|
+
this.wsServer = new ws.Server({ server })
|
|
41
|
+
this.wsServer.on('connection', (socket) => {
|
|
42
|
+
debug && debug('Client connected')
|
|
43
|
+
socket.on('message', (msg) => {
|
|
44
|
+
debug && debug('Client message', msg)
|
|
45
|
+
const request = JSON.parse(msg)
|
|
34
46
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
if (request.command === 'hello') {
|
|
48
|
+
debug && debug('Client handshake')
|
|
49
|
+
const data = JSON.stringify({
|
|
50
|
+
command: 'hello',
|
|
51
|
+
protocols: [
|
|
52
|
+
'http://livereload.com/protocols/official-7',
|
|
53
|
+
'http://livereload.com/protocols/official-8',
|
|
54
|
+
'http://livereload.com/protocols/official-9',
|
|
55
|
+
'http://livereload.com/protocols/2.x-origin-version-negotiation',
|
|
56
|
+
'http://livereload.com/protocols/2.x-remote-control',
|
|
57
|
+
],
|
|
58
|
+
serverName: 'cds-watch',
|
|
59
|
+
})
|
|
60
|
+
socket.send(data)
|
|
61
|
+
} else if (request.command === 'info') {
|
|
62
|
+
debug && debug('Server received client data. Not sending response.')
|
|
63
|
+
}
|
|
64
|
+
})
|
|
52
65
|
})
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
66
|
+
this.wsServer.on('close', () => { debug && debug('Socket closed') })
|
|
67
|
+
this.wsServer.on('error', (e) => debug && debug(e))
|
|
68
|
+
}
|
|
57
69
|
})
|
|
58
70
|
}
|
|
59
71
|
|
package/lib/watch/node-watch.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const DEBUG = /\bwatch\b/.test(process.env.DEBUG) && console.debug
|
|
2
|
+
|
|
1
3
|
module.exports = ({ cwd, script, ext, ignore=RegExp(), env={}, delay=200, options={} })=>{
|
|
2
4
|
|
|
3
5
|
let child
|
|
@@ -5,19 +7,23 @@ module.exports = ({ cwd, script, ext, ignore=RegExp(), env={}, delay=200, option
|
|
|
5
7
|
// Phoning home...
|
|
6
8
|
const EventEmitter = require('events')
|
|
7
9
|
const emitter = new EventEmitter
|
|
8
|
-
process.on('exit', () => {
|
|
10
|
+
process.on('exit', () => { _kill (child); emitter.emit('quit') })
|
|
9
11
|
|
|
10
12
|
// Re-starting child process...
|
|
11
13
|
const { fork } = require('child_process')
|
|
12
|
-
const restart = (
|
|
13
|
-
|
|
14
|
+
const restart = _coalesceEvents(delay, (events) => {
|
|
15
|
+
DEBUG && DEBUG('>> Events:', events)
|
|
16
|
+
_kill (child, () => {
|
|
14
17
|
const execArgv = [...process.execArgv]
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
events.forEach(evt => {
|
|
19
|
+
if (evt.type && evt.type.startsWith('--')) execArgv.push(evt.type)
|
|
20
|
+
if (evt.name && evt.name.startsWith('--')) execArgv.push(evt.name)
|
|
21
|
+
})
|
|
17
22
|
if (options.debug) execArgv.push('--inspect')
|
|
18
23
|
if (options['debug-brk']) execArgv.push('--inspect-brk')
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
|
|
25
|
+
const updated = events.filter(evt => evt.type && evt.type === 'update').map(evt => evt.name)
|
|
26
|
+
emitter.emit ('restart', updated)
|
|
21
27
|
child = fork (script, { cwd, env, stdio:'inherit', execArgv }, (err)=>{
|
|
22
28
|
if (err) console.error (err)
|
|
23
29
|
})
|
|
@@ -26,14 +32,16 @@ module.exports = ({ cwd, script, ext, ignore=RegExp(), env={}, delay=200, option
|
|
|
26
32
|
emitter.emit('message', msg)
|
|
27
33
|
})
|
|
28
34
|
})
|
|
29
|
-
|
|
35
|
+
|
|
36
|
+
})
|
|
37
|
+
|
|
30
38
|
restart()
|
|
31
39
|
|
|
32
40
|
// Watching for touched files...
|
|
33
41
|
const watch = require('node-watch')
|
|
34
42
|
const include = RegExp(`\\.(${ext.replace(/,/g,'|')})$`)
|
|
35
43
|
const filter = f => !ignore.test(f) && include.test(f)
|
|
36
|
-
watch (process.cwd(),{ recursive:true, filter, delay }, restart)
|
|
44
|
+
watch (process.cwd(),{ recursive:true, filter, delay:0 }, restart)
|
|
37
45
|
|
|
38
46
|
// Live commands...
|
|
39
47
|
const readline = require('readline')
|
|
@@ -44,12 +52,12 @@ module.exports = ({ cwd, script, ext, ignore=RegExp(), env={}, delay=200, option
|
|
|
44
52
|
else if (input === 'break' || input === 'brk') restart('--inspect-brk')
|
|
45
53
|
else if (input === 'debug-brk') restart('--inspect-brk')
|
|
46
54
|
else if (input === 'ps') ps(child,env)
|
|
47
|
-
else if (input === 'bye' || input.match(/^n$/i)) {
|
|
55
|
+
else if (input === 'bye' || input.match(/^n$/i)) { _kill (child, () => process.exit()) }
|
|
48
56
|
else console.log ('?\n')
|
|
49
57
|
})
|
|
50
58
|
|
|
51
59
|
emitter.restart = restart
|
|
52
|
-
emitter.stop = () => {
|
|
60
|
+
emitter.stop = () => { _kill(child, () => false); child = undefined; }
|
|
53
61
|
emitter.setEnv = (name, value) => {
|
|
54
62
|
if (typeof value === "undefined") {
|
|
55
63
|
delete env[name]
|
|
@@ -67,14 +75,32 @@ const ps = (child,env) => console.log (`\x1b[32m
|
|
|
67
75
|
\x1b[0m`
|
|
68
76
|
)
|
|
69
77
|
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
+
// reduces mutiple node-watch events in a time frame into a bulk
|
|
79
|
+
function _coalesceEvents(delay, fn) {
|
|
80
|
+
let timer, cache = []
|
|
81
|
+
function handle() {
|
|
82
|
+
fn(cache)
|
|
83
|
+
timer = null
|
|
84
|
+
cache = []
|
|
85
|
+
}
|
|
86
|
+
return function(type, name) { // node-watch callback signature
|
|
87
|
+
cache.push({type, name})
|
|
88
|
+
if (!timer) {
|
|
89
|
+
timer = setTimeout(handle, delay);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function _kill (proc, fn=()=>{}) {
|
|
95
|
+
if (!proc) return fn()
|
|
96
|
+
|
|
97
|
+
// On Windows, child_process.kill() abruptly kills the process (https://nodejs.org/api/child_process.html#subprocesskillsignal)
|
|
98
|
+
// Server has cleanup code to run, so send a custom message and give it a bit time.
|
|
99
|
+
if (process.platform === 'win32') {
|
|
100
|
+
proc.send({ exit: true }, () => {})
|
|
101
|
+
const waitTime = parseInt(process.env.CDS_WATCH_KILL_DELAY) || 500
|
|
102
|
+
setTimeout(()=> { proc.kill(); fn() }, waitTime)
|
|
103
|
+
} else {
|
|
104
|
+
proc.kill(); fn()
|
|
78
105
|
}
|
|
79
|
-
else fn()
|
|
80
106
|
}
|
package/lib/watch/open.js
CHANGED
|
@@ -19,7 +19,7 @@ function _open(args) {
|
|
|
19
19
|
// http://stackoverflow.com/q/1480971/3191, but see below for Windows.
|
|
20
20
|
let platform = process.platform
|
|
21
21
|
|
|
22
|
-
// Attempt to detect Windows
|
|
22
|
+
// Attempt to detect Windows Subsystem for Linux (WSL). WSL itself as Linux (which works in most cases), but in
|
|
23
23
|
// this specific case we need to treat it as actually being Windows. The 'Windows-way' of opening things through
|
|
24
24
|
// cmd.exe works just fine here, whereas using xdg-open does not, since there is no X Windows in WSL.
|
|
25
25
|
if (platform === 'linux' && os.release().indexOf('Microsoft') !== -1) {
|