mocha-compat 3.6.5 → 10.8.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.
Files changed (88) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +61 -110
  3. package/bin/_mocha +10 -0
  4. package/bin/mocha.js +142 -0
  5. package/browser-entry.js +61 -22
  6. package/lib/browser/highlight-tags.js +39 -0
  7. package/lib/browser/parse-query.js +24 -0
  8. package/lib/{template.html → browser/template.html} +7 -5
  9. package/lib/cli/cli.js +89 -0
  10. package/lib/cli/collect-files.js +137 -0
  11. package/lib/cli/commands.js +14 -0
  12. package/lib/cli/config.js +100 -0
  13. package/lib/cli/index.js +3 -0
  14. package/lib/cli/init.js +36 -0
  15. package/lib/cli/lookup-files.js +150 -0
  16. package/lib/cli/node-flags.js +85 -0
  17. package/lib/cli/one-and-dones.js +69 -0
  18. package/lib/cli/options.js +284 -0
  19. package/lib/cli/run-helpers.js +304 -0
  20. package/lib/cli/run-option-metadata.js +116 -0
  21. package/lib/cli/run.js +380 -0
  22. package/lib/cli/watch-run.js +377 -0
  23. package/lib/context.js +16 -42
  24. package/lib/errors.js +563 -0
  25. package/lib/hook.js +50 -9
  26. package/lib/interfaces/bdd.js +28 -29
  27. package/lib/interfaces/common.js +56 -21
  28. package/lib/interfaces/exports.js +4 -7
  29. package/lib/interfaces/qunit.js +10 -11
  30. package/lib/interfaces/tdd.js +15 -15
  31. package/lib/mocha.js +1073 -292
  32. package/lib/mocharc.json +10 -0
  33. package/lib/nodejs/buffered-worker-pool.js +188 -0
  34. package/lib/nodejs/esm-utils.js +106 -0
  35. package/lib/nodejs/file-unloader.js +15 -0
  36. package/lib/nodejs/parallel-buffered-runner.js +433 -0
  37. package/lib/nodejs/reporters/parallel-buffered.js +165 -0
  38. package/lib/nodejs/serializer.js +414 -0
  39. package/lib/nodejs/worker.js +151 -0
  40. package/lib/pending.js +3 -3
  41. package/lib/plugin-loader.js +286 -0
  42. package/lib/reporters/base.js +305 -205
  43. package/lib/reporters/doc.js +52 -21
  44. package/lib/reporters/dot.js +31 -18
  45. package/lib/reporters/html.js +153 -81
  46. package/lib/reporters/json-stream.js +53 -24
  47. package/lib/reporters/json.js +88 -18
  48. package/lib/reporters/landing.js +38 -16
  49. package/lib/reporters/list.js +34 -19
  50. package/lib/reporters/markdown.js +28 -15
  51. package/lib/reporters/min.js +22 -8
  52. package/lib/reporters/nyan.js +62 -58
  53. package/lib/reporters/progress.js +32 -19
  54. package/lib/reporters/spec.js +41 -23
  55. package/lib/reporters/tap.js +255 -32
  56. package/lib/reporters/xunit.js +89 -39
  57. package/lib/runnable.js +233 -148
  58. package/lib/runner.js +679 -380
  59. package/lib/stats-collector.js +83 -0
  60. package/lib/suite.js +376 -112
  61. package/lib/test.js +82 -21
  62. package/lib/utils.js +364 -477
  63. package/mocha.css +183 -54
  64. package/mocha.js +19315 -19984
  65. package/mocha.js.map +1 -0
  66. package/package.json +162 -334
  67. package/{lib/to-iso-string → vendor/serialize-javascript}/LICENSE +8 -6
  68. package/vendor/serialize-javascript/README.md +10 -0
  69. package/vendor/serialize-javascript/index.js +349 -0
  70. package/bin/_mocha-compat +0 -572
  71. package/bin/mocha-compat +0 -87
  72. package/bin/options.js +0 -41
  73. package/lib/browser/debug.js +0 -7
  74. package/lib/browser/events.js +0 -195
  75. package/lib/browser/progress.js +0 -119
  76. package/lib/browser/tty.js +0 -13
  77. package/lib/ms.js +0 -130
  78. package/lib/to-iso-string/index.js +0 -37
  79. package/vendor/glob/LICENSE +0 -15
  80. package/vendor/glob/README.md +0 -399
  81. package/vendor/glob/common.js +0 -244
  82. package/vendor/glob/glob.js +0 -788
  83. package/vendor/glob/package.json +0 -55
  84. package/vendor/glob/sync.js +0 -486
  85. package/vendor/inflight/LICENSE +0 -15
  86. package/vendor/inflight/README.md +0 -37
  87. package/vendor/inflight/inflight.js +0 -54
  88. package/vendor/inflight/package.json +0 -29
