mocha 6.1.0 → 6.1.4

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.
Files changed (61) hide show
  1. package/CHANGELOG.md +1776 -1751
  2. package/LICENSE +22 -22
  3. package/README.md +105 -105
  4. package/bin/_mocha +10 -10
  5. package/bin/mocha +149 -149
  6. package/bin/options.js +10 -10
  7. package/browser-entry.js +191 -191
  8. package/index.js +3 -3
  9. package/lib/browser/growl.js +168 -168
  10. package/lib/browser/progress.js +119 -119
  11. package/lib/browser/template.html +18 -18
  12. package/lib/browser/tty.js +13 -13
  13. package/lib/cli/cli.js +69 -69
  14. package/lib/cli/commands.js +13 -13
  15. package/lib/cli/config.js +101 -101
  16. package/lib/cli/index.js +9 -9
  17. package/lib/cli/init.js +37 -37
  18. package/lib/cli/node-flags.js +86 -86
  19. package/lib/cli/one-and-dones.js +70 -70
  20. package/lib/cli/options.js +347 -347
  21. package/lib/cli/run-helpers.js +337 -337
  22. package/lib/cli/run-option-metadata.js +76 -76
  23. package/lib/cli/run.js +297 -297
  24. package/lib/context.js +101 -101
  25. package/lib/errors.js +141 -141
  26. package/lib/growl.js +136 -136
  27. package/lib/hook.js +46 -46
  28. package/lib/interfaces/bdd.js +118 -118
  29. package/lib/interfaces/common.js +191 -191
  30. package/lib/interfaces/exports.js +60 -60
  31. package/lib/interfaces/index.js +6 -6
  32. package/lib/interfaces/qunit.js +99 -99
  33. package/lib/interfaces/tdd.js +107 -107
  34. package/lib/mocha.js +843 -843
  35. package/lib/mocharc.json +10 -10
  36. package/lib/pending.js +12 -12
  37. package/lib/reporters/base.js +491 -491
  38. package/lib/reporters/doc.js +85 -85
  39. package/lib/reporters/dot.js +81 -81
  40. package/lib/reporters/html.js +390 -390
  41. package/lib/reporters/index.js +19 -19
  42. package/lib/reporters/json-stream.js +90 -90
  43. package/lib/reporters/json.js +135 -135
  44. package/lib/reporters/landing.js +108 -108
  45. package/lib/reporters/list.js +78 -78
  46. package/lib/reporters/markdown.js +112 -112
  47. package/lib/reporters/min.js +52 -52
  48. package/lib/reporters/nyan.js +276 -276
  49. package/lib/reporters/progress.js +104 -104
  50. package/lib/reporters/spec.js +99 -99
  51. package/lib/reporters/tap.js +294 -294
  52. package/lib/reporters/xunit.js +216 -216
  53. package/lib/runnable.js +496 -496
  54. package/lib/runner.js +1049 -1049
  55. package/lib/stats-collector.js +83 -83
  56. package/lib/suite.js +642 -642
  57. package/lib/test.js +51 -51
  58. package/lib/utils.js +897 -897
  59. package/mocha.css +326 -326
  60. package/mocha.js +8170 -8476
  61. package/package.json +630 -628
