11'use strict' ;
2- const path = require ( 'path' ) ;
3- const { mkdirSync, writeFileSync } = require ( 'fs' ) ;
4- const hasInspector = process . config . variables . v8_enable_inspector === 1 ;
5- let inspector = null ;
6- if ( hasInspector ) inspector = require ( 'inspector' ) ;
7-
8- let session ;
2+ let coverageConnection = null ;
3+ let coverageDirectory ;
94
105function writeCoverage ( ) {
11- if ( ! session ) {
6+ if ( ! coverageConnection && coverageDirectory ) {
127 return ;
138 }
149
10+ const { join } = require ( 'path' ) ;
11+ const { mkdirSync, writeFileSync } = require ( 'fs' ) ;
1512 const { threadId } = require ( 'internal/worker' ) ;
1613
1714 const filename = `coverage-${ process . pid } -${ Date . now ( ) } -${ threadId } .json` ;
1815 try {
19- // TODO(bcoe): switch to mkdirp once #22302 is addressed.
20- mkdirSync ( process . env . NODE_V8_COVERAGE ) ;
16+ mkdirSync ( coverageDirectory , { recursive : true } ) ;
2117 } catch ( err ) {
2218 if ( err . code !== 'EEXIST' ) {
2319 console . error ( err ) ;
2420 return ;
2521 }
2622 }
2723
28- const target = path . join ( process . env . NODE_V8_COVERAGE , filename ) ;
29-
24+ const target = join ( coverageDirectory , filename ) ;
3025 try {
31- session . post ( 'Profiler.takePreciseCoverage' , ( err , coverageInfo ) => {
32- if ( err ) return console . error ( err ) ;
33- try {
34- writeFileSync ( target , JSON . stringify ( coverageInfo ) ) ;
35- } catch ( err ) {
36- console . error ( err ) ;
37- }
38- } ) ;
26+ disableAllAsyncHooks ( ) ;
27+ let msg ;
28+ coverageConnection . _coverageCallback = function ( _msg ) {
29+ msg = _msg ;
30+ } ;
31+ coverageConnection . dispatch ( JSON . stringify ( {
32+ id : 3 ,
33+ method : 'Profiler.takePreciseCoverage'
34+ } ) ) ;
35+ const coverageInfo = JSON . parse ( msg ) . result ;
36+ writeFileSync ( target , JSON . stringify ( coverageInfo ) ) ;
3937 } catch ( err ) {
4038 console . error ( err ) ;
4139 } finally {
42- session . disconnect ( ) ;
43- session = null ;
40+ coverageConnection . disconnect ( ) ;
41+ coverageConnection = null ;
4442 }
4543}
4644
45+ function disableAllAsyncHooks ( ) {
46+ const { getHookArrays } = require ( 'internal/async_hooks' ) ;
47+ const [ hooks_array ] = getHookArrays ( ) ;
48+ hooks_array . forEach ( ( hook ) => { hook . disable ( ) ; } ) ;
49+ }
50+
4751exports . writeCoverage = writeCoverage ;
4852
4953function setup ( ) {
50- if ( ! hasInspector ) {
51- console . warn ( 'coverage currently only supported in main thread' ) ;
54+ const { Connection } = process . binding ( 'inspector' ) ;
55+ if ( ! Connection ) {
56+ console . warn ( 'inspector not enabled' ) ;
5257 return ;
5358 }
5459
55- session = new inspector . Session ( ) ;
56- session . connect ( ) ;
57- session . post ( 'Profiler.enable' ) ;
58- session . post ( 'Profiler.startPreciseCoverage' , { callCount : true ,
59- detailed : true } ) ;
60+ coverageConnection = new Connection ( ( res ) => {
61+ if ( coverageConnection . _coverageCallback ) {
62+ coverageConnection . _coverageCallback ( res ) ;
63+ }
64+ } ) ;
65+ coverageConnection . dispatch ( JSON . stringify ( {
66+ id : 1 ,
67+ method : 'Profiler.enable'
68+ } ) ) ;
69+ coverageConnection . dispatch ( JSON . stringify ( {
70+ id : 2 ,
71+ method : 'Profiler.startPreciseCoverage' ,
72+ params : {
73+ callCount : true ,
74+ detailed : true
75+ }
76+ } ) ) ;
6077
61- const reallyReallyExit = process . reallyExit ;
78+ try {
79+ const { resolve } = require ( 'path' ) ;
80+ coverageDirectory = process . env . NODE_V8_COVERAGE =
81+ resolve ( process . env . NODE_V8_COVERAGE ) ;
82+ } catch ( err ) {
83+ console . error ( err ) ;
84+ }
85+ }
6286
87+ exports . setup = setup ;
88+
89+ function setupExitHooks ( ) {
90+ const reallyReallyExit = process . reallyExit ;
6391 process . reallyExit = function ( code ) {
6492 writeCoverage ( ) ;
6593 reallyReallyExit ( code ) ;
@@ -68,4 +96,4 @@ function setup() {
6896 process . on ( 'exit' , writeCoverage ) ;
6997}
7098
71- exports . setup = setup ;
99+ exports . setupExitHooks = setupExitHooks ;
0 commit comments