parse-args.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. const defaultExclude = require('@istanbuljs/schema/default-exclude')
  2. const defaultExtension = require('@istanbuljs/schema/default-extension')
  3. const findUp = require('find-up')
  4. const { readFileSync } = require('fs')
  5. const Yargs = require('yargs/yargs')
  6. const { applyExtends } = require('yargs/helpers')
  7. const parser = require('yargs-parser')
  8. const { resolve } = require('path')
  9. function buildYargs (withCommands = false) {
  10. const yargs = Yargs([])
  11. .usage('$0 [opts] [script] [opts]')
  12. .options('config', {
  13. alias: 'c',
  14. config: true,
  15. describe: 'path to JSON configuration file',
  16. configParser: (path) => {
  17. const config = JSON.parse(readFileSync(path))
  18. return applyExtends(config, process.cwd(), true)
  19. },
  20. default: () => findUp.sync(['.c8rc', '.c8rc.json', '.nycrc', '.nycrc.json'])
  21. })
  22. .option('reporter', {
  23. alias: 'r',
  24. group: 'Reporting options',
  25. describe: 'coverage reporter(s) to use',
  26. default: 'text'
  27. })
  28. .option('reports-dir', {
  29. alias: ['o', 'report-dir'],
  30. group: 'Reporting options',
  31. describe: 'directory where coverage reports will be output to',
  32. default: './coverage'
  33. })
  34. .options('all', {
  35. default: false,
  36. type: 'boolean',
  37. group: 'Reporting options',
  38. describe: 'supplying --all will cause c8 to consider all src files in the current working directory ' +
  39. 'when the determining coverage. Respects include/exclude.'
  40. })
  41. .options('src', {
  42. default: undefined,
  43. type: 'string',
  44. group: 'Reporting options',
  45. describe: 'supplying --src will override cwd as the default location where --all looks for src files. --src can be ' +
  46. 'supplied multiple times and each directory will be included. This allows for workspaces spanning multiple projects'
  47. })
  48. .option('exclude-node-modules', {
  49. default: true,
  50. type: 'boolean',
  51. describe: 'whether or not to exclude all node_module folders (i.e. **/node_modules/**) by default'
  52. })
  53. .option('include', {
  54. alias: 'n',
  55. default: [],
  56. group: 'Reporting options',
  57. describe: 'a list of specific files that should be covered (glob patterns are supported)'
  58. })
  59. .option('exclude', {
  60. alias: 'x',
  61. default: defaultExclude,
  62. group: 'Reporting options',
  63. describe: 'a list of specific files and directories that should be excluded from coverage (glob patterns are supported)'
  64. })
  65. .option('extension', {
  66. alias: 'e',
  67. default: defaultExtension,
  68. group: 'Reporting options',
  69. describe: 'a list of specific file extensions that should be covered'
  70. })
  71. .option('exclude-after-remap', {
  72. alias: 'a',
  73. type: 'boolean',
  74. default: false,
  75. group: 'Reporting options',
  76. describe: 'apply exclude logic to files after they are remapped by a source-map'
  77. })
  78. .options('skip-full', {
  79. default: false,
  80. type: 'boolean',
  81. group: 'Reporting options',
  82. describe: 'do not show files with 100% statement, branch, and function coverage'
  83. })
  84. .option('check-coverage', {
  85. default: false,
  86. type: 'boolean',
  87. group: 'Coverage thresholds',
  88. description: 'check whether coverage is within thresholds provided'
  89. })
  90. .option('branches', {
  91. default: 0,
  92. group: 'Coverage thresholds',
  93. description: 'what % of branches must be covered?',
  94. type: 'number'
  95. })
  96. .option('functions', {
  97. default: 0,
  98. group: 'Coverage thresholds',
  99. description: 'what % of functions must be covered?',
  100. type: 'number'
  101. })
  102. .option('lines', {
  103. default: 90,
  104. group: 'Coverage thresholds',
  105. description: 'what % of lines must be covered?',
  106. type: 'number'
  107. })
  108. .option('statements', {
  109. default: 0,
  110. group: 'Coverage thresholds',
  111. description: 'what % of statements must be covered?',
  112. type: 'number'
  113. })
  114. .option('per-file', {
  115. default: false,
  116. group: 'Coverage thresholds',
  117. description: 'check thresholds per file',
  118. type: 'boolean'
  119. })
  120. .option('100', {
  121. default: false,
  122. group: 'Coverage thresholds',
  123. description: 'shortcut for --check-coverage --lines 100 --functions 100 --branches 100 --statements 100',
  124. type: 'boolean'
  125. })
  126. .option('temp-directory', {
  127. describe: 'directory V8 coverage data is written to and read from',
  128. default: process.env.NODE_V8_COVERAGE
  129. })
  130. .option('clean', {
  131. default: true,
  132. type: 'boolean',
  133. describe: 'should temp files be deleted before script execution'
  134. })
  135. .option('resolve', {
  136. default: '',
  137. describe: 'resolve paths to alternate base directory'
  138. })
  139. .option('wrapper-length', {
  140. describe: 'how many bytes is the wrapper prefix on executed JavaScript',
  141. type: 'number'
  142. })
  143. .option('omit-relative', {
  144. default: true,
  145. type: 'boolean',
  146. describe: 'omit any paths that are not absolute, e.g., internal/net.js'
  147. })
  148. .options('allowExternal', {
  149. default: false,
  150. type: 'boolean',
  151. describe: 'supplying --allowExternal will cause c8 to allow files from outside of your cwd. This applies both to ' +
  152. 'files discovered in coverage temp files and also src files discovered if using the --all flag.'
  153. })
  154. .options('merge-async', {
  155. default: false,
  156. type: 'boolean',
  157. describe: 'supplying --merge-async will merge all v8 coverage reports asynchronously and incrementally. ' +
  158. 'This is to avoid OOM issues with Node.js runtime.'
  159. })
  160. .pkgConf('c8')
  161. .demandCommand(1)
  162. .check((argv) => {
  163. if (!argv.tempDirectory) {
  164. argv.tempDirectory = resolve(argv.reportsDir, 'tmp')
  165. }
  166. return true
  167. })
  168. .epilog('visit https://git.io/vHysA for list of available reporters')
  169. // TODO: enable once yargs upgraded to v17: https://github.com/bcoe/c8/pull/332#discussion_r721636191
  170. // yargs.middleware((argv) => {
  171. // if (!argv['100']) return argv
  172. // return {
  173. // ...argv,
  174. // branches: 100,
  175. // functions: 100,
  176. // lines: 100,
  177. // statements: 100,
  178. // }
  179. // })
  180. const checkCoverage = require('./commands/check-coverage')
  181. const report = require('./commands/report')
  182. if (withCommands) {
  183. yargs.command(checkCoverage)
  184. yargs.command(report)
  185. } else {
  186. yargs.command(checkCoverage.command, checkCoverage.describe)
  187. yargs.command(report.command, report.describe)
  188. }
  189. return yargs
  190. }
  191. function hideInstrumenterArgs (yargv) {
  192. let argv = process.argv.slice(1)
  193. argv = argv.slice(argv.indexOf(yargv._[0]))
  194. if (argv[0][0] === '-') {
  195. argv.unshift(process.execPath)
  196. }
  197. return argv
  198. }
  199. function hideInstrumenteeArgs () {
  200. let argv = process.argv.slice(2)
  201. const yargv = parser(argv)
  202. if (!yargv._.length) return argv
  203. // drop all the arguments after the bin being
  204. // instrumented by c8.
  205. argv = argv.slice(0, argv.indexOf(yargv._[0]))
  206. argv.push(yargv._[0])
  207. return argv
  208. }
  209. module.exports = {
  210. buildYargs,
  211. hideInstrumenterArgs,
  212. hideInstrumenteeArgs
  213. }