index.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. 'use strict';
  2. const defaultExclude = require('./default-exclude.js');
  3. const defaultExtension = require('./default-extension.js');
  4. const nycCommands = {
  5. all: [null, 'check-coverage', 'instrument', 'merge', 'report'],
  6. testExclude: [null, 'instrument', 'report', 'check-coverage'],
  7. instrument: [null, 'instrument'],
  8. checkCoverage: [null, 'report', 'check-coverage'],
  9. report: [null, 'report'],
  10. main: [null],
  11. instrumentOnly: ['instrument']
  12. };
  13. const cwd = {
  14. description: 'working directory used when resolving paths',
  15. type: 'string',
  16. get default() {
  17. return process.cwd();
  18. },
  19. nycCommands: nycCommands.all
  20. };
  21. const nycrcPath = {
  22. description: 'specify an explicit path to find nyc configuration',
  23. nycCommands: nycCommands.all
  24. };
  25. const tempDir = {
  26. description: 'directory to output raw coverage information to',
  27. type: 'string',
  28. default: './.nyc_output',
  29. nycAlias: 't',
  30. nycHiddenAlias: 'temp-directory',
  31. nycCommands: [null, 'check-coverage', 'merge', 'report']
  32. };
  33. const testExclude = {
  34. exclude: {
  35. description: 'a list of specific files and directories that should be excluded from coverage, glob patterns are supported',
  36. type: 'array',
  37. items: {
  38. type: 'string'
  39. },
  40. default: defaultExclude,
  41. nycCommands: nycCommands.testExclude,
  42. nycAlias: 'x'
  43. },
  44. excludeNodeModules: {
  45. description: 'whether or not to exclude all node_module folders (i.e. **/node_modules/**) by default',
  46. type: 'boolean',
  47. default: true,
  48. nycCommands: nycCommands.testExclude
  49. },
  50. include: {
  51. description: 'a list of specific files that should be covered, glob patterns are supported',
  52. type: 'array',
  53. items: {
  54. type: 'string'
  55. },
  56. default: [],
  57. nycCommands: nycCommands.testExclude,
  58. nycAlias: 'n'
  59. },
  60. extension: {
  61. description: 'a list of extensions that nyc should handle in addition to .js',
  62. type: 'array',
  63. items: {
  64. type: 'string'
  65. },
  66. default: defaultExtension,
  67. nycCommands: nycCommands.testExclude,
  68. nycAlias: 'e'
  69. }
  70. };
  71. const instrumentVisitor = {
  72. coverageVariable: {
  73. description: 'variable to store coverage',
  74. type: 'string',
  75. default: '__coverage__',
  76. nycCommands: nycCommands.instrument
  77. },
  78. coverageGlobalScope: {
  79. description: 'scope to store the coverage variable',
  80. type: 'string',
  81. default: 'this',
  82. nycCommands: nycCommands.instrument
  83. },
  84. coverageGlobalScopeFunc: {
  85. description: 'avoid potentially replaced `Function` when finding global scope',
  86. type: 'boolean',
  87. default: true,
  88. nycCommands: nycCommands.instrument
  89. },
  90. ignoreClassMethods: {
  91. description: 'class method names to ignore for coverage',
  92. type: 'array',
  93. items: {
  94. type: 'string'
  95. },
  96. default: [],
  97. nycCommands: nycCommands.instrument
  98. }
  99. };
  100. const instrumentParseGen = {
  101. autoWrap: {
  102. description: 'allow `return` statements outside of functions',
  103. type: 'boolean',
  104. default: true,
  105. nycCommands: nycCommands.instrument
  106. },
  107. esModules: {
  108. description: 'should files be treated as ES Modules',
  109. type: 'boolean',
  110. default: true,
  111. nycCommands: nycCommands.instrument
  112. },
  113. parserPlugins: {
  114. description: 'babel parser plugins to use when parsing the source',
  115. type: 'array',
  116. items: {
  117. type: 'string'
  118. },
  119. /* Babel parser plugins are to be enabled when the feature is stage 3 and
  120. * implemented in a released version of node.js. */
  121. default: [
  122. 'asyncGenerators',
  123. 'bigInt',
  124. 'classProperties',
  125. 'classPrivateProperties',
  126. 'classPrivateMethods',
  127. 'dynamicImport',
  128. 'importMeta',
  129. 'numericSeparator',
  130. 'objectRestSpread',
  131. 'optionalCatchBinding',
  132. 'topLevelAwait'
  133. ],
  134. nycCommands: nycCommands.instrument
  135. },
  136. compact: {
  137. description: 'should the output be compacted?',
  138. type: 'boolean',
  139. default: true,
  140. nycCommands: nycCommands.instrument
  141. },
  142. preserveComments: {
  143. description: 'should comments be preserved in the output?',
  144. type: 'boolean',
  145. default: true,
  146. nycCommands: nycCommands.instrument
  147. },
  148. produceSourceMap: {
  149. description: 'should source maps be produced?',
  150. type: 'boolean',
  151. default: true,
  152. nycCommands: nycCommands.instrument
  153. }
  154. };
  155. const checkCoverage = {
  156. excludeAfterRemap: {
  157. description: 'should exclude logic be performed after the source-map remaps filenames?',
  158. type: 'boolean',
  159. default: true,
  160. nycCommands: nycCommands.checkCoverage
  161. },
  162. branches: {
  163. description: 'what % of branches must be covered?',
  164. type: 'number',
  165. default: 0,
  166. minimum: 0,
  167. maximum: 100,
  168. nycCommands: nycCommands.checkCoverage
  169. },
  170. functions: {
  171. description: 'what % of functions must be covered?',
  172. type: 'number',
  173. default: 0,
  174. minimum: 0,
  175. maximum: 100,
  176. nycCommands: nycCommands.checkCoverage
  177. },
  178. lines: {
  179. description: 'what % of lines must be covered?',
  180. type: 'number',
  181. default: 90,
  182. minimum: 0,
  183. maximum: 100,
  184. nycCommands: nycCommands.checkCoverage
  185. },
  186. statements: {
  187. description: 'what % of statements must be covered?',
  188. type: 'number',
  189. default: 0,
  190. minimum: 0,
  191. maximum: 100,
  192. nycCommands: nycCommands.checkCoverage
  193. },
  194. perFile: {
  195. description: 'check thresholds per file',
  196. type: 'boolean',
  197. default: false,
  198. nycCommands: nycCommands.checkCoverage
  199. }
  200. };
  201. const report = {
  202. checkCoverage: {
  203. description: 'check whether coverage is within thresholds provided',
  204. type: 'boolean',
  205. default: false,
  206. nycCommands: nycCommands.report
  207. },
  208. reporter: {
  209. description: 'coverage reporter(s) to use',
  210. type: 'array',
  211. items: {
  212. type: 'string'
  213. },
  214. default: ['text'],
  215. nycCommands: nycCommands.report,
  216. nycAlias: 'r'
  217. },
  218. reportDir: {
  219. description: 'directory to output coverage reports in',
  220. type: 'string',
  221. default: 'coverage',
  222. nycCommands: nycCommands.report
  223. },
  224. showProcessTree: {
  225. description: 'display the tree of spawned processes',
  226. type: 'boolean',
  227. default: false,
  228. nycCommands: nycCommands.report
  229. },
  230. skipEmpty: {
  231. description: 'don\'t show empty files (no lines of code) in report',
  232. type: 'boolean',
  233. default: false,
  234. nycCommands: nycCommands.report
  235. },
  236. skipFull: {
  237. description: 'don\'t show files with 100% statement, branch, and function coverage',
  238. type: 'boolean',
  239. default: false,
  240. nycCommands: nycCommands.report
  241. }
  242. };
  243. const nycMain = {
  244. silent: {
  245. description: 'don\'t output a report after tests finish running',
  246. type: 'boolean',
  247. default: false,
  248. nycCommands: nycCommands.main,
  249. nycAlias: 's'
  250. },
  251. all: {
  252. description: 'whether or not to instrument all files of the project (not just the ones touched by your test suite)',
  253. type: 'boolean',
  254. default: false,
  255. nycCommands: nycCommands.main,
  256. nycAlias: 'a'
  257. },
  258. eager: {
  259. description: 'instantiate the instrumenter at startup (see https://git.io/vMKZ9)',
  260. type: 'boolean',
  261. default: false,
  262. nycCommands: nycCommands.main
  263. },
  264. cache: {
  265. description: 'cache instrumentation results for improved performance',
  266. type: 'boolean',
  267. default: true,
  268. nycCommands: nycCommands.main,
  269. nycAlias: 'c'
  270. },
  271. cacheDir: {
  272. description: 'explicitly set location for instrumentation cache',
  273. type: 'string',
  274. nycCommands: nycCommands.main
  275. },
  276. babelCache: {
  277. description: 'cache babel transpilation results for improved performance',
  278. type: 'boolean',
  279. default: false,
  280. nycCommands: nycCommands.main
  281. },
  282. useSpawnWrap: {
  283. description: 'use spawn-wrap instead of setting process.env.NODE_OPTIONS',
  284. type: 'boolean',
  285. default: false,
  286. nycCommands: nycCommands.main
  287. },
  288. hookRequire: {
  289. description: 'should nyc wrap require?',
  290. type: 'boolean',
  291. default: true,
  292. nycCommands: nycCommands.main
  293. },
  294. hookRunInContext: {
  295. description: 'should nyc wrap vm.runInContext?',
  296. type: 'boolean',
  297. default: false,
  298. nycCommands: nycCommands.main
  299. },
  300. hookRunInThisContext: {
  301. description: 'should nyc wrap vm.runInThisContext?',
  302. type: 'boolean',
  303. default: false,
  304. nycCommands: nycCommands.main
  305. },
  306. clean: {
  307. description: 'should the .nyc_output folder be cleaned before executing tests',
  308. type: 'boolean',
  309. default: true,
  310. nycCommands: nycCommands.main
  311. }
  312. };
  313. const instrumentOnly = {
  314. inPlace: {
  315. description: 'should nyc run the instrumentation in place?',
  316. type: 'boolean',
  317. default: false,
  318. nycCommands: nycCommands.instrumentOnly
  319. },
  320. exitOnError: {
  321. description: 'should nyc exit when an instrumentation failure occurs?',
  322. type: 'boolean',
  323. default: false,
  324. nycCommands: nycCommands.instrumentOnly
  325. },
  326. delete: {
  327. description: 'should the output folder be deleted before instrumenting files?',
  328. type: 'boolean',
  329. default: false,
  330. nycCommands: nycCommands.instrumentOnly
  331. },
  332. completeCopy: {
  333. description: 'should nyc copy all files from input to output as well as instrumented files?',
  334. type: 'boolean',
  335. default: false,
  336. nycCommands: nycCommands.instrumentOnly
  337. }
  338. };
  339. const nyc = {
  340. description: 'nyc configuration options',
  341. type: 'object',
  342. properties: {
  343. cwd,
  344. nycrcPath,
  345. tempDir,
  346. /* Test Exclude */
  347. ...testExclude,
  348. /* Instrumentation settings */
  349. ...instrumentVisitor,
  350. /* Instrumentation parser/generator settings */
  351. ...instrumentParseGen,
  352. sourceMap: {
  353. description: 'should nyc detect and handle source maps?',
  354. type: 'boolean',
  355. default: true,
  356. nycCommands: nycCommands.instrument
  357. },
  358. require: {
  359. description: 'a list of additional modules that nyc should attempt to require in its subprocess, e.g., @babel/register, @babel/polyfill',
  360. type: 'array',
  361. items: {
  362. type: 'string'
  363. },
  364. default: [],
  365. nycCommands: nycCommands.instrument,
  366. nycAlias: 'i'
  367. },
  368. instrument: {
  369. description: 'should nyc handle instrumentation?',
  370. type: 'boolean',
  371. default: true,
  372. nycCommands: nycCommands.instrument
  373. },
  374. /* Check coverage */
  375. ...checkCoverage,
  376. /* Report options */
  377. ...report,
  378. /* Main command options */
  379. ...nycMain,
  380. /* Instrument command options */
  381. ...instrumentOnly
  382. }
  383. };
  384. const configs = {
  385. nyc,
  386. testExclude: {
  387. description: 'test-exclude options',
  388. type: 'object',
  389. properties: {
  390. cwd,
  391. ...testExclude
  392. }
  393. },
  394. babelPluginIstanbul: {
  395. description: 'babel-plugin-istanbul options',
  396. type: 'object',
  397. properties: {
  398. cwd,
  399. ...testExclude,
  400. ...instrumentVisitor
  401. }
  402. },
  403. instrumentVisitor: {
  404. description: 'instrument visitor options',
  405. type: 'object',
  406. properties: instrumentVisitor
  407. },
  408. instrumenter: {
  409. description: 'stand-alone instrumenter options',
  410. type: 'object',
  411. properties: {
  412. ...instrumentVisitor,
  413. ...instrumentParseGen
  414. }
  415. }
  416. };
  417. function defaultsReducer(defaults, [name, {default: value}]) {
  418. /* Modifying arrays in defaults is safe, does not change schema. */
  419. if (Array.isArray(value)) {
  420. value = [...value];
  421. }
  422. return Object.assign(defaults, {[name]: value});
  423. }
  424. module.exports = {
  425. ...configs,
  426. defaults: Object.keys(configs).reduce(
  427. (defaults, id) => {
  428. Object.defineProperty(defaults, id, {
  429. enumerable: true,
  430. get() {
  431. /* This defers `process.cwd()` until defaults are requested. */
  432. return Object.entries(configs[id].properties)
  433. .filter(([, info]) => 'default' in info)
  434. .reduce(defaultsReducer, {});
  435. }
  436. });
  437. return defaults;
  438. },
  439. {}
  440. )
  441. };