'use strict'; const defaultExclude = require('./default-exclude.js'); const nycCommands = { all: [null, 'check-coverage', 'instrument', 'merge', 'report'], testExclude: [null, 'instrument', 'report', 'check-coverage'], instrument: [null, 'instrument'], checkCoverage: [null, 'report', 'check-coverage'], report: [null, 'report'], main: [null], instrumentOnly: ['instrument'] }; const cwd = { description: 'working directory used when resolving paths', type: 'string', get default() { return process.cwd(); }, nycCommands: nycCommands.all }; const nycrcPath = { description: 'specify an explicit path to find nyc configuration', nycCommands: nycCommands.all }; const tempDir = { description: 'directory to output raw coverage information to', type: 'string', default: './.nyc_output', nycAlias: 't', nycHiddenAlias: 'temp-directory', nycCommands: [null, 'check-coverage', 'merge', 'report'] }; const testExclude = { exclude: { description: 'a list of specific files and directories that should be excluded from coverage, glob patterns are supported', type: 'array', items: { type: 'string' }, default: defaultExclude, nycCommands: nycCommands.testExclude, nycAlias: 'x' }, excludeNodeModules: { description: 'whether or not to exclude all node_module folders (i.e. **/node_modules/**) by default', type: 'boolean', default: true, nycCommands: nycCommands.testExclude }, include: { description: 'a list of specific files that should be covered, glob patterns are supported', type: 'array', items: { type: 'string' }, default: [], nycCommands: nycCommands.testExclude, nycAlias: 'n' }, extension: { description: 'a list of extensions that nyc should handle in addition to .js', type: 'array', items: { type: 'string' }, default: ['.js', '.cjs', '.mjs', '.ts', '.tsx', '.jsx'], nycCommands: nycCommands.testExclude, nycAlias: 'e' } }; const instrumentVisitor = { coverageVariable: { description: 'variable to store coverage', type: 'string', default: '__coverage__', nycCommands: nycCommands.instrument }, coverageGlobalScope: { description: 'scope to store the coverage variable', type: 'string', default: 'this', nycCommands: nycCommands.instrument }, coverageGlobalScopeFunc: { description: 'avoid potentially replaced `Function` when finding global scope', type: 'boolean', default: true, nycCommands: nycCommands.instrument }, ignoreClassMethods: { description: 'class method names to ignore for coverage', type: 'array', items: { type: 'string' }, default: [], nycCommands: nycCommands.instrument } }; const instrumentParseGen = { autoWrap: { description: 'allow `return` statements outside of functions', type: 'boolean', default: true, nycCommands: nycCommands.instrument }, esModules: { description: 'should files be treated as ES Modules', type: 'boolean', default: true, nycCommands: nycCommands.instrument }, parserPlugins: { description: 'babel parser plugins to use when parsing the source', type: 'array', items: { type: 'string' }, /* Babel parser plugins are to be enabled when the feature is stage 3 and * implemented in a released version of node.js. */ default: [ 'asyncGenerators', 'bigInt', 'classProperties', 'classPrivateProperties', 'dynamicImport', 'importMeta', 'objectRestSpread', 'optionalCatchBinding' ], nycCommands: nycCommands.instrument }, compact: { description: 'should the output be compacted?', type: 'boolean', default: true, nycCommands: nycCommands.instrument }, preserveComments: { description: 'should comments be preserved in the output?', type: 'boolean', default: true, nycCommands: nycCommands.instrument }, produceSourceMap: { description: 'should source maps be produced?', type: 'boolean', default: true, nycCommands: nycCommands.instrument } }; const checkCoverage = { excludeAfterRemap: { description: 'should exclude logic be performed after the source-map remaps filenames?', type: 'boolean', default: true, nycCommands: nycCommands.checkCoverage }, branches: { description: 'what % of branches must be covered?', type: 'number', default: 0, minimum: 0, maximum: 100, nycCommands: nycCommands.checkCoverage }, functions: { description: 'what % of functions must be covered?', type: 'number', default: 0, minimum: 0, maximum: 100, nycCommands: nycCommands.checkCoverage }, lines: { description: 'what % of lines must be covered?', type: 'number', default: 90, minimum: 0, maximum: 100, nycCommands: nycCommands.checkCoverage }, statements: { description: 'what % of statements must be covered?', type: 'number', default: 0, minimum: 0, maximum: 100, nycCommands: nycCommands.checkCoverage }, perFile: { description: 'check thresholds per file', type: 'boolean', default: false, nycCommands: nycCommands.checkCoverage } }; const report = { checkCoverage: { description: 'check whether coverage is within thresholds provided', type: 'boolean', default: false, nycCommands: nycCommands.report }, reporter: { description: 'coverage reporter(s) to use', type: 'array', items: { type: 'string' }, default: ['text'], nycCommands: nycCommands.report, nycAlias: 'r' }, reportDir: { description: 'directory to output coverage reports in', type: 'string', default: 'coverage', nycCommands: nycCommands.report }, showProcessTree: { description: 'display the tree of spawned processes', type: 'boolean', default: false, nycCommands: nycCommands.report }, skipEmpty: { description: 'don\'t show empty files (no lines of code) in report', type: 'boolean', default: false, nycCommands: nycCommands.report }, skipFull: { description: 'don\'t show files with 100% statement, branch, and function coverage', type: 'boolean', default: false, nycCommands: nycCommands.report } }; const nycMain = { silent: { description: 'don\'t output a report after tests finish running', type: 'boolean', default: false, nycCommands: nycCommands.main, nycAlias: 's' }, all: { description: 'whether or not to instrument all files of the project (not just the ones touched by your test suite)', type: 'boolean', default: false, nycCommands: nycCommands.main, nycAlias: 'a' }, eager: { description: 'instantiate the instrumenter at startup (see https://git.io/vMKZ9)', type: 'boolean', default: false, nycCommands: nycCommands.main }, cache: { description: 'cache instrumentation results for improved performance', type: 'boolean', default: true, nycCommands: nycCommands.main, nycAlias: 'c' }, cacheDir: { description: 'explicitly set location for instrumentation cache', type: 'string', nycCommands: nycCommands.main }, babelCache: { description: 'cache babel transpilation results for improved performance', type: 'boolean', default: false, nycCommands: nycCommands.main }, useSpawnWrap: { description: 'use spawn-wrap instead of setting process.env.NODE_OPTIONS', type: 'boolean', default: false, nycCommands: nycCommands.main }, hookRequire: { description: 'should nyc wrap require?', type: 'boolean', default: true, nycCommands: nycCommands.main }, hookRunInContext: { description: 'should nyc wrap vm.runInContext?', type: 'boolean', default: false, nycCommands: nycCommands.main }, hookRunInThisContext: { description: 'should nyc wrap vm.runInThisContext?', type: 'boolean', default: false, nycCommands: nycCommands.main }, clean: { description: 'should the .nyc_output folder be cleaned before executing tests', type: 'boolean', default: true, nycCommands: nycCommands.main } }; const instrumentOnly = { inPlace: { description: 'should nyc run the instrumentation in place?', type: 'boolean', default: false, nycCommands: nycCommands.instrumentOnly }, exitOnError: { description: 'should nyc exit when an instrumentation failure occurs?', type: 'boolean', default: false, nycCommands: nycCommands.instrumentOnly }, delete: { description: 'should the output folder be deleted before instrumenting files?', type: 'boolean', default: false, nycCommands: nycCommands.instrumentOnly }, completeCopy: { description: 'should nyc copy all files from input to output as well as instrumented files?', type: 'boolean', default: false, nycCommands: nycCommands.instrumentOnly } }; const nyc = { description: 'nyc configuration options', type: 'object', properties: { cwd, nycrcPath, tempDir, /* Test Exclude */ ...testExclude, /* Instrumentation settings */ ...instrumentVisitor, /* Instrumentation parser/generator settings */ ...instrumentParseGen, sourceMap: { description: 'should nyc detect and handle source maps?', type: 'boolean', default: true, nycCommands: nycCommands.instrument }, require: { description: 'a list of additional modules that nyc should attempt to require in its subprocess, e.g., @babel/register, @babel/polyfill', type: 'array', items: { type: 'string' }, default: [], nycCommands: nycCommands.instrument, nycAlias: 'i' }, instrument: { description: 'should nyc handle instrumentation?', type: 'boolean', default: true, nycCommands: nycCommands.instrument }, /* Check coverage */ ...checkCoverage, /* Report options */ ...report, /* Main command options */ ...nycMain, /* Instrument command options */ ...instrumentOnly } }; const configs = { nyc, testExclude: { description: 'test-exclude options', type: 'object', properties: { cwd, ...testExclude } }, babelPluginIstanbul: { description: 'babel-plugin-istanbul options', type: 'object', properties: { cwd, ...testExclude, ...instrumentVisitor } }, instrumentVisitor: { description: 'instrument visitor options', type: 'object', properties: instrumentVisitor }, instrumenter: { description: 'stand-alone instrumenter options', type: 'object', properties: { ...instrumentVisitor, ...instrumentParseGen } } }; function defaultsReducer(defaults, [name, {default: value}]) { /* Modifying arrays in defaults is safe, does not change schema. */ if (Array.isArray(value)) { value = [...value]; } return Object.assign(defaults, {[name]: value}); } module.exports = { ...configs, defaults: Object.keys(configs).reduce( (defaults, id) => { Object.defineProperty(defaults, id, { enumerable: true, get() { /* This defers `process.cwd()` until defaults are requested. */ return Object.entries(configs[id].properties) .filter(([, info]) => 'default' in info) .reduce(defaultsReducer, {}); } }); return defaults; }, {} ) };