provider-87fc36e1.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. import { existsSync, promises } from 'fs';
  2. import _url from 'url';
  3. import { takeCoverage } from 'v8';
  4. import path from 'path';
  5. import { configDefaults } from 'vitest/config';
  6. import createReport from 'c8/lib/report.js';
  7. import { checkCoverages } from 'c8/lib/commands/check-coverage.js';
  8. function normalizeWindowsPath(input = "") {
  9. if (!input.includes("\\")) {
  10. return input;
  11. }
  12. return input.replace(/\\/g, "/");
  13. }
  14. const _UNC_REGEX = /^[/][/]/;
  15. const _UNC_DRIVE_REGEX = /^[/][/]([.]{1,2}[/])?([a-zA-Z]):[/]/;
  16. const _IS_ABSOLUTE_RE = /^\/|^\\|^[a-zA-Z]:[/\\]/;
  17. const sep = "/";
  18. const delimiter = ":";
  19. const normalize = function(path2) {
  20. if (path2.length === 0) {
  21. return ".";
  22. }
  23. path2 = normalizeWindowsPath(path2);
  24. const isUNCPath = path2.match(_UNC_REGEX);
  25. const hasUNCDrive = isUNCPath && path2.match(_UNC_DRIVE_REGEX);
  26. const isPathAbsolute = isAbsolute(path2);
  27. const trailingSeparator = path2[path2.length - 1] === "/";
  28. path2 = normalizeString(path2, !isPathAbsolute);
  29. if (path2.length === 0) {
  30. if (isPathAbsolute) {
  31. return "/";
  32. }
  33. return trailingSeparator ? "./" : ".";
  34. }
  35. if (trailingSeparator) {
  36. path2 += "/";
  37. }
  38. if (isUNCPath) {
  39. if (hasUNCDrive) {
  40. return `//./${path2}`;
  41. }
  42. return `//${path2}`;
  43. }
  44. return isPathAbsolute && !isAbsolute(path2) ? `/${path2}` : path2;
  45. };
  46. const join = function(...args) {
  47. if (args.length === 0) {
  48. return ".";
  49. }
  50. let joined;
  51. for (let i = 0; i < args.length; ++i) {
  52. const arg = args[i];
  53. if (arg.length > 0) {
  54. if (joined === void 0) {
  55. joined = arg;
  56. } else {
  57. joined += `/${arg}`;
  58. }
  59. }
  60. }
  61. if (joined === void 0) {
  62. return ".";
  63. }
  64. return normalize(joined);
  65. };
  66. const resolve = function(...args) {
  67. args = args.map((arg) => normalizeWindowsPath(arg));
  68. let resolvedPath = "";
  69. let resolvedAbsolute = false;
  70. for (let i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) {
  71. const path2 = i >= 0 ? args[i] : process.cwd();
  72. if (path2.length === 0) {
  73. continue;
  74. }
  75. resolvedPath = `${path2}/${resolvedPath}`;
  76. resolvedAbsolute = isAbsolute(path2);
  77. }
  78. resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute);
  79. if (resolvedAbsolute && !isAbsolute(resolvedPath)) {
  80. return `/${resolvedPath}`;
  81. }
  82. return resolvedPath.length > 0 ? resolvedPath : ".";
  83. };
  84. function normalizeString(path2, allowAboveRoot) {
  85. let res = "";
  86. let lastSegmentLength = 0;
  87. let lastSlash = -1;
  88. let dots = 0;
  89. let char = null;
  90. for (let i = 0; i <= path2.length; ++i) {
  91. if (i < path2.length) {
  92. char = path2[i];
  93. } else if (char === "/") {
  94. break;
  95. } else {
  96. char = "/";
  97. }
  98. if (char === "/") {
  99. if (lastSlash === i - 1 || dots === 1) ; else if (dots === 2) {
  100. if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {
  101. if (res.length > 2) {
  102. const lastSlashIndex = res.lastIndexOf("/");
  103. if (lastSlashIndex === -1) {
  104. res = "";
  105. lastSegmentLength = 0;
  106. } else {
  107. res = res.slice(0, lastSlashIndex);
  108. lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
  109. }
  110. lastSlash = i;
  111. dots = 0;
  112. continue;
  113. } else if (res.length !== 0) {
  114. res = "";
  115. lastSegmentLength = 0;
  116. lastSlash = i;
  117. dots = 0;
  118. continue;
  119. }
  120. }
  121. if (allowAboveRoot) {
  122. res += res.length > 0 ? "/.." : "..";
  123. lastSegmentLength = 2;
  124. }
  125. } else {
  126. if (res.length > 0) {
  127. res += `/${path2.slice(lastSlash + 1, i)}`;
  128. } else {
  129. res = path2.slice(lastSlash + 1, i);
  130. }
  131. lastSegmentLength = i - lastSlash - 1;
  132. }
  133. lastSlash = i;
  134. dots = 0;
  135. } else if (char === "." && dots !== -1) {
  136. ++dots;
  137. } else {
  138. dots = -1;
  139. }
  140. }
  141. return res;
  142. }
  143. const isAbsolute = function(p) {
  144. return _IS_ABSOLUTE_RE.test(p);
  145. };
  146. const toNamespacedPath = function(p) {
  147. return normalizeWindowsPath(p);
  148. };
  149. const extname = function(p) {
  150. return path.posix.extname(normalizeWindowsPath(p));
  151. };
  152. const relative = function(from, to) {
  153. return path.posix.relative(normalizeWindowsPath(from), normalizeWindowsPath(to));
  154. };
  155. const dirname = function(p) {
  156. return path.posix.dirname(normalizeWindowsPath(p));
  157. };
  158. const format = function(p) {
  159. return normalizeWindowsPath(path.posix.format(p));
  160. };
  161. const basename = function(p, ext) {
  162. return path.posix.basename(normalizeWindowsPath(p), ext);
  163. };
  164. const parse = function(p) {
  165. return path.posix.parse(normalizeWindowsPath(p));
  166. };
  167. const _path = /*#__PURE__*/Object.freeze({
  168. __proto__: null,
  169. sep: sep,
  170. delimiter: delimiter,
  171. normalize: normalize,
  172. join: join,
  173. resolve: resolve,
  174. normalizeString: normalizeString,
  175. isAbsolute: isAbsolute,
  176. toNamespacedPath: toNamespacedPath,
  177. extname: extname,
  178. relative: relative,
  179. dirname: dirname,
  180. format: format,
  181. basename: basename,
  182. parse: parse
  183. });
  184. ({
  185. ..._path
  186. });
  187. class C8CoverageProvider {
  188. constructor() {
  189. this.name = "c8";
  190. }
  191. initialize(ctx) {
  192. this.ctx = ctx;
  193. this.options = resolveC8Options(ctx.config.coverage, ctx.config.root);
  194. }
  195. resolveOptions() {
  196. return this.options;
  197. }
  198. onBeforeFilesRun() {
  199. var _a;
  200. (_a = process.env).NODE_V8_COVERAGE || (_a.NODE_V8_COVERAGE = this.options.tempDirectory);
  201. }
  202. async clean(clean = true) {
  203. if (clean && existsSync(this.options.reportsDirectory))
  204. await promises.rm(this.options.reportsDirectory, { recursive: true, force: true });
  205. if (!existsSync(this.options.tempDirectory))
  206. await promises.mkdir(this.options.tempDirectory, { recursive: true });
  207. }
  208. onAfterSuiteRun() {
  209. takeCoverage();
  210. }
  211. async reportCoverage() {
  212. takeCoverage();
  213. const report = createReport(this.ctx.config.coverage);
  214. const sourceMapMeta = {};
  215. await Promise.all(Array.from(this.ctx.vitenode.fetchCache.entries()).filter((i) => !i[0].includes("/node_modules/")).map(async ([file, { result }]) => {
  216. const map = result.map;
  217. if (!map)
  218. return;
  219. const url = _url.pathToFileURL(file).href;
  220. let code;
  221. try {
  222. code = (await promises.readFile(file)).toString();
  223. } catch {
  224. }
  225. const sources = [url];
  226. sourceMapMeta[url] = {
  227. source: result.code,
  228. map: {
  229. sourcesContent: code ? [code] : void 0,
  230. ...map,
  231. sources
  232. }
  233. };
  234. }));
  235. const offset = 224;
  236. report._getSourceMap = (coverage) => {
  237. const path = _url.pathToFileURL(coverage.url).href;
  238. const data = sourceMapMeta[path];
  239. if (!data)
  240. return {};
  241. return {
  242. sourceMap: {
  243. sourcemap: data.map
  244. },
  245. source: Array(offset).fill(".").join("") + data.source
  246. };
  247. };
  248. await report.run();
  249. await checkCoverages(this.options, report);
  250. }
  251. }
  252. function resolveC8Options(options, root) {
  253. const resolved = {
  254. ...configDefaults.coverage,
  255. ...options
  256. };
  257. if (options["100"]) {
  258. resolved.lines = 100;
  259. resolved.functions = 100;
  260. resolved.branches = 100;
  261. resolved.statements = 100;
  262. }
  263. resolved.reporter = resolved.reporter || [];
  264. resolved.reporter = Array.isArray(resolved.reporter) ? resolved.reporter : [resolved.reporter];
  265. resolved.reportsDirectory = resolve(root, resolved.reportsDirectory);
  266. resolved.tempDirectory = process.env.NODE_V8_COVERAGE || resolve(resolved.reportsDirectory, "tmp");
  267. return resolved;
  268. }
  269. export { C8CoverageProvider };