package/lib/cli/cli.js ADDED
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict';
4
+
5
+ /**
6
+ * Contains CLI entry point and public API for programmatic usage in Node.js.
7
+ * - Option parsing is handled by {@link https://npm.im/yargs yargs}.
8
+ * - If executed via `node`, this module will run {@linkcode module:lib/cli.main main()}.
9
+ * @public
10
+ * @module lib/cli
11
+ */
12
+
13
+ const debug = require('debug')('mocha:cli:cli');
14
+ const symbols = require('log-symbols');
15
+ const yargs = require('yargs/yargs');
16
+ const path = require('path');
17
+ const {
18
+ loadRc,
19
+ loadPkgRc,
20
+ loadOptions,
21
+ YARGS_PARSER_CONFIG
22
+ } = require('./options');
23
+ const lookupFiles = require('./lookup-files');
24
+ const commands = require('./commands');
25
+ const ansi = require('ansi-colors');
26
+ const {repository, homepage, version, discord} = require('../../package.json');
27
+ const {cwd} = require('../utils');
28
+
29
+ /**
30
+ * - Accepts an `Array` of arguments
31
+ * - Modifies {@link https://nodejs.org/api/modules.html#modules_module_paths Node.js' search path} for easy loading of consumer modules
32
+ * - Sets {@linkcode https://nodejs.org/api/errors.html#errors_error_stacktracelimit Error.stackTraceLimit} to `Infinity`
33
+ * @public
34
+ * @summary Mocha's main command-line entry-point.
35
+ * @param {string[]} argv - Array of arguments to parse, or by default the lovely `process.argv.slice(2)`
36
+ * @param {object} [mochaArgs] - Object of already parsed Mocha arguments (by bin/mocha)
37
+ */
38
+ exports.main = (argv = process.argv.slice(2), mochaArgs) => {
39
+ debug('entered main with raw args', argv);
40
+ // ensure we can require() from current working directory
41
+ if (typeof module.paths !== 'undefined') {
42
+ module.paths.push(cwd(), path.resolve('node_modules'));
43
+ }
44
+
45
+ Error.stackTraceLimit = Infinity; // configurable via --stack-trace-limit?
46
+
47
+ var args = mochaArgs || loadOptions(argv);
48
+
49
+ yargs()
50
+ .scriptName('mocha-compat-10')
51
+ .command(commands.run)
52
+ .command(commands.init)
53
+ .updateStrings({
54
+ 'Positionals:': 'Positional Arguments',
55
+ 'Options:': 'Other Options',
56
+ 'Commands:': 'Commands'
57
+ })
58
+ .fail((msg, err, yargs) => {
59
+ debug('caught error sometime before command handler: %O', err);
60
+ yargs.showHelp();
61
+ console.error(`\n${symbols.error} ${ansi.red('ERROR:')} ${msg}`);
62
+ process.exitCode = 1;
63
+ })
64
+ .help('help', 'Show usage information & exit')
65
+ .alias('help', 'h')
66
+ .version('version', 'Show version number & exit', version)
67
+ .alias('version', 'V')
68
+ .wrap(process.stdout.columns ? Math.min(process.stdout.columns, 80) : 80)
69
+ .epilog(
70
+ `Mocha Resources
71
+ Chat: ${ansi.magenta(discord)}
72
+ GitHub: ${ansi.blue(repository.url)}
73
+ Docs: ${ansi.yellow(homepage)}
74
+ `
75
+ )
76
+ .parserConfiguration(YARGS_PARSER_CONFIG)
77
+ .config(args)
78
+ .parse(args._);
79
+ };
80
+
81
+ exports.lookupFiles = lookupFiles;
82
+ exports.loadOptions = loadOptions;
83
+ exports.loadPkgRc = loadPkgRc;
84
+ exports.loadRc = loadRc;
85
+
86
+ // allow direct execution
87
+ if (require.main === module) {
88
+ exports.main();
89
+ }
@@ -0,0 +1,137 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const ansi = require('ansi-colors');
6
+ const debug = require('debug')('mocha:cli:run:helpers');
7
+ const minimatch = require('minimatch');
8
+ const {NO_FILES_MATCH_PATTERN} = require('../errors').constants;
9
+ const lookupFiles = require('./lookup-files');
10
+ const {castArray} = require('../utils');
11
+
12
+ /**
13
+ * Exports a function that collects test files from CLI parameters.
14
+ * @see module:lib/cli/run-helpers
15
+ * @see module:lib/cli/watch-run
16
+ * @module
17
+ * @private
18
+ */
19
+
20
+ /**
21
+ * Smash together an array of test files in the correct order
22
+ * @param {FileCollectionOptions} [opts] - Options
23
+ * @returns {FileCollectionResponse} An object containing a list of files to test and unmatched files.
24
+ * @private
25
+ */
26
+ module.exports = ({
27
+ ignore,
28
+ extension,
29
+ file: fileArgs,
30
+ recursive,
31
+ sort,
32
+ spec
33
+ } = {}) => {
34
+ const unmatchedSpecFiles = [];
35
+ const specFiles = spec.reduce((specFiles, arg) => {
36
+ try {
37
+ const moreSpecFiles = castArray(lookupFiles(arg, extension, recursive))
38
+ .filter(filename =>
39
+ ignore.every(
40
+ pattern =>
41
+ !minimatch(filename, pattern, {windowsPathsNoEscape: true})
42
+ )
43
+ )
44
+ .map(filename => path.resolve(filename));
45
+ return [...specFiles, ...moreSpecFiles];
46
+ } catch (err) {
47
+ if (err.code === NO_FILES_MATCH_PATTERN) {
48
+ unmatchedSpecFiles.push({message: err.message, pattern: err.pattern});
49
+ return specFiles;
50
+ }
51
+
52
+ throw err;
53
+ }
54
+ }, []);
55
+
56
+ // check that each file passed in to --file exists
57
+
58
+ const unmatchedFiles = [];
59
+ fileArgs.forEach(file => {
60
+ const fileAbsolutePath = path.resolve(file);
61
+ try {
62
+ // Used instead of fs.existsSync to ensure that file-ending less files are still resolved correctly
63
+ require.resolve(fileAbsolutePath);
64
+ } catch (err) {
65
+ if (err.code === 'MODULE_NOT_FOUND') {
66
+ unmatchedFiles.push({
67
+ pattern: file,
68
+ absolutePath: fileAbsolutePath
69
+ });
70
+ return;
71
+ }
72
+
73
+ throw err;
74
+ }
75
+ });
76
+
77
+ // ensure we don't sort the stuff from fileArgs; order is important!
78
+ if (sort) {
79
+ specFiles.sort();
80
+ }
81
+
82
+ // add files given through --file to be ran first
83
+ const files = [
84
+ ...fileArgs.map(filepath => path.resolve(filepath)),
85
+ ...specFiles
86
+ ];
87
+ debug('test files (in order): ', files);
88
+
89
+ if (!files.length) {
90
+ // give full message details when only 1 file is missing
91
+ const noneFoundMsg =
92
+ unmatchedSpecFiles.length === 1
93
+ ? `Error: No test files found: ${JSON.stringify(
94
+ unmatchedSpecFiles[0].pattern
95
+ )}` // stringify to print escaped characters raw
96
+ : 'Error: No test files found';
97
+ console.error(ansi.red(noneFoundMsg));
98
+ process.exit(1);
99
+ } else {
100
+ // print messages as a warning
101
+ unmatchedSpecFiles.forEach(warning => {
102
+ console.warn(ansi.yellow(`Warning: ${warning.message}`));
103
+ });
104
+ }
105
+
106
+ return {
107
+ files,
108
+ unmatchedFiles
109
+ };
110
+ };
111
+
112
+ /**
113
+ * An object to configure how Mocha gathers test files
114
+ * @private
115
+ * @typedef {Object} FileCollectionOptions
116
+ * @property {string[]} extension - File extensions to use
117
+ * @property {string[]} spec - Files, dirs, globs to run
118
+ * @property {string[]} ignore - Files, dirs, globs to ignore
119
+ * @property {string[]} file - List of additional files to include
120
+ * @property {boolean} recursive - Find files recursively
121
+ * @property {boolean} sort - Sort test files
122
+ */
123
+
124
+ /**
125
+ * Diagnostic object containing unmatched files
126
+ * @typedef {Object} UnmatchedFile -
127
+ * @property {string} absolutePath - A list of unmatched files derived from the file arguments passed in.
128
+ * @property {string} pattern - A list of unmatched files derived from the file arguments passed in.
129
+ *
130
+ */
131
+
132
+ /**
133
+ * Response object containing a list of files to test and unmatched files.
134
+ * @typedef {Object} FileCollectionResponse
135
+ * @property {string[]} files - A list of files to test
136
+ * @property {UnmatchedFile[]} unmatchedFiles - A list of unmatched files derived from the file arguments passed in.
137
+ */
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Exports Yargs commands
5
+ * @see https://github.com/yargs/yargs/blob/main/docs/advanced.md
6
+ * @private
7
+ * @module
8
+ */
9
+
10
+ module.exports = {
11
+ init: require('./init'),
12
+ // default command
13
+ run: require('./run'),
14
+ }
@@ -0,0 +1,100 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Responsible for loading / finding Mocha's "rc" files.
5
+ *
6
+ * @private
7
+ * @module
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const debug = require('debug')('mocha:cli:config');
13
+ const findUp = require('find-up');
14
+ const {createUnparsableFileError} = require('../errors');
15
+ const utils = require('../utils');
16
+
17
+ /**
18
+ * These are the valid config files, in order of precedence;
19
+ * e.g., if `.mocharc.js` is present, then `.mocharc.yaml` and the rest
20
+ * will be ignored.
21
+ * The user should still be able to explicitly specify a file.
22
+ * @private
23
+ */
24
+ exports.CONFIG_FILES = [
25
+ '.mocharc.cjs',
26
+ '.mocharc.js',
27
+ '.mocharc.yaml',
28
+ '.mocharc.yml',
29
+ '.mocharc.jsonc',
30
+ '.mocharc.json'
31
+ ];
32
+
33
+ /**
34
+ * Parsers for various config filetypes. Each accepts a filepath and
35
+ * returns an object (but could throw)
36
+ */
37
+ const parsers = (exports.parsers = {
38
+ yaml: filepath => require('js-yaml').load(fs.readFileSync(filepath, 'utf8')),
39
+ js: filepath => {
40
+ let cwdFilepath;
41
+ try {
42
+ debug('parsers: load cwd-relative path: "%s"', path.resolve(filepath));
43
+ cwdFilepath = require.resolve(path.resolve(filepath)); // evtl. throws
44
+ return require(cwdFilepath);
45
+ } catch (err) {
46
+ if (cwdFilepath) throw err;
47
+
48
+ debug('parsers: retry load as module-relative path: "%s"', filepath);
49
+ return require(filepath);
50
+ }
51
+ },
52
+ json: filepath =>
53
+ JSON.parse(
54
+ require('strip-json-comments')(fs.readFileSync(filepath, 'utf8'))
55
+ )
56
+ });
57
+
58
+ /**
59
+ * Loads and parses, based on file extension, a config file.
60
+ * "JSON" files may have comments.
61
+ *
62
+ * @private
63
+ * @param {string} filepath - Config file path to load
64
+ * @returns {Object} Parsed config object
65
+ */
66
+ exports.loadConfig = filepath => {
67
+ let config = {};
68
+ debug('loadConfig: trying to parse config at %s', filepath);
69
+
70
+ const ext = path.extname(filepath);
71
+ try {
72
+ if (ext === '.yml' || ext === '.yaml') {
73
+ config = parsers.yaml(filepath);
74
+ } else if (ext === '.js' || ext === '.cjs') {
75
+ config = parsers.js(filepath);
76
+ } else {
77
+ config = parsers.json(filepath);
78
+ }
79
+ } catch (err) {
80
+ throw createUnparsableFileError(
81
+ `Unable to read/parse ${filepath}: ${err}`,
82
+ filepath
83
+ );
84
+ }
85
+ return config;
86
+ };
87
+
88
+ /**
89
+ * Find ("find up") config file starting at `cwd`
90
+ *
91
+ * @param {string} [cwd] - Current working directory
92
+ * @returns {string|null} Filepath to config, if found
93
+ */
94
+ exports.findConfig = (cwd = utils.cwd()) => {
95
+ const filepath = findUp.sync(exports.CONFIG_FILES, {cwd});
96
+ if (filepath) {
97
+ debug('findConfig: found config file %s', filepath);
98
+ }
99
+ return filepath;
100
+ };
@@ -0,0 +1,3 @@
1
+ 'use strict';
2
+
3
+ module.exports = require('./cli');
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Command module for "init" command
5
+ *
6
+ * @private
7
+ * @module
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+
13
+ exports.command = 'init <path>';
14
+
15
+ exports.description = 'create a client-side Mocha setup at <path>';
16
+
17
+ exports.builder = yargs =>
18
+ yargs.positional('path', {
19
+ type: 'string',
20
+ normalize: true
21
+ });
22
+
23
+ exports.handler = argv => {
24
+ const destdir = argv.path;
25
+ const srcdir = path.join(__dirname, '..', '..');
26
+ fs.mkdirSync(destdir, {recursive: true});
27
+ const css = fs.readFileSync(path.join(srcdir, 'mocha.css'));
28
+ const js = fs.readFileSync(path.join(srcdir, 'mocha.js'));
29
+ const tmpl = fs.readFileSync(
30
+ path.join(srcdir, 'lib', 'browser', 'template.html')
31
+ );
32
+ fs.writeFileSync(path.join(destdir, 'mocha.css'), css);
33
+ fs.writeFileSync(path.join(destdir, 'mocha.js'), js);
34
+ fs.writeFileSync(path.join(destdir, 'tests.spec.js'), '');
35
+ fs.writeFileSync(path.join(destdir, 'index.html'), tmpl);
36
+ };
@@ -0,0 +1,150 @@
1
+ 'use strict';
2
+ /**
3
+ * Contains `lookupFiles`, which takes some globs/dirs/options and returns a list of files.
4
+ * @module
5
+ * @private
6
+ */
7
+
8
+ var fs = require('fs');
9
+ var path = require('path');
10
+ var glob = require('glob');
11
+ var errors = require('../errors');
12
+ var createNoFilesMatchPatternError = errors.createNoFilesMatchPatternError;
13
+ var createMissingArgumentError = errors.createMissingArgumentError;
14
+ const debug = require('debug')('mocha:cli:lookup-files');
15
+
16
+ /**
17
+ * Determines if pathname would be a "hidden" file (or directory) on UN*X.
18
+ *
19
+ * @description
20
+ * On UN*X, pathnames beginning with a full stop (aka dot) are hidden during
21
+ * typical usage. Dotfiles, plain-text configuration files, are prime examples.
22
+ *
23
+ * @see {@link http://xahlee.info/UnixResource_dir/writ/unix_origin_of_dot_filename.html|Origin of Dot File Names}
24
+ *
25
+ * @private
26
+ * @param {string} pathname - Pathname to check for match.
27
+ * @return {boolean} whether pathname would be considered a hidden file.
28
+ * @example
29
+ * isHiddenOnUnix('.profile'); // => true
30
+ */
31
+ const isHiddenOnUnix = pathname => path.basename(pathname).startsWith('.');
32
+
33
+ /**
34
+ * Determines if pathname has a matching file extension.
35
+ *
36
+ * Supports multi-part extensions.
37
+ *
38
+ * @private
39
+ * @param {string} pathname - Pathname to check for match.
40
+ * @param {string[]} exts - List of file extensions, w/-or-w/o leading period
41
+ * @return {boolean} `true` if file extension matches.
42
+ * @example
43
+ * hasMatchingExtname('foo.html', ['js', 'css']); // false
44
+ * hasMatchingExtname('foo.js', ['.js']); // true
45
+ * hasMatchingExtname('foo.js', ['js']); // ture
46
+ */
47
+ const hasMatchingExtname = (pathname, exts = []) =>
48
+ exts
49
+ .map(ext => (ext.startsWith('.') ? ext : `.${ext}`))
50
+ .some(ext => pathname.endsWith(ext));
51
+
52
+ /**
53
+ * Lookup file names at the given `path`.
54
+ *
55
+ * @description
56
+ * Filenames are returned in _traversal_ order by the OS/filesystem.
57
+ * **Make no assumption that the names will be sorted in any fashion.**
58
+ *
59
+ * @public
60
+ * @alias module:lib/cli.lookupFiles
61
+ * @param {string} filepath - Base path to start searching from.
62
+ * @param {string[]} [extensions=[]] - File extensions to look for.
63
+ * @param {boolean} [recursive=false] - Whether to recurse into subdirectories.
64
+ * @return {string[]} An array of paths.
65
+ * @throws {Error} if no files match pattern.
66
+ * @throws {TypeError} if `filepath` is directory and `extensions` not provided.
67
+ */
68
+ module.exports = function lookupFiles(
69
+ filepath,
70
+ extensions = [],
71
+ recursive = false
72
+ ) {
73
+ const files = [];
74
+ let stat;
75
+
76
+ if (!fs.existsSync(filepath)) {
77
+ let pattern;
78
+ if (glob.hasMagic(filepath, {windowsPathsNoEscape: true})) {
79
+ // Handle glob as is without extensions
80
+ pattern = filepath;
81
+ } else {
82
+ // glob pattern e.g. 'filepath+(.js|.ts)'
83
+ const strExtensions = extensions
84
+ .map(ext => (ext.startsWith('.') ? ext : `.${ext}`))
85
+ .join('|');
86
+ pattern = `${filepath}+(${strExtensions})`;
87
+ debug('looking for files using glob pattern: %s', pattern);
88
+ }
89
+ files.push(
90
+ ...glob.sync(pattern, {
91
+ nodir: true,
92
+ windowsPathsNoEscape: true
93
+ })
94
+ );
95
+ if (!files.length) {
96
+ throw createNoFilesMatchPatternError(
97
+ `Cannot find any files matching pattern "${filepath}"`,
98
+ filepath
99
+ );
100
+ }
101
+ return files;
102
+ }
103
+
104
+ // Handle file
105
+ try {
106
+ stat = fs.statSync(filepath);
107
+ if (stat.isFile()) {
108
+ return filepath;
109
+ }
110
+ } catch (err) {
111
+ // ignore error
112
+ return;
113
+ }
114
+
115
+ // Handle directory
116
+ fs.readdirSync(filepath).forEach(dirent => {
117
+ const pathname = path.join(filepath, dirent);
118
+ let stat;
119
+
120
+ try {
121
+ stat = fs.statSync(pathname);
122
+ if (stat.isDirectory()) {
123
+ if (recursive) {
124
+ files.push(...lookupFiles(pathname, extensions, recursive));
125
+ }
126
+ return;
127
+ }
128
+ } catch (ignored) {
129
+ return;
130
+ }
131
+ if (!extensions.length) {
132
+ throw createMissingArgumentError(
133
+ `Argument '${extensions}' required when argument '${filepath}' is a directory`,
134
+ 'extensions',
135
+ 'array'
136
+ );
137
+ }
138
+
139
+ if (
140
+ !stat.isFile() ||
141
+ !hasMatchingExtname(pathname, extensions) ||
142
+ isHiddenOnUnix(pathname)
143
+ ) {
144
+ return;
145
+ }
146
+ files.push(pathname);
147
+ });
148
+
149
+ return files;
150
+ };
@@ -0,0 +1,85 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Some settings and code related to Mocha's handling of Node.js/V8 flags.
5
+ * @private
6
+ * @module
7
+ */
8
+
9
+ const nodeFlags = process.allowedNodeEnvironmentFlags;
10
+ const {isMochaFlag} = require('./run-option-metadata');
11
+ const unparse = require('yargs-unparser');
12
+
13
+ /**
14
+ * These flags are considered "debug" flags.
15
+ * @see {@link impliesNoTimeouts}
16
+ * @private
17
+ */
18
+ const debugFlags = new Set(['inspect', 'inspect-brk']);
19
+
20
+ /**
21
+ * Mocha has historical support for various `node` and V8 flags which might not
22
+ * appear in `process.allowedNodeEnvironmentFlags`.
23
+ * These include:
24
+ * - `--preserve-symlinks`
25
+ * - `--harmony-*`
26
+ * - `--gc-global`
27
+ * - `--trace-*`
28
+ * - `--es-staging`
29
+ * - `--use-strict`
30
+ * - `--v8-*` (but *not* `--v8-options`)
31
+ * @summary Whether or not to pass a flag along to the `node` executable.
32
+ * @param {string} flag - Flag to test
33
+ * @param {boolean} [bareword=true] - If `false`, we expect `flag` to have one or two leading dashes.
34
+ * @returns {boolean} If the flag is considered a "Node" flag.
35
+ * @private
36
+ */
37
+ exports.isNodeFlag = (flag, bareword = true) => {
38
+ if (!bareword) {
39
+ // check if the flag begins with dashes; if not, not a node flag.
40
+ if (!/^--?/.test(flag)) {
41
+ return false;
42
+ }
43
+ // strip the leading dashes to match against subsequent checks
44
+ flag = flag.replace(/^--?/, '');
45
+ }
46
+ return (
47
+ // check actual node flags from `process.allowedNodeEnvironmentFlags`,
48
+ // then historical support for various V8 and non-`NODE_OPTIONS` flags
49
+ // and also any V8 flags with `--v8-` prefix
50
+ (!isMochaFlag(flag) && nodeFlags && nodeFlags.has(flag)) ||
51
+ debugFlags.has(flag) ||
52
+ /(?:preserve-symlinks(?:-main)?|harmony(?:[_-]|$)|(?:trace[_-].+$)|gc[_-]global$|es[_-]staging$|use[_-]strict$|v8[_-](?!options).+?$)/.test(
53
+ flag
54
+ )
55
+ );
56
+ };
57
+
58
+ /**
59
+ * Returns `true` if the flag is a "debug-like" flag. These require timeouts
60
+ * to be suppressed, or pausing the debugger on breakpoints will cause test failures.
61
+ * @param {string} flag - Flag to test
62
+ * @returns {boolean}
63
+ * @private
64
+ */
65
+ exports.impliesNoTimeouts = flag => debugFlags.has(flag);
66
+
67
+ /**
68
+ * All non-strictly-boolean arguments to node--those with values--must specify those values using `=`, e.g., `--inspect=0.0.0.0`.
69
+ * Unparse these arguments using `yargs-unparser` (which would result in `--inspect 0.0.0.0`), then supply `=` where we have values.
70
+ * There's probably an easier or more robust way to do this; fixes welcome
71
+ * @param {Object} opts - Arguments object
72
+ * @returns {string[]} Unparsed arguments using `=` to specify values
73
+ * @private
74
+ */
75
+ exports.unparseNodeFlags = opts => {
76
+ var args = unparse(opts);
77
+ return args.length
78
+ ? args
79
+ .join(' ')
80
+ .split(/\b/)
81
+ .map(arg => (arg === ' ' ? '=' : arg))
82
+ .join('')
83
+ .split(' ')
84
+ : [];
85
+ };
@@ -0,0 +1,69 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Contains "command" code for "one-and-dones"--options passed
5
+ * to Mocha which cause it to just dump some info and exit.
6
+ * See {@link module:lib/cli/one-and-dones.ONE_AND_DONE_ARGS ONE_AND_DONE_ARGS} for more info.
7
+ * @module
8
+ * @private
9
+ */
10
+
11
+ const Mocha = require('../mocha');
12
+
13
+ /**
14
+ * Dumps a sorted list of the enumerable, lower-case keys of some object
15
+ * to `STDOUT`.
16
+ * @param {Object} obj - Object, ostensibly having some enumerable keys
17
+ * @ignore
18
+ * @private
19
+ */
20
+ const showKeys = obj => {
21
+ console.log();
22
+ const keys = Object.keys(obj);
23
+ const maxKeyLength = keys.reduce((max, key) => Math.max(max, key.length), 0);
24
+ keys
25
+ .filter(
26
+ key => /^[a-z]/.test(key) && !obj[key].browserOnly && !obj[key].abstract
27
+ )
28
+ .sort()
29
+ .forEach(key => {
30
+ const description = obj[key].description;
31
+ console.log(
32
+ ` ${key.padEnd(maxKeyLength + 1)}${
33
+ description ? `- ${description}` : ''
34
+ }`
35
+ );
36
+ });
37
+ console.log();
38
+ };
39
+
40
+ /**
41
+ * Handlers for one-and-done options
42
+ * @namespace
43
+ * @private
44
+ */
45
+ exports.ONE_AND_DONES = {
46
+ /**
47
+ * Dump list of built-in interfaces
48
+ * @private
49
+ */
50
+ 'list-interfaces': () => {
51
+ showKeys(Mocha.interfaces);
52
+ },
53
+ /**
54
+ * Dump list of built-in reporters
55
+ * @private
56
+ */
57
+ 'list-reporters': () => {
58
+ showKeys(Mocha.reporters);
59
+ }
60
+ };
61
+
62
+ /**
63
+ * A Set of all one-and-done options
64
+ * @type Set<string>
65
+ * @private
66
+ */
67
+ exports.ONE_AND_DONE_ARGS = new Set(
68
+ ['help', 'h', 'version', 'V'].concat(Object.keys(exports.ONE_AND_DONES))
69
+ );