diff --git a/.gitignore b/.gitignore index 9daa8247..62adae57 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store node_modules +.nyc_output diff --git a/README.md b/README.md index f4ee9194..32a5b35e 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,19 @@ The above example will collect coverage for `foo.js` using v8's profiler. TODO: -- [ ] write logic for converting v8 coverage output to [Istanbul Coverage.json format](https://github.com/gotwarlost/istanbul/blob/master/coverage.json.md). +- [x] write logic for converting v8 coverage output to [Istanbul Coverage.json format](https://github.com/gotwarlost/istanbul/blob/master/coverage.json.md). + * https://github.com/bcoe/v8-to-istanbul + - [ ] talk to Node.js project about silencing messages: > `Debugger listening on ws://127.0.0.1:56399/e850110a-c5df-41d8-8ef2-400f6829617f`. -- [ ] figure out why `detailed` mode does not appear to be working. -- [ ] figure out a better way to determine that all processes in event loop +- [x] figure out why `detailed` mode does not appear to be working. + * this is fixed in v8, as long as you start with `--inspect-brk` you + can collect coverage in detailed mode. +- [x] figure out a better way to determine that all processes in event loop have terminated (except the inspector session). -- [ ] process.exit() can't perform an async operation; how can we track coverage +- [x] process.exit() can't perform an async operation; how can we track coverage for scripts that exit? + * we can now listen for the `Runtime.executionContextDestroyed` event. +- [ ] diff --git a/bin/c8.js b/bin/c8.js index c62b7f25..91fd8b06 100755 --- a/bin/c8.js +++ b/bin/c8.js @@ -1,10 +1,58 @@ #!/usr/bin/env node const argv = require('yargs').parse() +const CRI = require('chrome-remote-interface') +const getPort = require('get-port'); const foreground = require('foreground-child') -const sw = require('spawn-wrap') +const waitTillPortOpen = require('wait-till-port-open') -if (argv._.length) { - sw([require.resolve('./wrap')]) - foreground(process.argv.slice(2)) +getPort().then(async port => { + foreground( + ['node', `--inspect-brk=${port}`].concat(process.argv.slice(2)), + (done) => { + console.info('actually got here') + } + ) + try { + await waitTillPortOpen(port) + const client = await CRI({port: port}) + + const {Debugger, Runtime, Profiler} = client + await Runtime.runIfWaitingForDebugger() + await Runtime.enable() + await Profiler.enable() + await Profiler.startPreciseCoverage({callCount: true, detailed: true}) + await Debugger.enable() + await Debugger.paused() + await Debugger.resume() + + client.on('event', async (message) => { + // console.info(message) + if (message.method === 'Runtime.executionContextDestroyed') { + await outputCoverage(Profiler) + client.close() + } + }) + + } catch (err) { + console.error(err) + process.exit(1) + } +}) + +async function outputCoverage (Profiler) { + const IGNORED_PATHS = [ + /\/bin\/wrap.js/, + /\/node_modules\//, + /node-spawn-wrap/ + ] + let {result} = await Profiler.takePreciseCoverage() + result = result.filter(coverage => { + for (var ignored, i = 0; (ignored = IGNORED_PATHS[i]) !== undefined; i++) { + if (ignored.test(coverage.url)) return false + } + if (!/^\//.test(coverage.url)) return false + else return true + }) + console.log(JSON.stringify(result, null, 2)) } diff --git a/bin/wrap.js b/bin/wrap.js deleted file mode 100755 index ce5b4ea5..00000000 --- a/bin/wrap.js +++ /dev/null @@ -1,52 +0,0 @@ -const fs = require('fs') -const sw = require('spawn-wrap') -const CRI = require('chrome-remote-interface'); -const getPort = require('get-port'); -const inspector = require('inspector') - -// if there are N or less active handles -// in the event loop, dump coverage and exit. -const EXIT_HANDLE_COUNT = 4 - -getPort().then(async port => { - // start an inspector session on an unused port. - inspector.open(port, true) - const client = await CRI({port: port}) - const {Profiler} = client - await Profiler.enable() - await Profiler.startPreciseCoverage({callCount: true, detailed: true}) - - // run the original "main" now that we've started the inspector. - sw.runMain() - - // wait for everything in event loop to terminate - // except for inspector session. - setInterval(() => { - const handleCount = process._getActiveHandles().length - + process._getActiveRequests().length - if (handleCount <= EXIT_HANDLE_COUNT) { - outputCoverageAndExit(client, Profiler) - } - }, 100) -}).catch(err => { - throw err -}) - -async function outputCoverageAndExit (client, Profiler) { - const IGNORED_PATHS = [ - /\/bin\/wrap.js/, - /\/node_modules\//, - /node-spawn-wrap/ - ] - let {result} = await Profiler.takePreciseCoverage() - result = result.filter(coverage => { - for (var ignored, i = 0; (ignored = IGNORED_PATHS[i]) !== undefined; i++) { - if (ignored.test(coverage.url)) return false - } - if (!/^\//.test(coverage.url)) return false - else return true - }) - console.log(JSON.stringify(result, null, 2)) - client.close() - process.exit(process.exitCode || 0) -} diff --git a/index.js b/index.js deleted file mode 100644 index e69de29b..00000000 diff --git a/package-lock.json b/package-lock.json index 80783278..00c9f188 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,27 +57,17 @@ "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" }, "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } + "bluebird": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" }, "builtin-modules": { "version": "1.1.1", @@ -183,11 +173,6 @@ "dot-prop": "3.0.0" } }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, "concat-stream": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", @@ -513,11 +498,6 @@ "null-check": "1.0.0" } }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, "get-caller-file": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", @@ -594,19 +574,6 @@ "ini": "1.3.4" } }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -649,19 +616,11 @@ "repeating": "2.0.1" } }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true }, "ini": { "version": "1.3.4", @@ -914,26 +873,11 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=" }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "1.1.8" - } - }, "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true }, "modify-values": { "version": "1.0.0", @@ -978,14 +922,6 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1.0.2" - } - }, "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", @@ -996,11 +932,6 @@ "wordwrap": "0.0.3" } }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, "os-locale": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", @@ -1049,11 +980,6 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -1091,6 +1017,14 @@ "pinkie": "2.0.4" } }, + "portscanner": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-1.2.0.tgz", + "integrity": "sha1-sUu9olfRTDEPqcwJaCrwLUCWGAI=", + "requires": { + "async": "1.5.2" + } + }, "process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", @@ -1210,14 +1144,6 @@ "align-text": "0.1.4" } }, - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "requires": { - "glob": "7.1.2" - } - }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", @@ -1261,19 +1187,6 @@ "amdefine": "1.0.1" } }, - "spawn-wrap": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.0.tgz", - "integrity": "sha512-2ASeXMB5TG+beYge/4QKZUrYoOtyFBnyUjcOXrDOQbCVgGRjfX0gvk9gs8sXuLtdkpx9Hv0a5TVeZQ/gVpanag==", - "requires": { - "foreground-child": "1.5.6", - "mkdirp": "0.5.1", - "os-homedir": "1.0.2", - "rimraf": "2.6.2", - "signal-exit": "3.0.2", - "which": "1.3.0" - } - }, "spdx-correct": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", @@ -1611,6 +1524,15 @@ "spdx-expression-parse": "1.0.4" } }, + "wait-till-port-open": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wait-till-port-open/-/wait-till-port-open-1.0.0.tgz", + "integrity": "sha1-cPYksl3MGEiHFEupvt2JyUDGfik=", + "requires": { + "bluebird": "2.11.0", + "portscanner": "1.2.0" + } + }, "which": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", @@ -1658,11 +1580,6 @@ } } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, "ws": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ws/-/ws-3.2.0.tgz", diff --git a/package.json b/package.json index 8d29122c..06d060e4 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "chrome-remote-interface": "^0.25.2", "foreground-child": "^1.5.6", "get-port": "^3.2.0", - "spawn-wrap": "=1.3.8", + "wait-till-port-open": "^1.0.0", "yargs": "^10.0.3" }, "devDependencies": { diff --git a/test/fixtures/c.mjs b/test/fixtures/c.mjs new file mode 100644 index 00000000..6a325c22 --- /dev/null +++ b/test/fixtures/c.mjs @@ -0,0 +1,11 @@ +const foo = true || (9 + 10) + +if (true) { + const a = 9 + 22 +} else if (foo) { + const b = 9 + 10 +} else { + console.info('hey') +} + +throw 'cool'