Skip to content

Commit 7923697

Browse files
committed
adding detecting folder that matches current folder root
1 parent d18d49b commit 7923697

File tree

2 files changed

+148
-21
lines changed

2 files changed

+148
-21
lines changed

task.js

Lines changed: 119 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ const istanbul = require('istanbul-lib-coverage')
33
const { join, resolve, isAbsolute } = require('path')
44
const { existsSync, mkdirSync, readFileSync, writeFileSync } = require('fs')
55
const execa = require('execa')
6-
const fs = require('fs')
7-
const { fixSourcePathes } = require('./utils')
6+
const path = require('path')
7+
const { fixSourcePathes, showNycInfo } = require('./utils')
88
const NYC = require('nyc')
99

1010
const debug = require('debug')('code-coverage')
@@ -20,8 +20,8 @@ const nycFilename = join(coverageFolder, 'out.json')
2020
// potentially there might be "nyc" options in other configuration files
2121
// it allows, but for now ignore those options
2222
const pkgFilename = join(processWorkingDirectory, 'package.json')
23-
const pkg = fs.existsSync(pkgFilename)
24-
? JSON.parse(fs.readFileSync(pkgFilename, 'utf8'))
23+
const pkg = existsSync(pkgFilename)
24+
? JSON.parse(readFileSync(pkgFilename, 'utf8'))
2525
: {}
2626
const nycOptions = pkg.nyc || {}
2727
const scripts = pkg.scripts || {}
@@ -38,38 +38,121 @@ function saveCoverage(coverage) {
3838
}
3939

