aboutsummaryrefslogtreecommitdiff
path: root/node_modules/istanbul/lib/command/common
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2017-05-03 15:35:00 +0200
committerFlorian Dold <florian.dold@gmail.com>2017-05-03 15:35:00 +0200
commitde98e0b232509d5f40c135d540a70e415272ff85 (patch)
treea79222a5b58484ab3b80d18efcaaa7ccc4769b33 /node_modules/istanbul/lib/command/common
parente0c9d480a73fa629c1e4a47d3e721f1d2d345406 (diff)
node_modules
Diffstat (limited to 'node_modules/istanbul/lib/command/common')
-rw-r--r--node_modules/istanbul/lib/command/common/run-with-cover.js261
1 files changed, 261 insertions, 0 deletions
diff --git a/node_modules/istanbul/lib/command/common/run-with-cover.js b/node_modules/istanbul/lib/command/common/run-with-cover.js
new file mode 100644
index 000000000..d4c5fafe4
--- /dev/null
+++ b/node_modules/istanbul/lib/command/common/run-with-cover.js
@@ -0,0 +1,261 @@
+/*
+ Copyright (c) 2012, Yahoo! Inc. All rights reserved.
+ Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
+ */
+var Module = require('module'),
+ path = require('path'),
+ fs = require('fs'),
+ nopt = require('nopt'),
+ which = require('which'),
+ mkdirp = require('mkdirp'),
+ existsSync = fs.existsSync || path.existsSync,
+ inputError = require('../../util/input-error'),
+ matcherFor = require('../../util/file-matcher').matcherFor,
+ Instrumenter = require('../../instrumenter'),
+ Collector = require('../../collector'),
+ formatOption = require('../../util/help-formatter').formatOption,
+ hook = require('../../hook'),
+ Reporter = require('../../reporter'),
+ resolve = require('resolve'),
+ configuration = require('../../config');
+
+function usage(arg0, command) {
+
+ console.error('\nUsage: ' + arg0 + ' ' + command + ' [<options>] <executable-js-file-or-command> [-- <arguments-to-jsfile>]\n\nOptions are:\n\n'
+ + [
+ formatOption('--config <path-to-config>', 'the configuration file to use, defaults to .istanbul.yml'),
+ formatOption('--root <path> ', 'the root path to look for files to instrument, defaults to .'),
+ formatOption('-x <exclude-pattern> [-x <exclude-pattern>]', 'one or more glob patterns e.g. "**/vendor/**"'),
+ formatOption('-i <include-pattern> [-i <include-pattern>]', 'one or more glob patterns e.g. "**/*.js"'),
+ formatOption('--[no-]default-excludes', 'apply default excludes [ **/node_modules/**, **/test/**, **/tests/** ], defaults to true'),
+ formatOption('--hook-run-in-context', 'hook vm.runInThisContext in addition to require (supports RequireJS), defaults to false'),
+ formatOption('--post-require-hook <file> | <module>', 'JS module that exports a function for post-require processing'),
+ formatOption('--report <format> [--report <format>] ', 'report format, defaults to lcov (= lcov.info + HTML)'),
+ formatOption('--dir <report-dir>', 'report directory, defaults to ./coverage'),
+ formatOption('--print <type>', 'type of report to print to console, one of summary (default), detail, both or none'),
+ formatOption('--verbose, -v', 'verbose mode'),
+ formatOption('--[no-]preserve-comments', 'remove / preserve comments in the output, defaults to false'),
+ formatOption('--include-all-sources', 'instrument all unused sources after running tests, defaults to false'),
+ formatOption('--[no-]include-pid', 'include PID in output coverage filename')
+ ].join('\n\n') + '\n');
+ console.error('\n');
+}
+
+function run(args, commandName, enableHooks, callback) {
+
+ var template = {
+ config: path,
+ root: path,
+ x: [ Array, String ],
+ report: [Array, String ],
+ dir: path,
+ verbose: Boolean,
+ yui: Boolean,
+ 'default-excludes': Boolean,
+ print: String,
+ 'self-test': Boolean,
+ 'hook-run-in-context': Boolean,
+ 'post-require-hook': String,
+ 'preserve-comments': Boolean,
+ 'include-all-sources': Boolean,
+ 'preload-sources': Boolean,
+ i: [ Array, String ],
+ 'include-pid': Boolean
+ },
+ opts = nopt(template, { v : '--verbose' }, args, 0),
+ overrides = {
+ verbose: opts.verbose,
+ instrumentation: {
+ root: opts.root,
+ 'default-excludes': opts['default-excludes'],
+ excludes: opts.x,
+ 'include-all-sources': opts['include-all-sources'],
+ 'preload-sources': opts['preload-sources'],
+ 'include-pid': opts['include-pid']
+ },
+ reporting: {
+ reports: opts.report,
+ print: opts.print,
+ dir: opts.dir
+ },
+ hooks: {
+ 'hook-run-in-context': opts['hook-run-in-context'],
+ 'post-require-hook': opts['post-require-hook'],
+ 'handle-sigint': opts['handle-sigint']
+ }
+ },
+ config = configuration.loadFile(opts.config, overrides),
+ verbose = config.verbose,
+ cmdAndArgs = opts.argv.remain,
+ preserveComments = opts['preserve-comments'],
+ includePid = opts['include-pid'],
+ cmd,
+ cmdArgs,
+ reportingDir,
+ reporter = new Reporter(config),
+ runFn,
+ excludes;
+
+ if (cmdAndArgs.length === 0) {
+ return callback(inputError.create('Need a filename argument for the ' + commandName + ' command!'));
+ }
+
+ cmd = cmdAndArgs.shift();
+ cmdArgs = cmdAndArgs;
+
+ if (!existsSync(cmd)) {
+ try {
+ cmd = which.sync(cmd);
+ } catch (ex) {
+ return callback(inputError.create('Unable to resolve file [' + cmd + ']'));
+ }
+ } else {
+ cmd = path.resolve(cmd);
+ }
+
+ runFn = function () {
+ process.argv = ["node", cmd].concat(cmdArgs);
+ if (verbose) {
+ console.log('Running: ' + process.argv.join(' '));
+ }
+ process.env.running_under_istanbul=1;
+ Module.runMain(cmd, null, true);
+ };
+
+ excludes = config.instrumentation.excludes(true);
+
+ if (enableHooks) {
+ reportingDir = path.resolve(config.reporting.dir());
+ mkdirp.sync(reportingDir); //ensure we fail early if we cannot do this
+ reporter.dir = reportingDir;
+ reporter.addAll(config.reporting.reports());
+ if (config.reporting.print() !== 'none') {
+ switch (config.reporting.print()) {
+ case 'detail':
+ reporter.add('text');
+ break;
+ case 'both':
+ reporter.add('text');
+ reporter.add('text-summary');
+ break;
+ default:
+ reporter.add('text-summary');
+ break;
+ }
+ }
+
+ excludes.push(path.relative(process.cwd(), path.join(reportingDir, '**', '*')));
+ matcherFor({
+ root: config.instrumentation.root() || process.cwd(),
+ includes: opts.i || config.instrumentation.extensions().map(function (ext) {
+ return '**/*' + ext;
+ }),
+ excludes: excludes
+ },
+ function (err, matchFn) {
+ if (err) { return callback(err); }
+
+ var coverageVar = '$$cov_' + new Date().getTime() + '$$',
+ instrumenter = new Instrumenter({ coverageVariable: coverageVar , preserveComments: preserveComments}),
+ transformer = instrumenter.instrumentSync.bind(instrumenter),
+ hookOpts = { verbose: verbose, extensions: config.instrumentation.extensions() },
+ postRequireHook = config.hooks.postRequireHook(),
+ postLoadHookFile;
+
+ if (postRequireHook) {
+ postLoadHookFile = path.resolve(postRequireHook);
+ } else if (opts.yui) { //EXPERIMENTAL code: do not rely on this in anyway until the docs say it is allowed
+ postLoadHookFile = path.resolve(__dirname, '../../util/yui-load-hook');
+ }
+
+ if (postRequireHook) {
+ if (!existsSync(postLoadHookFile)) { //assume it is a module name and resolve it
+ try {
+ postLoadHookFile = resolve.sync(postRequireHook, { basedir: process.cwd() });
+ } catch (ex) {
+ if (verbose) { console.error('Unable to resolve [' + postRequireHook + '] as a node module'); }
+ callback(ex);
+ return;
+ }
+ }
+ }
+ if (postLoadHookFile) {
+ if (verbose) { console.error('Use post-load-hook: ' + postLoadHookFile); }
+ hookOpts.postLoadHook = require(postLoadHookFile)(matchFn, transformer, verbose);
+ }
+
+ if (opts['self-test']) {
+ hook.unloadRequireCache(matchFn);
+ }
+ // runInThisContext is used by RequireJS [issue #23]
+ if (config.hooks.hookRunInContext()) {
+ hook.hookRunInThisContext(matchFn, transformer, hookOpts);
+ }
+ hook.hookRequire(matchFn, transformer, hookOpts);
+
+ //initialize the global variable to stop mocha from complaining about leaks
+ global[coverageVar] = {};
+
+ // enable passing --handle-sigint to write reports on SIGINT.
+ // This allows a user to manually kill a process while
+ // still getting the istanbul report.
+ if (config.hooks.handleSigint()) {
+ process.once('SIGINT', process.exit);
+ }
+
+ process.once('exit', function () {
+ var pidExt = includePid ? ('-' + process.pid) : '',
+ file = path.resolve(reportingDir, 'coverage' + pidExt + '.json'),
+ collector,
+ cov;
+ if (typeof global[coverageVar] === 'undefined' || Object.keys(global[coverageVar]).length === 0) {
+ console.error('No coverage information was collected, exit without writing coverage information');
+ return;
+ } else {
+ cov = global[coverageVar];
+ }
+ //important: there is no event loop at this point
+ //everything that happens in this exit handler MUST be synchronous
+ if (config.instrumentation.includeAllSources()) {
+ // Files that are not touched by code ran by the test runner is manually instrumented, to
+ // illustrate the missing coverage.
+ matchFn.files.forEach(function (file) {
+ if (!cov[file]) {
+ transformer(fs.readFileSync(file, 'utf-8'), file);
+
+ // When instrumenting the code, istanbul will give each FunctionDeclaration a value of 1 in coverState.s,
+ // presumably to compensate for function hoisting. We need to reset this, as the function was not hoisted,
+ // as it was never loaded.
+ Object.keys(instrumenter.coverState.s).forEach(function (key) {
+ instrumenter.coverState.s[key] = 0;
+ });
+
+ cov[file] = instrumenter.coverState;
+ }
+ });
+ }
+ mkdirp.sync(reportingDir); //yes, do this again since some test runners could clean the dir initially created
+ if (config.reporting.print() !== 'none') {
+ console.error('=============================================================================');
+ console.error('Writing coverage object [' + file + ']');
+ }
+ fs.writeFileSync(file, JSON.stringify(cov), 'utf8');
+ collector = new Collector();
+ collector.add(cov);
+ if (config.reporting.print() !== 'none') {
+ console.error('Writing coverage reports at [' + reportingDir + ']');
+ console.error('=============================================================================');
+ }
+ reporter.write(collector, true, callback);
+ });
+ runFn();
+ });
+ } else {
+ runFn();
+ }
+}
+
+module.exports = {
+ run: run,
+ usage: usage
+};