mocha 9.1.2
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 +1015 -0
- package/LICENSE +22 -0
- package/README.md +70 -0
- package/assets/growl/error.png +0 -0
- package/assets/growl/ok.png +0 -0
- package/bin/_mocha +10 -0
- package/bin/mocha +142 -0
- package/browser-entry.js +216 -0
- package/index.js +3 -0
- package/lib/browser/growl.js +169 -0
- package/lib/browser/highlight-tags.js +39 -0
- package/lib/browser/parse-query.js +24 -0
- package/lib/browser/progress.js +123 -0
- package/lib/browser/template.html +20 -0
- package/lib/cli/cli.js +89 -0
- package/lib/cli/collect-files.js +92 -0
- package/lib/cli/commands.js +13 -0
- package/lib/cli/config.js +105 -0
- package/lib/cli/index.js +3 -0
- package/lib/cli/init.js +36 -0
- package/lib/cli/lookup-files.js +145 -0
- package/lib/cli/node-flags.js +85 -0
- package/lib/cli/one-and-dones.js +69 -0
- package/lib/cli/options.js +261 -0
- package/lib/cli/run-helpers.js +243 -0
- package/lib/cli/run-option-metadata.js +117 -0
- package/lib/cli/run.js +379 -0
- package/lib/cli/watch-run.js +380 -0
- package/lib/context.js +86 -0
- package/lib/errors.js +563 -0
- package/lib/hook.js +89 -0
- package/lib/interfaces/bdd.js +111 -0
- package/lib/interfaces/common.js +193 -0
- package/lib/interfaces/exports.js +60 -0
- package/lib/interfaces/index.js +6 -0
- package/lib/interfaces/qunit.js +98 -0
- package/lib/interfaces/tdd.js +106 -0
- package/lib/mocha.js +1374 -0
- package/lib/mocharc.json +10 -0
- package/lib/nodejs/buffered-worker-pool.js +172 -0
- package/lib/nodejs/esm-utils.js +109 -0
- package/lib/nodejs/file-unloader.js +15 -0
- package/lib/nodejs/growl.js +137 -0
- package/lib/nodejs/parallel-buffered-runner.js +433 -0
- package/lib/nodejs/reporters/parallel-buffered.js +165 -0
- package/lib/nodejs/serializer.js +412 -0
- package/lib/nodejs/worker.js +151 -0
- package/lib/pending.js +16 -0
- package/lib/plugin-loader.js +286 -0
- package/lib/reporters/base.js +537 -0
- package/lib/reporters/doc.js +95 -0
- package/lib/reporters/dot.js +81 -0
- package/lib/reporters/html.js +390 -0
- package/lib/reporters/index.js +19 -0
- package/lib/reporters/json-stream.js +92 -0
- package/lib/reporters/json.js +162 -0
- package/lib/reporters/landing.js +116 -0
- package/lib/reporters/list.js +78 -0
- package/lib/reporters/markdown.js +112 -0
- package/lib/reporters/min.js +52 -0
- package/lib/reporters/nyan.js +276 -0
- package/lib/reporters/progress.js +104 -0
- package/lib/reporters/spec.js +99 -0
- package/lib/reporters/tap.js +293 -0
- package/lib/reporters/xunit.js +217 -0
- package/lib/runnable.js +476 -0
- package/lib/runner.js +1269 -0
- package/lib/stats-collector.js +83 -0
- package/lib/suite.js +695 -0
- package/lib/test.js +113 -0
- package/lib/utils.js +641 -0
- package/mocha-es2018.js +19816 -0
- package/mocha.css +325 -0
- package/mocha.js +30844 -0
- package/mocha.js.map +1 -0
- package/package.json +200 -0
package/lib/mocharc.json
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A wrapper around a third-party child process worker pool implementation.
|
|
3
|
+
* Used by {@link module:buffered-runner}.
|
|
4
|
+
* @private
|
|
5
|
+
* @module buffered-worker-pool
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
const serializeJavascript = require('serialize-javascript');
|
|
11
|
+
const workerpool = require('workerpool');
|
|
12
|
+
const {deserialize} = require('./serializer');
|
|
13
|
+
const debug = require('debug')('mocha:parallel:buffered-worker-pool');
|
|
14
|
+
const {createInvalidArgumentTypeError} = require('../errors');
|
|
15
|
+
|
|
16
|
+
const WORKER_PATH = require.resolve('./worker.js');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A mapping of Mocha `Options` objects to serialized values.
|
|
20
|
+
*
|
|
21
|
+
* This is helpful because we tend to same the same options over and over
|
|
22
|
+
* over IPC.
|
|
23
|
+
* @type {WeakMap<Options,string>}
|
|
24
|
+
*/
|
|
25
|
+
let optionsCache = new WeakMap();
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* These options are passed into the [workerpool](https://npm.im/workerpool) module.
|
|
29
|
+
* @type {Partial<WorkerPoolOptions>}
|
|
30
|
+
*/
|
|
31
|
+
const WORKER_POOL_DEFAULT_OPTS = {
|
|
32
|
+
// use child processes, not worker threads!
|
|
33
|
+
workerType: 'process',
|
|
34
|
+
// ensure the same flags sent to `node` for this `mocha` invocation are passed
|
|
35
|
+
// along to children
|
|
36
|
+
forkOpts: {execArgv: process.execArgv},
|
|
37
|
+
maxWorkers: workerpool.cpus - 1
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* A wrapper around a third-party worker pool implementation.
|
|
42
|
+
* @private
|
|
43
|
+
*/
|
|
44
|
+
class BufferedWorkerPool {
|
|
45
|
+
/**
|
|
46
|
+
* Creates an underlying worker pool instance; determines max worker count
|
|
47
|
+
* @param {Partial<WorkerPoolOptions>} [opts] - Options
|
|
48
|
+
*/
|
|
49
|
+
constructor(opts = {}) {
|
|
50
|
+
const maxWorkers = Math.max(
|
|
51
|
+
1,
|
|
52
|
+
typeof opts.maxWorkers === 'undefined'
|
|
53
|
+
? WORKER_POOL_DEFAULT_OPTS.maxWorkers
|
|
54
|
+
: opts.maxWorkers
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
/* istanbul ignore next */
|
|
58
|
+
if (workerpool.cpus < 2) {
|
|
59
|
+
// TODO: decide whether we should warn
|
|
60
|
+
debug(
|
|
61
|
+
'not enough CPU cores available to run multiple jobs; avoid --parallel on this machine'
|
|
62
|
+
);
|
|
63
|
+
} else if (maxWorkers >= workerpool.cpus) {
|
|
64
|
+
// TODO: decide whether we should warn
|
|
65
|
+
debug(
|
|
66
|
+
'%d concurrent job(s) requested, but only %d core(s) available',
|
|
67
|
+
maxWorkers,
|
|
68
|
+
workerpool.cpus
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
/* istanbul ignore next */
|
|
72
|
+
debug(
|
|
73
|
+
'run(): starting worker pool of max size %d, using node args: %s',
|
|
74
|
+
maxWorkers,
|
|
75
|
+
process.execArgv.join(' ')
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
this.options = {...WORKER_POOL_DEFAULT_OPTS, opts, maxWorkers};
|
|
79
|
+
this._pool = workerpool.pool(WORKER_PATH, this.options);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Terminates all workers in the pool.
|
|
84
|
+
* @param {boolean} [force] - Whether to force-kill workers. By default, lets workers finish their current task before termination.
|
|
85
|
+
* @private
|
|
86
|
+
* @returns {Promise<void>}
|
|
87
|
+
*/
|
|
88
|
+
async terminate(force = false) {
|
|
89
|
+
/* istanbul ignore next */
|
|
90
|
+
debug('terminate(): terminating with force = %s', force);
|
|
91
|
+
return this._pool.terminate(force);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Adds a test file run to the worker pool queue for execution by a worker process.
|
|
96
|
+
*
|
|
97
|
+
* Handles serialization/deserialization.
|
|
98
|
+
*
|
|
99
|
+
* @param {string} filepath - Filepath of test
|
|
100
|
+
* @param {Options} [options] - Options for Mocha instance
|
|
101
|
+
* @private
|
|
102
|
+
* @returns {Promise<SerializedWorkerResult>}
|
|
103
|
+
*/
|
|
104
|
+
async run(filepath, options = {}) {
|
|
105
|
+
if (!filepath || typeof filepath !== 'string') {
|
|
106
|
+
throw createInvalidArgumentTypeError(
|
|
107
|
+
'Expected a non-empty filepath',
|
|
108
|
+
'filepath',
|
|
109
|
+
'string'
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
const serializedOptions = BufferedWorkerPool.serializeOptions(options);
|
|
113
|
+
const result = await this._pool.exec('run', [filepath, serializedOptions]);
|
|
114
|
+
return deserialize(result);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Returns stats about the state of the worker processes in the pool.
|
|
119
|
+
*
|
|
120
|
+
* Used for debugging.
|
|
121
|
+
*
|
|
122
|
+
* @private
|
|
123
|
+
*/
|
|
124
|
+
stats() {
|
|
125
|
+
return this._pool.stats();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Instantiates a {@link WorkerPool}.
|
|
130
|
+
* @private
|
|
131
|
+
*/
|
|
132
|
+
static create(...args) {
|
|
133
|
+
return new BufferedWorkerPool(...args);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Given Mocha options object `opts`, serialize into a format suitable for
|
|
138
|
+
* transmission over IPC.
|
|
139
|
+
*
|
|
140
|
+
* @param {Options} [opts] - Mocha options
|
|
141
|
+
* @private
|
|
142
|
+
* @returns {string} Serialized options
|
|
143
|
+
*/
|
|
144
|
+
static serializeOptions(opts = {}) {
|
|
145
|
+
if (!optionsCache.has(opts)) {
|
|
146
|
+
const serialized = serializeJavascript(opts, {
|
|
147
|
+
unsafe: true, // this means we don't care about XSS
|
|
148
|
+
ignoreFunction: true // do not serialize functions
|
|
149
|
+
});
|
|
150
|
+
optionsCache.set(opts, serialized);
|
|
151
|
+
/* istanbul ignore next */
|
|
152
|
+
debug(
|
|
153
|
+
'serializeOptions(): serialized options %O to: %s',
|
|
154
|
+
opts,
|
|
155
|
+
serialized
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
return optionsCache.get(opts);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Resets internal cache of serialized options objects.
|
|
163
|
+
*
|
|
164
|
+
* For testing/debugging
|
|
165
|
+
* @private
|
|
166
|
+
*/
|
|
167
|
+
static resetOptionsCache() {
|
|
168
|
+
optionsCache = new WeakMap();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
exports.BufferedWorkerPool = BufferedWorkerPool;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const url = require('url');
|
|
3
|
+
|
|
4
|
+
const formattedImport = async file => {
|
|
5
|
+
if (path.isAbsolute(file)) {
|
|
6
|
+
try {
|
|
7
|
+
return await import(url.pathToFileURL(file));
|
|
8
|
+
} catch (err) {
|
|
9
|
+
// This is a hack created because ESM in Node.js (at least in Node v15.5.1) does not emit
|
|
10
|
+
// the location of the syntax error in the error thrown.
|
|
11
|
+
// This is problematic because the user can't see what file has the problem,
|
|
12
|
+
// so we add the file location to the error.
|
|
13
|
+
// This `if` should be removed once Node.js fixes the problem.
|
|
14
|
+
if (
|
|
15
|
+
err instanceof SyntaxError &&
|
|
16
|
+
err.message &&
|
|
17
|
+
err.stack &&
|
|
18
|
+
!err.stack.includes(file)
|
|
19
|
+
) {
|
|
20
|
+
const newErrorWithFilename = new SyntaxError(err.message);
|
|
21
|
+
newErrorWithFilename.stack = err.stack.replace(
|
|
22
|
+
/^SyntaxError/,
|
|
23
|
+
`SyntaxError[ @${file} ]`
|
|
24
|
+
);
|
|
25
|
+
throw newErrorWithFilename;
|
|
26
|
+
}
|
|
27
|
+
throw err;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return import(file);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const hasStableEsmImplementation = (() => {
|
|
34
|
+
const [major, minor] = process.version.split('.');
|
|
35
|
+
// ESM is stable from v12.22.0 onward
|
|
36
|
+
// https://nodejs.org/api/esm.html#esm_modules_ecmascript_modules
|
|
37
|
+
const majorNumber = parseInt(major.slice(1), 10);
|
|
38
|
+
const minorNumber = parseInt(minor, 10);
|
|
39
|
+
return majorNumber > 12 || (majorNumber === 12 && minorNumber >= 22);
|
|
40
|
+
})();
|
|
41
|
+
|
|
42
|
+
exports.requireOrImport = hasStableEsmImplementation
|
|
43
|
+
? async file => {
|
|
44
|
+
if (path.extname(file) === '.mjs') {
|
|
45
|
+
return formattedImport(file);
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
return dealWithExports(await formattedImport(file));
|
|
49
|
+
} catch (err) {
|
|
50
|
+
if (
|
|
51
|
+
err.code === 'ERR_MODULE_NOT_FOUND' ||
|
|
52
|
+
err.code === 'ERR_UNKNOWN_FILE_EXTENSION' ||
|
|
53
|
+
err.code === 'ERR_UNSUPPORTED_DIR_IMPORT'
|
|
54
|
+
) {
|
|
55
|
+
try {
|
|
56
|
+
return require(file);
|
|
57
|
+
} catch (requireErr) {
|
|
58
|
+
if (requireErr.code === 'ERR_REQUIRE_ESM') {
|
|
59
|
+
// This happens when the test file is a JS file, but via type:module is actually ESM,
|
|
60
|
+
// AND has an import to a file that doesn't exist.
|
|
61
|
+
// This throws an `ERR_MODULE_NOT_FOUND` // error above,
|
|
62
|
+
// and when we try to `require` it here, it throws an `ERR_REQUIRE_ESM`.
|
|
63
|
+
// What we want to do is throw the original error (the `ERR_MODULE_NOT_FOUND`),
|
|
64
|
+
// and not the `ERR_REQUIRE_ESM` error, which is a red herring.
|
|
65
|
+
throw err;
|
|
66
|
+
} else {
|
|
67
|
+
throw requireErr;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
: implementationOfRequireOrImportForUnstableEsm;
|
|
76
|
+
|
|
77
|
+
function dealWithExports(module) {
|
|
78
|
+
if (module.default) {
|
|
79
|
+
return module.default;
|
|
80
|
+
} else {
|
|
81
|
+
return {...module, default: undefined};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
exports.loadFilesAsync = async (files, preLoadFunc, postLoadFunc) => {
|
|
86
|
+
for (const file of files) {
|
|
87
|
+
preLoadFunc(file);
|
|
88
|
+
const result = await exports.requireOrImport(path.resolve(file));
|
|
89
|
+
postLoadFunc(file, result);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/* istanbul ignore next */
|
|
94
|
+
async function implementationOfRequireOrImportForUnstableEsm(file) {
|
|
95
|
+
if (path.extname(file) === '.mjs') {
|
|
96
|
+
return formattedImport(file);
|
|
97
|
+
}
|
|
98
|
+
// This is currently the only known way of figuring out whether a file is CJS or ESM in
|
|
99
|
+
// Node.js that doesn't necessitate calling `import` first.
|
|
100
|
+
try {
|
|
101
|
+
return require(file);
|
|
102
|
+
} catch (err) {
|
|
103
|
+
if (err.code === 'ERR_REQUIRE_ESM') {
|
|
104
|
+
return formattedImport(file);
|
|
105
|
+
} else {
|
|
106
|
+
throw err;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This module should not be in the browser bundle, so it's here.
|
|
5
|
+
* @private
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Deletes a file from the `require` cache.
|
|
11
|
+
* @param {string} file - File
|
|
12
|
+
*/
|
|
13
|
+
exports.unloadFile = file => {
|
|
14
|
+
delete require.cache[require.resolve(file)];
|
|
15
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Desktop Notifications module.
|
|
5
|
+
* @module Growl
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const os = require('os');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const {sync: which} = require('which');
|
|
11
|
+
const {EVENT_RUN_END} = require('../runner').constants;
|
|
12
|
+
const {isBrowser} = require('../utils');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @summary
|
|
16
|
+
* Checks if Growl notification support seems likely.
|
|
17
|
+
*
|
|
18
|
+
* @description
|
|
19
|
+
* Glosses over the distinction between an unsupported platform
|
|
20
|
+
* and one that lacks prerequisite software installations.
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
* @see {@link https://github.com/tj/node-growl/blob/master/README.md|Prerequisite Installs}
|
|
24
|
+
* @see {@link Mocha#growl}
|
|
25
|
+
* @see {@link Mocha#isGrowlCapable}
|
|
26
|
+
* @return {boolean} whether Growl notification support can be expected
|
|
27
|
+
*/
|
|
28
|
+
exports.isCapable = () => {
|
|
29
|
+
if (!isBrowser()) {
|
|
30
|
+
return getSupportBinaries().reduce(
|
|
31
|
+
(acc, binary) => acc || Boolean(which(binary, {nothrow: true})),
|
|
32
|
+
false
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
return false;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Implements desktop notifications as a pseudo-reporter.
|
|
40
|
+
*
|
|
41
|
+
* @public
|
|
42
|
+
* @see {@link Mocha#_growl}
|
|
43
|
+
* @param {Runner} runner - Runner instance.
|
|
44
|
+
*/
|
|
45
|
+
exports.notify = runner => {
|
|
46
|
+
runner.once(EVENT_RUN_END, () => {
|
|
47
|
+
display(runner);
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Displays the notification.
|
|
53
|
+
*
|
|
54
|
+
* @private
|
|
55
|
+
* @param {Runner} runner - Runner instance.
|
|
56
|
+
*/
|
|
57
|
+
const display = runner => {
|
|
58
|
+
const growl = require('growl');
|
|
59
|
+
const stats = runner.stats;
|
|
60
|
+
const symbol = {
|
|
61
|
+
cross: '\u274C',
|
|
62
|
+
tick: '\u2705'
|
|
63
|
+
};
|
|
64
|
+
let _message;
|
|
65
|
+
let message;
|
|
66
|
+
let title;
|
|
67
|
+
|
|
68
|
+
if (stats.failures) {
|
|
69
|
+
_message = `${stats.failures} of ${stats.tests} tests failed`;
|
|
70
|
+
message = `${symbol.cross} ${_message}`;
|
|
71
|
+
title = 'Failed';
|
|
72
|
+
} else {
|
|
73
|
+
_message = `${stats.passes} tests passed in ${stats.duration}ms`;
|
|
74
|
+
message = `${symbol.tick} ${_message}`;
|
|
75
|
+
title = 'Passed';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Send notification
|
|
79
|
+
const options = {
|
|
80
|
+
image: logo(),
|
|
81
|
+
name: 'mocha',
|
|
82
|
+
title
|
|
83
|
+
};
|
|
84
|
+
growl(message, options, onCompletion);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @summary
|
|
89
|
+
* Callback for result of attempted Growl notification.
|
|
90
|
+
*
|
|
91
|
+
* @description
|
|
92
|
+
* Despite its appearance, this is <strong>not</strong> an Error-first
|
|
93
|
+
* callback -- all parameters are populated regardless of success.
|
|
94
|
+
*
|
|
95
|
+
* @private
|
|
96
|
+
* @callback Growl~growlCB
|
|
97
|
+
* @param {*} err - Error object, or <code>null</code> if successful.
|
|
98
|
+
*/
|
|
99
|
+
function onCompletion(err) {
|
|
100
|
+
if (err) {
|
|
101
|
+
// As notifications are tangential to our purpose, just log the error.
|
|
102
|
+
const message =
|
|
103
|
+
err.code === 'ENOENT' ? 'prerequisite software not found' : err.message;
|
|
104
|
+
console.error('notification error:', message);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Returns Mocha logo image path.
|
|
110
|
+
*
|
|
111
|
+
* @private
|
|
112
|
+
* @return {string} Pathname of Mocha logo
|
|
113
|
+
*/
|
|
114
|
+
const logo = () => {
|
|
115
|
+
return path.join(__dirname, '..', 'assets', 'mocha-logo-96.png');
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @summary
|
|
120
|
+
* Gets platform-specific Growl support binaries.
|
|
121
|
+
*
|
|
122
|
+
* @description
|
|
123
|
+
* Somewhat brittle dependency on `growl` package implementation, but it
|
|
124
|
+
* rarely changes.
|
|
125
|
+
*
|
|
126
|
+
* @private
|
|
127
|
+
* @see {@link https://github.com/tj/node-growl/blob/master/lib/growl.js#L28-L126|setupCmd}
|
|
128
|
+
* @return {string[]} names of Growl support binaries
|
|
129
|
+
*/
|
|
130
|
+
const getSupportBinaries = () => {
|
|
131
|
+
const binaries = {
|
|
132
|
+
Darwin: ['terminal-notifier', 'growlnotify'],
|
|
133
|
+
Linux: ['notify-send', 'growl'],
|
|
134
|
+
Windows_NT: ['growlnotify.exe']
|
|
135
|
+
};
|
|
136
|
+
return binaries[os.type()] || [];
|
|
137
|
+
};
|