4040
/**
41-
* A small debug utility to inspect paths saved in NYC output JSON file
41+
* @param {string[]} filepaths
42+
* @returns {string | undefined} common prefix that corresponds to current folder
4243
*/
43-
function showNycInfo(nycFilename) {
44+
function findCommonRoot(filepaths) {
45+
if (!filepaths.length) {
46+
debug('cannot find common root without any files')
47+
return
48+
}
49+
50+
// assuming / as file separator
51+
const splitParts = filepaths.map(name => name.split('/'))
52+
const lengths = splitParts.map(arr => arr.length)
53+
const shortestLength = Math.min.apply(null, lengths)
54+
debug('shorted file path has %d parts', shortestLength)
55+
56+
const cwd = process.cwd()
57+
let commonPrefix = []
58+
let foundCurrentFolder
59+
60+
for (let k = 0; k < shortestLength; k += 1) {
61+
const part = splitParts[0][k]
62+
const prefix = commonPrefix.concat(part).join('/')
63+
debug('testing prefix %o', prefix)
64+
const allFilesStart = filepaths.every(name => name.startsWith(prefix))
65+
if (!allFilesStart) {
66+
debug('stopped at non-common prefix %s', prefix)
67+
break
68+
}
69+
70+
commonPrefix.push(part)
71+
72+
const removedPrefixNames = filepaths.map(filepath =>
73+
filepath.slice(prefix.length)
74+
)
75+
debug('removedPrefix %o', removedPrefixNames)
76+
const foundAllPaths = removedPrefixNames.every(filepath =>
77+
existsSync(path.join(cwd, filepath))
78+
)
79+
debug('all files found at %s? %o', prefix, foundAllPaths)
80+
if (foundAllPaths) {
81+
debug('found prefix that matches current folder: %s', prefix)
82+
foundCurrentFolder = prefix
83+
break
84+
}
85+
}
86+
87+
return foundCurrentFolder
88+
}
89+
90+
function tryFindingLocalFiles(nycFilename) {
91+
const nycCoverage = JSON.parse(readFileSync(nycFilename, 'utf8'))
92+
const coverageKeys = Object.keys(nycCoverage)
93+
const filenames = coverageKeys.map(key => nycCoverage[key].path)
94+
const commonFolder = findCommonRoot(filenames)
95+
if (!commonFolder) {
96+
debug('could not find common folder %s', commonFolder)
97+
return
98+
}
99+
const cwd = process.cwd()
100+
debug(
101+
'found common folder %s that matches current working directory %s',
102+
commonFolder,
103+
cwd
104+
)
105+
const length = commonFolder.length
106+
let changed
107+
108+
coverageKeys.forEach(key => {
109+
const from = nycCoverage[key].path
110+
if (from.startsWith(commonFolder)) {
111+
const to = path.join(cwd, from.slice(length))
112+
nycCoverage[key].path = to
113+
debug('replaced %s -> %s', from, to)
114+
changed = true
115+
}
116+
})
117+
118+
if (changed) {
119+
debug('saving updated file %s', nycFilename)
120+
writeFileSync(
121+
nycFilename,
122+
JSON.stringify(nycCoverage, null, 2) + '\n',
123+
'utf8'
124+
)
125+
}
126+
}
127+
128+
function checkAllPathsNotFound(nycFilename) {
44129
const nycCoverage = JSON.parse(readFileSync(nycFilename, 'utf8'))
45130

46131
const coverageKeys = Object.keys(nycCoverage)
47132
if (!coverageKeys.length) {
48133
console.error('⚠️ file %s has no coverage information', nycFilename)
49134
return
50135
}
51-
debug('NYC file %s has %d key(s)', nycFilename, coverageKeys.length)
52136

53-
const maxPrintKeys = 3
54-
const showKeys = coverageKeys.slice(0, maxPrintKeys)
55-
56-
showKeys.forEach((key, k) => {
137+
const allFilesAreMissing = coverageKeys.every((key, k) => {
57138
const coverage = nycCoverage[key]
58-
59-
// printing a few found keys and file paths from the coverage file
60-
// will make debugging any problems much much easier
61-
if (k < maxPrintKeys) {
62-
debug('%d key %s file path %s', k + 1, key, coverage.path)
63-
}
139+
return !existsSync(coverage.path)
64140
})
141+
142+
debug(
143+
'in file %s all files are not found? %o',
144+
nycFilename,
145+
allFilesAreMissing
146+
)
147+
return allFilesAreMissing
65148
}
66149

67150
/**
68151
* Looks at all coverage objects in the given JSON coverage file
69152
* and if the file is relative, and exists, changes its path to
70153
* be absolute.
71154
*/
72-
function resolvePaths(nycFilename) {
155+
function resolveRelativePaths(nycFilename) {
73156
const nycCoverage = JSON.parse(readFileSync(nycFilename, 'utf8'))
74157

75158
const coverageKeys = Object.keys(nycCoverage)
@@ -84,12 +167,23 @@ function resolvePaths(nycFilename) {
84167
coverageKeys.forEach((key, k) => {
85168
const coverage = nycCoverage[key]
86169

87-
if (coverage.path && !isAbsolute(coverage.path)) {
170+
if (!coverage.path) {
171+
debug('key %s does not have path', key)
172+
return
173+
}
174+
175+
if (!isAbsolute(coverage.path)) {
88176
if (existsSync(coverage.path)) {
89177
debug('resolving path %s', coverage.path)
90178
coverage.path = resolve(coverage.path)
91179
changed = true
92180
}
181+
return
182+
}
183+
184+
// path is absolute, let's check if it exists
185+
if (!existsSync(coverage.path)) {
186+
debug('⚠️ cannot find file %s with hash %s', coverage.path, coverage.hash)
93187
}
94188
})
95189

@@ -164,7 +258,12 @@ const tasks = {
164258
}
165259

166260
showNycInfo(nycFilename)
167-
resolvePaths(nycFilename)
261+
const allSourceFilesMissing = checkAllPathsNotFound(nycFilename)
262+
if (allSourceFilesMissing) {
263+
tryFindingLocalFiles(nycFilename)
264+
}
265+
266+
resolveRelativePaths(nycFilename)
168267

169268
if (customNycReportScript) {
170269
debug(

utils.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,35 @@ function fixSourcePathes(coverage) {
5858
})
5959
}
6060

61+
/**
62+
* A small debug utility to inspect paths saved in NYC output JSON file
63+
*/
64+
function showNycInfo(nycFilename) {
65+
const nycCoverage = JSON.parse(readFileSync(nycFilename, 'utf8'))
66+
67+
const coverageKeys = Object.keys(nycCoverage)
68+
if (!coverageKeys.length) {
69+
console.error('⚠️ file %s has no coverage information', nycFilename)
70+
return
71+
}
72+
debug('NYC file %s has %d key(s)', nycFilename, coverageKeys.length)
73+
74+
const maxPrintKeys = 3
75+
const showKeys = coverageKeys.slice(0, maxPrintKeys)
76+
77+
showKeys.forEach((key, k) => {
78+
const coverage = nycCoverage[key]
79+
80+
// printing a few found keys and file paths from the coverage file
81+
// will make debugging any problems much much easier
82+
if (k < maxPrintKeys) {
83+
debug('%d key %s file path %s', k + 1, key, coverage.path)
84+
}
85+
})
86+
}
87+
6188
module.exports = {
6289
fixSourcePathes,
63-
filterSpecsFromCoverage
90+
filterSpecsFromCoverage,
91+
showNycInfo
6492
}

0 commit comments

Comments
 (0)