@@ -1,347 +1,347 @@
1
- 'use strict';
2
-
3
- /**
4
- * Main entry point for handling filesystem-based configuration,
5
- * whether that's `mocha.opts` or a config file or `package.json` or whatever.
6
- * @module
7
- */
8
-
9
- const fs = require('fs');
10
- const yargsParser = require('yargs-parser');
11
- const {types, aliases} = require('./run-option-metadata');
12
- const {ONE_AND_DONE_ARGS} = require('./one-and-dones');
13
- const mocharc = require('../mocharc.json');
14
- const {list} = require('./run-helpers');
15
- const {loadConfig, findConfig} = require('./config');
16
- const findUp = require('find-up');
17
- const {deprecate} = require('../utils');
18
- const debug = require('debug')('mocha:cli:options');
19
- const {createMissingArgumentError} = require('../errors');
20
- const {isNodeFlag} = require('./node-flags');
21
-
22
- /**
23
- * The `yargs-parser` namespace
24
- * @external yargsParser
25
- * @see {@link https://npm.im/yargs-parser}
26
- */
27
-
28
- /**
29
- * An object returned by a configured `yargs-parser` representing arguments
30
- * @memberof external:yargsParser
31
- * @interface Arguments
32
- */
33
-
34
- /**
35
- * Base yargs parser configuration
36
- * @private
37
- */
38
- const YARGS_PARSER_CONFIG = {
39
- 'combine-arrays': true,
40
- 'short-option-groups': false,
41
- 'dot-notation': false
42
- };
43
-
44
- /**
45
- * This is the config pulled from the `yargs` property of Mocha's
46
- * `package.json`, but it also disables camel case expansion as to
47
- * avoid outputting non-canonical keynames, as we need to do some
48
- * lookups.
49
- * @private
50
- * @ignore
51
- */
52
- const configuration = Object.assign({}, YARGS_PARSER_CONFIG, {
53
- 'camel-case-expansion': false
54
- });
55
-
56
- /**
57
- * This is a really fancy way to ensure unique values for `array`-type
58
- * options.
59
- * This is passed as the `coerce` option to `yargs-parser`
60
- * @private
61
- * @ignore
62
- */
63
- const coerceOpts = types.array.reduce(
64
- (acc, arg) => Object.assign(acc, {[arg]: v => Array.from(new Set(list(v)))}),
65
- {}
66
- );
67
-
68
- /**
69
- * We do not have a case when multiple arguments are ever allowed after a flag
70
- * (e.g., `--foo bar baz quux`), so we fix the number of arguments to 1 across
71
- * the board of non-boolean options.
72
- * This is passed as the `narg` option to `yargs-parser`
73
- * @private
74
- * @ignore
75
- */
76
- const nargOpts = types.array
77
- .concat(types.string, types.number)
78
- .reduce((acc, arg) => Object.assign(acc, {[arg]: 1}), {});
79
-
80
- /**
81
- * Wrapper around `yargs-parser` which applies our settings
82
- * @param {string|string[]} args - Arguments to parse
83
- * @param {...Object} configObjects - `configObjects` for yargs-parser
84
- * @private
85
- * @ignore
86
- */
87
- const parse = (args = [], ...configObjects) => {
88
- // save node-specific args for special handling.
89
- // 1. when these args have a "=" they should be considered to have values
90
- // 2. if they don't, they just boolean flags
91
- // 3. to avoid explicitly defining the set of them, we tell yargs-parser they
92
- // are ALL boolean flags.
93
- // 4. we can then reapply the values after yargs-parser is done.
94
- const nodeArgs = (Array.isArray(args) ? args : args.split(' ')).reduce(
95
- (acc, arg) => {
96
- const pair = arg.split('=');
97
- let flag = pair[0];
98
- if (isNodeFlag(flag, false)) {
99
- flag = flag.replace(/^--?/, '');
100
- return arg.includes('=')
101
- ? acc.concat([[flag, pair[1]]])
102
- : acc.concat([[flag, true]]);
103
- }
104
- return acc;
105
- },
106
- []
107
- );
108
-
109
- const result = yargsParser.detailed(args, {
110
- configuration,
111
- configObjects,
112
- coerce: coerceOpts,
113
- narg: nargOpts,
114
- alias: aliases,
115
- string: types.string,
116
- array: types.array,
117
- number: types.number,
118
- boolean: types.boolean.concat(nodeArgs.map(pair => pair[0]))
119
- });
120
- if (result.error) {
121
- throw createMissingArgumentError(result.error.message);
122
- }
123
-
124
- // reapply "=" arg values from above
125
- nodeArgs.forEach(([key, value]) => {
126
- result.argv[key] = value;
127
- });
128
-
129
- return result.argv;
130
- };
131
-
132
- /**
133
- * - Replaces comments with empty strings
134
- * - Replaces escaped spaces (e.g., 'xxx\ yyy') with HTML space
135
- * - Splits on whitespace, creating array of substrings
136
- * - Filters empty string elements from array
137
- * - Replaces any HTML space with space
138
- * @summary Parses options read from run-control file.
139
- * @private
140
- * @param {string} content - Content read from run-control file.
141
- * @returns {string[]} cmdline options (and associated arguments)
142
- * @ignore
143
- */
144
- const parseMochaOpts = content =>
145
- content
146
- .replace(/^#.*$/gm, '')
147
- .replace(/\\\s/g, '%20')
148
- .split(/\s/)
149
- .filter(Boolean)
150
- .map(value => value.replace(/%20/g, ' '));
151
-
152
- /**
153
- * Prepends options from run-control file to the command line arguments.
154
- *
155
- * @deprecated Deprecated in v6.0.0; This function is no longer used internally and will be removed in a future version.
156
- * @public
157
- * @alias module:lib/cli/options
158
- * @see {@link https://mochajs.org/#mochaopts|mocha.opts}
159
- */
160
- module.exports = function getOptions() {
161
- deprecate(
162
- 'getOptions() is DEPRECATED and will be removed from a future version of Mocha. Use loadOptions() instead'
163
- );
164
- if (process.argv.length === 3 && ONE_AND_DONE_ARGS.has(process.argv[2])) {
165
- return;
166
- }
167
-
168
- const optsPath =
169
- process.argv.indexOf('--opts') === -1
170
- ? mocharc.opts
171
- : process.argv[process.argv.indexOf('--opts') + 1];
172
-
173
- try {
174
- const options = parseMochaOpts(fs.readFileSync(optsPath, 'utf8'));
175
-
176
- process.argv = process.argv
177
- .slice(0, 2)
178
- .concat(options.concat(process.argv.slice(2)));
179
- } catch (ignore) {
180
- // NOTE: should console.error() and throw the error
181
- }
182
-
183
- process.env.LOADED_MOCHA_OPTS = true;
184
- };
185
-
186
- /**
187
- * Given filepath in `args.opts`, attempt to load and parse a `mocha.opts` file.
188
- * @param {Object} [args] - Arguments object
189
- * @param {string|boolean} [args.opts] - Filepath to mocha.opts; defaults to whatever's in `mocharc.opts`, or `false` to skip
190
- * @returns {external:yargsParser.Arguments|void} If read, object containing parsed arguments
191
- * @memberof module:lib/cli/options
192
- * @public
193
- */
194
- const loadMochaOpts = (args = {}) => {
195
- let result;
196
- let filepath = args.opts;
197
- // /dev/null is backwards compat
198
- if (filepath === false || filepath === '/dev/null') {
199
- return result;
200
- }
201
- filepath = filepath || mocharc.opts;
202
- result = {};
203
- let mochaOpts;
204
- try {
205
- mochaOpts = fs.readFileSync(filepath, 'utf8');
206
- debug(`read ${filepath}`);
207
- } catch (err) {
208
- if (args.opts) {
209
- throw new Error(`Unable to read ${filepath}: ${err}`);
210
- }
211
- // ignore otherwise. we tried
212
- debug(`No mocha.opts found at ${filepath}`);
213
- }
214
-
215
- // real args should override `mocha.opts` which should override defaults.
216
- // if there's an exception to catch here, I'm not sure what it is.
217
- // by attaching the `no-opts` arg, we avoid re-parsing of `mocha.opts`.
218
- if (mochaOpts) {
219
- result = parse(parseMochaOpts(mochaOpts));
220
- debug(`${filepath} parsed succesfully`);
221
- }
222
- return result;
223
- };
224
-
225
- module.exports.loadMochaOpts = loadMochaOpts;
226
-
227
- /**
228
- * Given path to config file in `args.config`, attempt to load & parse config file.
229
- * @param {Object} [args] - Arguments object
230
- * @param {string|boolean} [args.config] - Path to config file or `false` to skip
231
- * @public
232
- * @memberof module:lib/cli/options
233
- * @returns {external:yargsParser.Arguments|void} Parsed config, or nothing if `args.config` is `false`
234
- */
235
- const loadRc = (args = {}) => {
236
- if (args.config !== false) {
237
- const config = args.config || findConfig();
238
- return config ? loadConfig(config) : {};
239
- }
240
- };
241
-
242
- module.exports.loadRc = loadRc;
243
-
244
- /**
245
- * Given path to `package.json` in `args.package`, attempt to load config from `mocha` prop.
246
- * @param {Object} [args] - Arguments object
247
- * @param {string|boolean} [args.config] - Path to `package.json` or `false` to skip
248
- * @public
249
- * @memberof module:lib/cli/options
250
- * @returns {external:yargsParser.Arguments|void} Parsed config, or nothing if `args.package` is `false`
251
- */
252
- const loadPkgRc = (args = {}) => {
253
- let result;
254
- if (args.package === false) {
255
- return result;
256
- }
257
- result = {};
258
- const filepath = args.package || findUp.sync(mocharc.package);
259
- if (filepath) {
260
- try {
261
- const pkg = JSON.parse(fs.readFileSync(filepath, 'utf8'));
262
- if (pkg.mocha) {
263
- debug(`'mocha' prop of package.json parsed:`, pkg.mocha);
264
- result = pkg.mocha;
265
- } else {
266
- debug(`no config found in ${filepath}`);
267
- }
268
- } catch (err) {
269
- if (args.package) {
270
- throw new Error(`Unable to read/parse ${filepath}: ${err}`);
271
- }
272
- debug(`failed to read default package.json at ${filepath}; ignoring`);
273
- }
274
- }
275
- return result;
276
- };
277
-
278
- module.exports.loadPkgRc = loadPkgRc;
279
-
280
- /**
281
- * Priority list:
282
- *
283
- * 1. Command-line args
284
- * 2. RC file (`.mocharc.js`, `.mocharc.ya?ml`, `mocharc.json`)
285
- * 3. `mocha` prop of `package.json`
286
- * 4. `mocha.opts`
287
- * 5. default configuration (`lib/mocharc.json`)
288
- *
289
- * If a {@link module:lib/cli/one-and-dones.ONE_AND_DONE_ARGS "one-and-done" option} is present in the `argv` array, no external config files will be read.
290
- * @summary Parses options read from `mocha.opts`, `.mocharc.*` and `package.json`.
291
- * @param {string|string[]} [argv] - Arguments to parse
292
- * @public
293
- * @memberof module:lib/cli/options
294
- * @returns {external:yargsParser.Arguments} Parsed args from everything
295
- */
296
- const loadOptions = (argv = []) => {
297
- let args = parse(argv);
298
- // short-circuit: look for a flag that would abort loading of mocha.opts
299
- if (
300
- Array.from(ONE_AND_DONE_ARGS).reduce(
301
- (acc, arg) => acc || arg in args,
302
- false
303
- )
304
- ) {
305
- return args;
306
- }
307
-
308
- const rcConfig = loadRc(args);
309
- const pkgConfig = loadPkgRc(args);
310
- const optsConfig = loadMochaOpts(args);
311
-
312
- if (rcConfig) {
313
- args.config = false;
314
- args._ = args._.concat(rcConfig._ || []);
315
- }
316
- if (pkgConfig) {
317
- args.package = false;
318
- args._ = args._.concat(pkgConfig._ || []);
319
- }
320
- if (optsConfig) {
321
- args.opts = false;
322
- args._ = args._.concat(optsConfig._ || []);
323
- }
324
-
325
- args = parse(
326
- args._,
327
- args,
328
- rcConfig || {},
329
- pkgConfig || {},
330
- optsConfig || {},
331
- mocharc
332
- );
333
-
334
- // recombine positional arguments and "spec"
335
- if (args.spec) {
336
- args._ = args._.concat(args.spec);
337
- delete args.spec;
338
- }
339
-
340
- // make unique
341
- args._ = Array.from(new Set(args._));
342
-
343
- return args;
344
- };
345
-
346
- module.exports.loadOptions = loadOptions;
347
- module.exports.YARGS_PARSER_CONFIG = YARGS_PARSER_CONFIG;
1
+ 'use strict';
2
+
3
+ /**
4
+ * Main entry point for handling filesystem-based configuration,
5
+ * whether that's `mocha.opts` or a config file or `package.json` or whatever.
6
+ * @module
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const yargsParser = require('yargs-parser');
11
+ const {types, aliases} = require('./run-option-metadata');
12
+ const {ONE_AND_DONE_ARGS} = require('./one-and-dones');
13
+ const mocharc = require('../mocharc.json');
14
+ const {list} = require('./run-helpers');
15
+ const {loadConfig, findConfig} = require('./config');
16
+ const findUp = require('find-up');
17
+ const {deprecate} = require('../utils');
18
+ const debug = require('debug')('mocha:cli:options');
19
+ const {createMissingArgumentError} = require('../errors');
20
+ const {isNodeFlag} = require('./node-flags');
21
+
22
+ /**
23
+ * The `yargs-parser` namespace
24
+ * @external yargsParser
25
+ * @see {@link https://npm.im/yargs-parser}
26
+ */
27
+
28
+ /**
29
+ * An object returned by a configured `yargs-parser` representing arguments
30
+ * @memberof external:yargsParser
31
+ * @interface Arguments
32
+ */
33
+
34
+ /**
35
+ * Base yargs parser configuration
36
+ * @private
37
+ */
38
+ const YARGS_PARSER_CONFIG = {
39
+ 'combine-arrays': true,
40
+ 'short-option-groups': false,
41
+ 'dot-notation': false
42
+ };
43
+
44
+ /**
45
+ * This is the config pulled from the `yargs` property of Mocha's
46
+ * `package.json`, but it also disables camel case expansion as to
47
+ * avoid outputting non-canonical keynames, as we need to do some
48
+ * lookups.
49
+ * @private
50
+ * @ignore
51
+ */
52
+ const configuration = Object.assign({}, YARGS_PARSER_CONFIG, {
53
+ 'camel-case-expansion': false
54
+ });
55
+
56
+ /**
57
+ * This is a really fancy way to ensure unique values for `array`-type
58
+ * options.
59
+ * This is passed as the `coerce` option to `yargs-parser`
60
+ * @private
61
+ * @ignore
62
+ */
63
+ const coerceOpts = types.array.reduce(
64
+ (acc, arg) => Object.assign(acc, {[arg]: v => Array.from(new Set(list(v)))}),
65
+ {}
66
+ );
67
+
68
+ /**
69
+ * We do not have a case when multiple arguments are ever allowed after a flag
70
+ * (e.g., `--foo bar baz quux`), so we fix the number of arguments to 1 across
71
+ * the board of non-boolean options.
72
+ * This is passed as the `narg` option to `yargs-parser`
73
+ * @private
74
+ * @ignore
75
+ */
76
+ const nargOpts = types.array
77
+ .concat(types.string, types.number)
78
+ .reduce((acc, arg) => Object.assign(acc, {[arg]: 1}), {});
79
+
80
+ /**
81
+ * Wrapper around `yargs-parser` which applies our settings
82
+ * @param {string|string[]} args - Arguments to parse
83
+ * @param {...Object} configObjects - `configObjects` for yargs-parser
84
+ * @private
85
+ * @ignore
86
+ */
87
+ const parse = (args = [], ...configObjects) => {
88
+ // save node-specific args for special handling.
89
+ // 1. when these args have a "=" they should be considered to have values
90
+ // 2. if they don't, they just boolean flags
91
+ // 3. to avoid explicitly defining the set of them, we tell yargs-parser they
92
+ // are ALL boolean flags.
93
+ // 4. we can then reapply the values after yargs-parser is done.
94
+ const nodeArgs = (Array.isArray(args) ? args : args.split(' ')).reduce(
95
+ (acc, arg) => {
96
+ const pair = arg.split('=');
97
+ let flag = pair[0];
98
+ if (isNodeFlag(flag, false)) {
99
+ flag = flag.replace(/^--?/, '');
100
+ return arg.includes('=')
101
+ ? acc.concat([[flag, pair[1]]])
102
+ : acc.concat([[flag, true]]);
103
+ }
104
+ return acc;
105
+ },
106
+ []
107
+ );
108
+
109
+ const result = yargsParser.detailed(args, {
110
+ configuration,
111
+ configObjects,
112
+ coerce: coerceOpts,
113
+ narg: nargOpts,
114
+ alias: aliases,
115
+ string: types.string,
116
+ array: types.array,
117
+ number: types.number,
118
+ boolean: types.boolean.concat(nodeArgs.map(pair => pair[0]))
119
+ });
120
+ if (result.error) {
121
+ throw createMissingArgumentError(result.error.message);
122
+ }
123
+
124
+ // reapply "=" arg values from above
125
+ nodeArgs.forEach(([key, value]) => {
126
+ result.argv[key] = value;
127
+ });
128
+
129
+ return result.argv;
130
+ };
131
+
132
+ /**
133
+ * - Replaces comments with empty strings
134
+ * - Replaces escaped spaces (e.g., 'xxx\ yyy') with HTML space
135
+ * - Splits on whitespace, creating array of substrings
136
+ * - Filters empty string elements from array
137
+ * - Replaces any HTML space with space
138
+ * @summary Parses options read from run-control file.
139
+ * @private
140
+ * @param {string} content - Content read from run-control file.
141
+ * @returns {string[]} cmdline options (and associated arguments)
142
+ * @ignore
143
+ */
144
+ const parseMochaOpts = content =>
145
+ content
146
+ .replace(/^#.*$/gm, '')
147
+ .replace(/\\\s/g, '%20')
148
+ .split(/\s/)
149
+ .filter(Boolean)
150
+ .map(value => value.replace(/%20/g, ' '));
151
+
152
+ /**
153
+ * Prepends options from run-control file to the command line arguments.
154
+ *
155
+ * @deprecated Deprecated in v6.0.0; This function is no longer used internally and will be removed in a future version.
156
+ * @public
157
+ * @alias module:lib/cli/options
158
+ * @see {@link https://mochajs.org/#mochaopts|mocha.opts}
159
+ */
160
+ module.exports = function getOptions() {
161
+ deprecate(
162
+ 'getOptions() is DEPRECATED and will be removed from a future version of Mocha. Use loadOptions() instead'
163
+ );
164
+ if (process.argv.length === 3 && ONE_AND_DONE_ARGS.has(process.argv[2])) {
165
+ return;
166
+ }
167
+
168
+ const optsPath =
169
+ process.argv.indexOf('--opts') === -1
170
+ ? mocharc.opts
171
+ : process.argv[process.argv.indexOf('--opts') + 1];
172
+
173
+ try {
174
+ const options = parseMochaOpts(fs.readFileSync(optsPath, 'utf8'));
175
+
176
+ process.argv = process.argv
177
+ .slice(0, 2)
178
+ .concat(options.concat(process.argv.slice(2)));
179
+ } catch (ignore) {
180
+ // NOTE: should console.error() and throw the error
181
+ }
182
+
183
+ process.env.LOADED_MOCHA_OPTS = true;
184
+ };
185
+
186
+ /**
187
+ * Given filepath in `args.opts`, attempt to load and parse a `mocha.opts` file.
188
+ * @param {Object} [args] - Arguments object
189
+ * @param {string|boolean} [args.opts] - Filepath to mocha.opts; defaults to whatever's in `mocharc.opts`, or `false` to skip
190
+ * @returns {external:yargsParser.Arguments|void} If read, object containing parsed arguments
191
+ * @memberof module:lib/cli/options
192
+ * @public
193
+ */
194
+ const loadMochaOpts = (args = {}) => {
195
+ let result;
196
+ let filepath = args.opts;
197
+ // /dev/null is backwards compat
198
+ if (filepath === false || filepath === '/dev/null') {
199
+ return result;
200
+ }
201
+ filepath = filepath || mocharc.opts;
202
+ result = {};
203
+ let mochaOpts;
204
+ try {
205
+ mochaOpts = fs.readFileSync(filepath, 'utf8');
206
+ debug(`read ${filepath}`);
207
+ } catch (err) {
208
+ if (args.opts) {
209
+ throw new Error(`Unable to read ${filepath}: ${err}`);
210
+ }
211
+ // ignore otherwise. we tried
212
+ debug(`No mocha.opts found at ${filepath}`);
213
+ }
214
+
215
+ // real args should override `mocha.opts` which should override defaults.
216
+ // if there's an exception to catch here, I'm not sure what it is.
217
+ // by attaching the `no-opts` arg, we avoid re-parsing of `mocha.opts`.
218
+ if (mochaOpts) {
219
+ result = parse(parseMochaOpts(mochaOpts));
220
+ debug(`${filepath} parsed succesfully`);
221
+ }
222
+ return result;
223
+ };
224
+
225
+ module.exports.loadMochaOpts = loadMochaOpts;
226
+
227
+ /**
228
+ * Given path to config file in `args.config`, attempt to load & parse config file.
229
+ * @param {Object} [args] - Arguments object
230
+ * @param {string|boolean} [args.config] - Path to config file or `false` to skip
231
+ * @public
232
+ * @memberof module:lib/cli/options
233
+ * @returns {external:yargsParser.Arguments|void} Parsed config, or nothing if `args.config` is `false`
234
+ */
235
+ const loadRc = (args = {}) => {
236
+ if (args.config !== false) {
237
+ const config = args.config || findConfig();
238
+ return config ? loadConfig(config) : {};
239
+ }
240
+ };
241
+
242
+ module.exports.loadRc = loadRc;
243
+
244
+ /**
245
+ * Given path to `package.json` in `args.package`, attempt to load config from `mocha` prop.
246
+ * @param {Object} [args] - Arguments object
247
+ * @param {string|boolean} [args.config] - Path to `package.json` or `false` to skip
248
+ * @public
249
+ * @memberof module:lib/cli/options
250
+ * @returns {external:yargsParser.Arguments|void} Parsed config, or nothing if `args.package` is `false`
251
+ */
252
+ const loadPkgRc = (args = {}) => {
253
+ let result;
254
+ if (args.package === false) {
255
+ return result;
256
+ }
257
+ result = {};
258
+ const filepath = args.package || findUp.sync(mocharc.package);
259
+ if (filepath) {
260
+ try {
261
+ const pkg = JSON.parse(fs.readFileSync(filepath, 'utf8'));
262
+ if (pkg.mocha) {
263
+ debug(`'mocha' prop of package.json parsed:`, pkg.mocha);
264
+ result = pkg.mocha;
265
+ } else {
266
+ debug(`no config found in ${filepath}`);
267
+ }
268
+ } catch (err) {
269
+ if (args.package) {
270
+ throw new Error(`Unable to read/parse ${filepath}: ${err}`);
271
+ }
272
+ debug(`failed to read default package.json at ${filepath}; ignoring`);
273
+ }
274
+ }
275
+ return result;
276
+ };
277
+
278
+ module.exports.loadPkgRc = loadPkgRc;
279
+
280
+ /**
281
+ * Priority list:
282
+ *
283
+ * 1. Command-line args
284
+ * 2. RC file (`.mocharc.js`, `.mocharc.ya?ml`, `mocharc.json`)
285
+ * 3. `mocha` prop of `package.json`
286
+ * 4. `mocha.opts`
287
+ * 5. default configuration (`lib/mocharc.json`)
288
+ *
289
+ * If a {@link module:lib/cli/one-and-dones.ONE_AND_DONE_ARGS "one-and-done" option} is present in the `argv` array, no external config files will be read.
290
+ * @summary Parses options read from `mocha.opts`, `.mocharc.*` and `package.json`.
291
+ * @param {string|string[]} [argv] - Arguments to parse
292
+ * @public
293
+ * @memberof module:lib/cli/options
294
+ * @returns {external:yargsParser.Arguments} Parsed args from everything
295
+ */
296
+ const loadOptions = (argv = []) => {
297
+ let args = parse(argv);
298
+ // short-circuit: look for a flag that would abort loading of mocha.opts
299
+ if (
300
+ Array.from(ONE_AND_DONE_ARGS).reduce(
301
+ (acc, arg) => acc || arg in args,
302
+ false
303
+ )
304
+ ) {
305
+ return args;
306
+ }
307
+
308
+ const rcConfig = loadRc(args);
309
+ const pkgConfig = loadPkgRc(args);
310
+ const optsConfig = loadMochaOpts(args);
311
+
312
+ if (rcConfig) {
313
+ args.config = false;
314
+ args._ = args._.concat(rcConfig._ || []);
315
+ }
316
+ if (pkgConfig) {
317
+ args.package = false;
318
+ args._ = args._.concat(pkgConfig._ || []);
319
+ }
320
+ if (optsConfig) {
321
+ args.opts = false;
322
+ args._ = args._.concat(optsConfig._ || []);
323
+ }
324
+
325
+ args = parse(
326
+ args._,
327
+ args,
328
+ rcConfig || {},
329
+ pkgConfig || {},
330
+ optsConfig || {},
331
+ mocharc
332
+ );
333
+
334
+ // recombine positional arguments and "spec"
335
+ if (args.spec) {
336
+ args._ = args._.concat(args.spec);
337
+ delete args.spec;
338
+ }
339
+
340
+ // make unique
341
+ args._ = Array.from(new Set(args._));
342
+
343
+ return args;
344
+ };
345
+
346
+ module.exports.loadOptions = loadOptions;
347
+ module.exports.YARGS_PARSER_CONFIG = YARGS_PARSER_CONFIG;