Skip to content

Commit 53bba15

Browse files
author
Benjamin E. Coe
authored
feat!: use Node.js' source-map cache, to support tools like ts-node (#152)
BREAKING CHANGE: Node.js' source-map and lineLength cache is now used to remap coverage output (this allows tools like ts-node to be supported, which transpile at runtime).
1 parent a107093 commit 53bba15

File tree

9 files changed

+164
-9
lines changed

9 files changed

+164
-9
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ os:
44
- osx
55
- windows
66
node_js:
7-
- "12"
7+
- "13"
88
after_success: npm run coverage

lib/report.js

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class Report {
3232
include: include
3333
})
3434
this.omitRelative = omitRelative
35+
this.sourceMapCache = {}
3536
this.wrapperLength = wrapperLength
3637
}
3738

@@ -63,8 +64,9 @@ class Report {
6364

6465
for (const v8ScriptCov of v8ProcessCov.result) {
6566
try {
67+
const sources = this._getSourceMap(v8ScriptCov)
6668
const path = resolve(this.resolve, v8ScriptCov.url)
67-
const converter = v8toIstanbul(path, this.wrapperLength)
69+
const converter = v8toIstanbul(path, this.wrapperLength, sources)
6870
await converter.load()
6971

7072
if (resultCountPerPath.has(path)) {
@@ -98,6 +100,34 @@ class Report {
98100
return this._allCoverageFiles
99101
}
100102

103+
/**
104+
* Returns source-map and fake source file, if cached during Node.js'
105+
* execution. This is used to support tools like ts-node, which transpile
106+
* using runtime hooks.
107+
*
108+
* Note: requires Node.js 13+
109+
*
110+
* @return {Object} sourceMap and fake source file (created from line #s).
111+
* @private
112+
*/
113+
_getSourceMap (v8ScriptCov) {
114+
const sources = {}
115+
if (this.sourceMapCache[`file://${v8ScriptCov.url}`]) {
116+
const sourceMapAndLineLengths = this.sourceMapCache[`file://${v8ScriptCov.url}`]
117+
sources.sourceMap = {
118+
sourcemap: sourceMapAndLineLengths.data
119+
}
120+
if (sourceMapAndLineLengths.lineLengths) {
121+
let source = ''
122+
sourceMapAndLineLengths.lineLengths.forEach(length => {
123+
source += `${''.padEnd(length, '.')}\n`
124+
})
125+
sources.source = source
126+
}
127+
}
128+
return sources
129+
}
130+
101131
/**
102132
* Returns the merged V8 process coverage.
103133
*
@@ -111,6 +141,9 @@ class Report {
111141
const v8ProcessCovs = []
112142
for (const v8ProcessCov of this._loadReports()) {
113143
if (this._isCoverageObject(v8ProcessCov)) {
144+
if (v8ProcessCov['source-map-cache']) {
145+
Object.assign(this.sourceMapCache, v8ProcessCov['source-map-cache'])
146+
}
114147
v8ProcessCovs.push(this._normalizeProcessCov(v8ProcessCov))
115148
}
116149
}

package-lock.json

Lines changed: 58 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"istanbul-reports": "^2.2.6",
4242
"rimraf": "^3.0.0",
4343
"test-exclude": "^5.2.3",
44-
"v8-to-istanbul": "^3.2.3",
44+
"v8-to-istanbul": "^3.2.6",
4545
"yargs": "^14.0.0",
4646
"yargs-parser": "^14.0.0"
4747
},
@@ -51,7 +51,9 @@
5151
"coveralls": "^3.0.6",
5252
"mocha": "^6.2.0",
5353
"standard": "^14.1.0",
54-
"standard-version": "^7.0.0"
54+
"standard-version": "^7.0.0",
55+
"ts-node": "^8.4.1",
56+
"typescript": "^3.6.4"
5557
},
5658
"engines": {
5759
"node": ">=10.12.0"

test/fixtures/source-maps/branches/branches.uglify.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/fixtures/source-maps/classes/classes.uglify.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/fixtures/ts-node-basic.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
export interface FooOptions {
2+
x: number;
3+
}
4+
5+
class Foo {
6+
x: number;
7+
constructor (options: FooOptions) {
8+
this.x = options.x ? options.x : 99
9+
if (this.x) {
10+
console.info('covered')
11+
} else {
12+
console.info('uncovered')
13+
}
14+
this.methodC()
15+
}
16+
methodA (): number {
17+
console.info('covered')
18+
return 33
19+
}
20+
/* c8 ignore next 3 */
21+
methodB () {
22+
console.info('uncovered')
23+
}
24+
private methodC () {
25+
console.info('covered')
26+
}
27+
methodD () {
28+
console.info('uncovered')
29+
}
30+
}
31+
32+
const a = new Foo({x: 0})
33+
const b = new Foo({x: 33})
34+
a.methodA()

test/integration.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,4 +311,20 @@ describe('c8', () => {
311311
})
312312
})
313313
})
314+
315+
describe('ts-node', () => {
316+
beforeEach(cb => rimraf('tmp/source-map', cb))
317+
318+
it('reads source-map from cache, and applies to coverage', () => {
319+
const { output } = spawnSync(nodePath, [
320+
c8Path,
321+
'--exclude="test/*.js"',
322+
'--temp-directory=tmp/source-map',
323+
'--clean=true',
324+
'./node_modules/.bin/ts-node',
325+
require.resolve('./fixtures/ts-node-basic.ts')
326+
])
327+
output.toString('utf8').should.matchSnapshot()
328+
})
329+
})
314330
})

test/integration.js.snap

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,3 +219,18 @@ All files | 83.33 | 85.71 | 60 | 83.33 | |
219219
-----------|----------|----------|----------|----------|-------------------|
220220
,"
221221
`;
222+
223+
exports[`c8 ts-node reads source-map from cache, and applies to coverage 1`] = `
224+
",covered
225+
covered
226+
covered
227+
covered
228+
covered
229+
------------------|----------|----------|----------|----------|-------------------|
230+
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
231+
------------------|----------|----------|----------|----------|-------------------|
232+
All files | 88.24 | 87.5 | 80 | 88.24 | |
233+
ts-node-basic.ts | 88.24 | 87.5 | 80 | 88.24 | 12,13,28,29 |
234+
------------------|----------|----------|----------|----------|-------------------|
235+
,"
236+
`;

0 commit comments

Comments
 (0)