Comparing version
104
bin/c8.js
#!/usr/bin/env node | ||
'use strict' | ||
const argv = require('yargs').parse() | ||
const foreground = require('foreground-child') | ||
const sw = require('spawn-wrap') | ||
const CRI = require('chrome-remote-interface') | ||
const Exclude = require('test-exclude') | ||
const {isAbsolute} = require('path') | ||
const mkdirp = require('mkdirp') | ||
const report = require('../lib/report') | ||
const {resolve} = require('path') | ||
const rimraf = require('rimraf') | ||
const spawn = require('../lib/spawn') | ||
const uuid = require('uuid') | ||
const v8ToIstanbul = require('v8-to-istanbul') | ||
const {writeFileSync} = require('fs') | ||
const { | ||
hideInstrumenteeArgs, | ||
hideInstrumenterArgs, | ||
yargs | ||
} = require('../lib/parse-args') | ||
if (argv._.length) { | ||
sw([require.resolve('./wrap')]) | ||
foreground(process.argv.slice(2)) | ||
const instrumenterArgs = hideInstrumenteeArgs() | ||
const argv = yargs.parse(instrumenterArgs) | ||
const exclude = Exclude({ | ||
include: argv.include, | ||
exclude: argv.exclude | ||
}) | ||
;(async function executeWithCoverage (instrumenteeArgv) { | ||
try { | ||
const bin = instrumenteeArgv.shift() | ||
const info = await spawn(bin, | ||
[`--inspect-brk=0`].concat(instrumenteeArgv)) | ||
const client = await CRI({port: info.port}) | ||
const initialPause = new Promise((resolve) => { | ||
client.once('Debugger.paused', resolve) | ||
}) | ||
const mainContextInfo = new Promise((resolve) => { | ||
client.once('Runtime.executionContextCreated', (message) => { | ||
resolve(message.context) | ||
}) | ||
}) | ||
const executionComplete = new Promise((resolve) => { | ||
client.on('Runtime.executionContextDestroyed', async (message) => { | ||
if (message.executionContextId === (await mainContextInfo).id) { | ||
resolve(message) | ||
} | ||
}) | ||
}) | ||
const {Debugger, Runtime, Profiler} = client | ||
await Promise.all([ | ||
Profiler.enable(), | ||
Runtime.enable(), | ||
Debugger.enable(), | ||
Profiler.startPreciseCoverage({callCount: true, detailed: true}), | ||
Runtime.runIfWaitingForDebugger(), | ||
initialPause | ||
]) | ||
await Debugger.resume() | ||
await executionComplete | ||
const allV8Coverage = await collectV8Coverage(Profiler) | ||
writeIstanbulFormatCoverage(allV8Coverage) | ||
await client.close() | ||
report({ | ||
reporter: Array.isArray(argv.reporter) ? argv.reporter : [argv.reporter], | ||
coverageDirectory: argv.coverageDirectory, | ||
watermarks: argv.watermarks | ||
}) | ||
} catch (err) { | ||
console.error(err) | ||
process.exit(1) | ||
} | ||
})(hideInstrumenterArgs(argv)) | ||
async function collectV8Coverage (Profiler) { | ||
let {result} = await Profiler.takePreciseCoverage() | ||
result = result.filter(({url}) => { | ||
url = url.replace('file://', '') | ||
return isAbsolute(url) && exclude.shouldInstrument(url) | ||
}) | ||
return result | ||
} | ||
function writeIstanbulFormatCoverage (allV8Coverage) { | ||
const tmpDirctory = resolve(argv.coverageDirectory, './tmp') | ||
rimraf.sync(tmpDirctory) | ||
mkdirp.sync(tmpDirctory) | ||
allV8Coverage.forEach((v8) => { | ||
const script = v8ToIstanbul(v8.url) | ||
script.applyCoverage(v8.functions) | ||
writeFileSync( | ||
resolve(tmpDirctory, `./${uuid.v4()}.json`), | ||
JSON.stringify(script.toIstanbul(), null, 2), | ||
'utf8' | ||
) | ||
}) | ||
} |
@@ -5,2 +5,24 @@ # Change Log | ||
<a name="2.0.0"></a> | ||
# [2.0.0](https://github.com/bcoe/c8/compare/v1.0.1...v2.0.0) (2017-12-17) | ||
### Bug Fixes | ||
* tweak inspector event timing ([#6](https://github.com/bcoe/c8/issues/6)) ([01f654e](https://github.com/bcoe/c8/commit/01f654e)) | ||
### Features | ||
* first pass at functional prototype without subprocess support ([#5](https://github.com/bcoe/c8/issues/5)) ([9534f56](https://github.com/bcoe/c8/commit/9534f56)) | ||
* implement Istanbul reporting ([#8](https://github.com/bcoe/c8/issues/8)) ([8e430bf](https://github.com/bcoe/c8/commit/8e430bf)) | ||
* switch to stderr and default port ([#7](https://github.com/bcoe/c8/issues/7)) ([bb117b7](https://github.com/bcoe/c8/commit/bb117b7)) | ||
### BREAKING CHANGES | ||
* dropped subprocess support for the time being, while we march towards an initial implementation. | ||
<a name="1.0.1"></a> | ||
@@ -7,0 +29,0 @@ ## [1.0.1](https://github.com/bcoe/c8/compare/v1.0.0...v1.0.1) (2017-10-26) |
{ | ||
"name": "c8", | ||
"version": "1.0.1", | ||
"description": "collect test coverage using v8's profiler", | ||
"version": "2.0.0", | ||
"description": "collect test coverage using v8's inspector", | ||
"main": "index.js", | ||
"bin": "./bin/c8.js", | ||
"scripts": { | ||
"test": "nyc mocha test.js", | ||
"test": "./bin/c8.js node ./node_modules/.bin/_mocha ./test/*.js", | ||
"posttest": "standard", | ||
"release": "standard-version" | ||
}, | ||
"c8": { | ||
"exclude": [ | ||
"test/*.js" | ||
] | ||
}, | ||
"standard": { | ||
"ignore": [ | ||
"test/fixtures" | ||
] | ||
}, | ||
"keywords": [ | ||
@@ -26,10 +37,20 @@ "coverage", | ||
"chrome-remote-interface": "^0.25.2", | ||
"foreground-child": "^1.5.6", | ||
"get-port": "^3.2.0", | ||
"spawn-wrap": "=1.3.8", | ||
"yargs": "^10.0.3" | ||
"find-up": "^2.1.0", | ||
"istanbul-lib-coverage": "^1.1.1", | ||
"istanbul-lib-report": "^1.1.2", | ||
"istanbul-reports": "^1.1.3", | ||
"mkdirp": "^0.5.1", | ||
"rimraf": "^2.6.2", | ||
"test-exclude": "^4.1.1", | ||
"uuid": "^3.1.0", | ||
"v8-to-istanbul": "^1.2.0", | ||
"yargs": "^10.0.3", | ||
"yargs-parser": "^8.0.0" | ||
}, | ||
"devDependencies": { | ||
"chai": "^4.1.2", | ||
"mocha": "^4.0.1", | ||
"standard": "^10.0.3", | ||
"standard-version": "^4.2.0" | ||
} | ||
} |
# c8 - native v8 code-coverage | ||
Code-coverage using [v8's Profiler](https://nodejs.org/dist/latest-v8.x/docs/api/inspector.html) | ||
Code-coverage using [v8's Inspector](https://nodejs.org/dist/latest-v8.x/docs/api/inspector.html) | ||
that's compatible with [Istanbul's reporters](https://istanbul.js.org/docs/advanced/alternative-reporters/). | ||
Like [nyc](https://github.com/istanbuljs/nyc), c8 just magically works, simply: | ||
Like [nyc](https://github.com/istanbuljs/nyc), c8 just magically works: | ||
@@ -13,15 +13,22 @@ ```bash | ||
The above example will collect coverage for `foo.js` using v8's profiler. | ||
The above example will collect coverage for `foo.js` using v8's inspector. | ||
TODO: | ||
## remaining work | ||
- [ ] write logic for converting v8 coverage output to [Istanbul Coverage.json format](https://github.com/gotwarlost/istanbul/blob/master/coverage.json.md). | ||
- [ ] talk to Node.js project about silencing messages: | ||
- [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. | ||
- [x] figure out why instrumentation of .mjs files does not work: | ||
* see: https://github.com/nodejs/node/issues/17336 |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
11489
137.72%8
14.29%221
301.82%34
25.93%12
140%4
300%7
133.33%2
Infinity%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed