web 3d图形渲染器
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

662 lines
18 KiB

  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. function path() {
  7. const data = _interopRequireWildcard(require('path'));
  8. path = function () {
  9. return data;
  10. };
  11. return data;
  12. }
  13. function _v8Coverage() {
  14. const data = require('@bcoe/v8-coverage');
  15. _v8Coverage = function () {
  16. return data;
  17. };
  18. return data;
  19. }
  20. function _chalk() {
  21. const data = _interopRequireDefault(require('chalk'));
  22. _chalk = function () {
  23. return data;
  24. };
  25. return data;
  26. }
  27. function _glob() {
  28. const data = _interopRequireDefault(require('glob'));
  29. _glob = function () {
  30. return data;
  31. };
  32. return data;
  33. }
  34. function fs() {
  35. const data = _interopRequireWildcard(require('graceful-fs'));
  36. fs = function () {
  37. return data;
  38. };
  39. return data;
  40. }
  41. function _istanbulLibCoverage() {
  42. const data = _interopRequireDefault(require('istanbul-lib-coverage'));
  43. _istanbulLibCoverage = function () {
  44. return data;
  45. };
  46. return data;
  47. }
  48. function _istanbulLibReport() {
  49. const data = _interopRequireDefault(require('istanbul-lib-report'));
  50. _istanbulLibReport = function () {
  51. return data;
  52. };
  53. return data;
  54. }
  55. function _istanbulLibSourceMaps() {
  56. const data = _interopRequireDefault(require('istanbul-lib-source-maps'));
  57. _istanbulLibSourceMaps = function () {
  58. return data;
  59. };
  60. return data;
  61. }
  62. function _istanbulReports() {
  63. const data = _interopRequireDefault(require('istanbul-reports'));
  64. _istanbulReports = function () {
  65. return data;
  66. };
  67. return data;
  68. }
  69. function _v8ToIstanbul() {
  70. const data = _interopRequireDefault(require('v8-to-istanbul'));
  71. _v8ToIstanbul = function () {
  72. return data;
  73. };
  74. return data;
  75. }
  76. function _jestUtil() {
  77. const data = require('jest-util');
  78. _jestUtil = function () {
  79. return data;
  80. };
  81. return data;
  82. }
  83. function _jestWorker() {
  84. const data = _interopRequireDefault(require('jest-worker'));
  85. _jestWorker = function () {
  86. return data;
  87. };
  88. return data;
  89. }
  90. var _BaseReporter = _interopRequireDefault(require('./BaseReporter'));
  91. var _getWatermarks = _interopRequireDefault(require('./getWatermarks'));
  92. function _interopRequireDefault(obj) {
  93. return obj && obj.__esModule ? obj : {default: obj};
  94. }
  95. function _getRequireWildcardCache() {
  96. if (typeof WeakMap !== 'function') return null;
  97. var cache = new WeakMap();
  98. _getRequireWildcardCache = function () {
  99. return cache;
  100. };
  101. return cache;
  102. }
  103. function _interopRequireWildcard(obj) {
  104. if (obj && obj.__esModule) {
  105. return obj;
  106. }
  107. if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
  108. return {default: obj};
  109. }
  110. var cache = _getRequireWildcardCache();
  111. if (cache && cache.has(obj)) {
  112. return cache.get(obj);
  113. }
  114. var newObj = {};
  115. var hasPropertyDescriptor =
  116. Object.defineProperty && Object.getOwnPropertyDescriptor;
  117. for (var key in obj) {
  118. if (Object.prototype.hasOwnProperty.call(obj, key)) {
  119. var desc = hasPropertyDescriptor
  120. ? Object.getOwnPropertyDescriptor(obj, key)
  121. : null;
  122. if (desc && (desc.get || desc.set)) {
  123. Object.defineProperty(newObj, key, desc);
  124. } else {
  125. newObj[key] = obj[key];
  126. }
  127. }
  128. }
  129. newObj.default = obj;
  130. if (cache) {
  131. cache.set(obj, newObj);
  132. }
  133. return newObj;
  134. }
  135. function _defineProperty(obj, key, value) {
  136. if (key in obj) {
  137. Object.defineProperty(obj, key, {
  138. value: value,
  139. enumerable: true,
  140. configurable: true,
  141. writable: true
  142. });
  143. } else {
  144. obj[key] = value;
  145. }
  146. return obj;
  147. }
  148. const FAIL_COLOR = _chalk().default.bold.red;
  149. const RUNNING_TEST_COLOR = _chalk().default.bold.dim;
  150. class CoverageReporter extends _BaseReporter.default {
  151. constructor(globalConfig, options) {
  152. super();
  153. _defineProperty(this, '_coverageMap', void 0);
  154. _defineProperty(this, '_globalConfig', void 0);
  155. _defineProperty(this, '_sourceMapStore', void 0);
  156. _defineProperty(this, '_options', void 0);
  157. _defineProperty(this, '_v8CoverageResults', void 0);
  158. this._coverageMap = _istanbulLibCoverage().default.createCoverageMap({});
  159. this._globalConfig = globalConfig;
  160. this._sourceMapStore = _istanbulLibSourceMaps().default.createSourceMapStore();
  161. this._v8CoverageResults = [];
  162. this._options = options || {};
  163. }
  164. onTestResult(_test, testResult) {
  165. if (testResult.v8Coverage) {
  166. this._v8CoverageResults.push(testResult.v8Coverage);
  167. return;
  168. }
  169. if (testResult.coverage) {
  170. this._coverageMap.merge(testResult.coverage);
  171. }
  172. }
  173. async onRunComplete(contexts, aggregatedResults) {
  174. await this._addUntestedFiles(contexts);
  175. const {map, reportContext} = await this._getCoverageResult();
  176. try {
  177. const coverageReporters = this._globalConfig.coverageReporters || [];
  178. if (!this._globalConfig.useStderr && coverageReporters.length < 1) {
  179. coverageReporters.push('text-summary');
  180. }
  181. coverageReporters.forEach(reporter => {
  182. let additionalOptions = {};
  183. if (Array.isArray(reporter)) {
  184. [reporter, additionalOptions] = reporter;
  185. }
  186. _istanbulReports()
  187. .default.create(reporter, {
  188. maxCols: process.stdout.columns || Infinity,
  189. ...additionalOptions
  190. }) // @ts-expect-error
  191. .execute(reportContext);
  192. });
  193. aggregatedResults.coverageMap = map;
  194. } catch (e) {
  195. console.error(
  196. _chalk().default.red(`
  197. Failed to write coverage reports:
  198. ERROR: ${e.toString()}
  199. STACK: ${e.stack}
  200. `)
  201. );
  202. }
  203. this._checkThreshold(map);
  204. }
  205. async _addUntestedFiles(contexts) {
  206. const files = [];
  207. contexts.forEach(context => {
  208. const config = context.config;
  209. if (
  210. this._globalConfig.collectCoverageFrom &&
  211. this._globalConfig.collectCoverageFrom.length
  212. ) {
  213. context.hasteFS
  214. .matchFilesWithGlob(
  215. this._globalConfig.collectCoverageFrom,
  216. config.rootDir
  217. )
  218. .forEach(filePath =>
  219. files.push({
  220. config,
  221. path: filePath
  222. })
  223. );
  224. }
  225. });
  226. if (!files.length) {
  227. return;
  228. }
  229. if (_jestUtil().isInteractive) {
  230. process.stderr.write(
  231. RUNNING_TEST_COLOR('Running coverage on untested files...')
  232. );
  233. }
  234. let worker;
  235. if (this._globalConfig.maxWorkers <= 1) {
  236. worker = require('./CoverageWorker');
  237. } else {
  238. worker = new (_jestWorker().default)(
  239. require.resolve('./CoverageWorker'),
  240. {
  241. exposedMethods: ['worker'],
  242. maxRetries: 2,
  243. numWorkers: this._globalConfig.maxWorkers
  244. }
  245. );
  246. }
  247. const instrumentation = files.map(async fileObj => {
  248. const filename = fileObj.path;
  249. const config = fileObj.config;
  250. const hasCoverageData = this._v8CoverageResults.some(v8Res =>
  251. v8Res.some(innerRes => innerRes.result.url === filename)
  252. );
  253. if (
  254. !hasCoverageData &&
  255. !this._coverageMap.data[filename] &&
  256. 'worker' in worker
  257. ) {
  258. try {
  259. const result = await worker.worker({
  260. config,
  261. globalConfig: this._globalConfig,
  262. options: {
  263. ...this._options,
  264. changedFiles:
  265. this._options.changedFiles &&
  266. Array.from(this._options.changedFiles),
  267. sourcesRelatedToTestsInChangedFiles:
  268. this._options.sourcesRelatedToTestsInChangedFiles &&
  269. Array.from(this._options.sourcesRelatedToTestsInChangedFiles)
  270. },
  271. path: filename
  272. });
  273. if (result) {
  274. if (result.kind === 'V8Coverage') {
  275. this._v8CoverageResults.push([
  276. {
  277. codeTransformResult: undefined,
  278. result: result.result
  279. }
  280. ]);
  281. } else {
  282. this._coverageMap.addFileCoverage(result.coverage);
  283. }
  284. }
  285. } catch (error) {
  286. console.error(
  287. _chalk().default.red(
  288. [
  289. `Failed to collect coverage from ${filename}`,
  290. `ERROR: ${error.message}`,
  291. `STACK: ${error.stack}`
  292. ].join('\n')
  293. )
  294. );
  295. }
  296. }
  297. });
  298. try {
  299. await Promise.all(instrumentation);
  300. } catch {
  301. // Do nothing; errors were reported earlier to the console.
  302. }
  303. if (_jestUtil().isInteractive) {
  304. (0, _jestUtil().clearLine)(process.stderr);
  305. }
  306. if (worker && 'end' in worker && typeof worker.end === 'function') {
  307. await worker.end();
  308. }
  309. }
  310. _checkThreshold(map) {
  311. const {coverageThreshold} = this._globalConfig;
  312. if (coverageThreshold) {
  313. function check(name, thresholds, actuals) {
  314. return ['statements', 'branches', 'lines', 'functions'].reduce(
  315. (errors, key) => {
  316. const actual = actuals[key].pct;
  317. const actualUncovered = actuals[key].total - actuals[key].covered;
  318. const threshold = thresholds[key];
  319. if (threshold !== undefined) {
  320. if (threshold < 0) {
  321. if (threshold * -1 < actualUncovered) {
  322. errors.push(
  323. `Jest: Uncovered count for ${key} (${actualUncovered}) ` +
  324. `exceeds ${name} threshold (${-1 * threshold})`
  325. );
  326. }
  327. } else if (actual < threshold) {
  328. errors.push(
  329. `Jest: "${name}" coverage threshold for ${key} (${threshold}%) not met: ${actual}%`
  330. );
  331. }
  332. }
  333. return errors;
  334. },
  335. []
  336. );
  337. }
  338. const THRESHOLD_GROUP_TYPES = {
  339. GLOB: 'glob',
  340. GLOBAL: 'global',
  341. PATH: 'path'
  342. };
  343. const coveredFiles = map.files();
  344. const thresholdGroups = Object.keys(coverageThreshold);
  345. const groupTypeByThresholdGroup = {};
  346. const filesByGlob = {};
  347. const coveredFilesSortedIntoThresholdGroup = coveredFiles.reduce(
  348. (files, file) => {
  349. const pathOrGlobMatches = thresholdGroups.reduce(
  350. (agg, thresholdGroup) => {
  351. const absoluteThresholdGroup = path().resolve(thresholdGroup); // The threshold group might be a path:
  352. if (file.indexOf(absoluteThresholdGroup) === 0) {
  353. groupTypeByThresholdGroup[thresholdGroup] =
  354. THRESHOLD_GROUP_TYPES.PATH;
  355. return agg.concat([[file, thresholdGroup]]);
  356. } // If the threshold group is not a path it might be a glob:
  357. // Note: glob.sync is slow. By memoizing the files matching each glob
  358. // (rather than recalculating it for each covered file) we save a tonne
  359. // of execution time.
  360. if (filesByGlob[absoluteThresholdGroup] === undefined) {
  361. filesByGlob[absoluteThresholdGroup] = _glob()
  362. .default.sync(absoluteThresholdGroup)
  363. .map(filePath => path().resolve(filePath));
  364. }
  365. if (filesByGlob[absoluteThresholdGroup].indexOf(file) > -1) {
  366. groupTypeByThresholdGroup[thresholdGroup] =
  367. THRESHOLD_GROUP_TYPES.GLOB;
  368. return agg.concat([[file, thresholdGroup]]);
  369. }
  370. return agg;
  371. },
  372. []
  373. );
  374. if (pathOrGlobMatches.length > 0) {
  375. return files.concat(pathOrGlobMatches);
  376. } // Neither a glob or a path? Toss it in global if there's a global threshold:
  377. if (thresholdGroups.indexOf(THRESHOLD_GROUP_TYPES.GLOBAL) > -1) {
  378. groupTypeByThresholdGroup[THRESHOLD_GROUP_TYPES.GLOBAL] =
  379. THRESHOLD_GROUP_TYPES.GLOBAL;
  380. return files.concat([[file, THRESHOLD_GROUP_TYPES.GLOBAL]]);
  381. } // A covered file that doesn't have a threshold:
  382. return files.concat([[file, undefined]]);
  383. },
  384. []
  385. );
  386. const getFilesInThresholdGroup = thresholdGroup =>
  387. coveredFilesSortedIntoThresholdGroup
  388. .filter(fileAndGroup => fileAndGroup[1] === thresholdGroup)
  389. .map(fileAndGroup => fileAndGroup[0]);
  390. function combineCoverage(filePaths) {
  391. return filePaths
  392. .map(filePath => map.fileCoverageFor(filePath))
  393. .reduce((combinedCoverage, nextFileCoverage) => {
  394. if (combinedCoverage === undefined || combinedCoverage === null) {
  395. return nextFileCoverage.toSummary();
  396. }
  397. return combinedCoverage.merge(nextFileCoverage.toSummary());
  398. }, undefined);
  399. }
  400. let errors = [];
  401. thresholdGroups.forEach(thresholdGroup => {
  402. switch (groupTypeByThresholdGroup[thresholdGroup]) {
  403. case THRESHOLD_GROUP_TYPES.GLOBAL: {
  404. const coverage = combineCoverage(
  405. getFilesInThresholdGroup(THRESHOLD_GROUP_TYPES.GLOBAL)
  406. );
  407. if (coverage) {
  408. errors = errors.concat(
  409. check(
  410. thresholdGroup,
  411. coverageThreshold[thresholdGroup],
  412. coverage
  413. )
  414. );
  415. }
  416. break;
  417. }
  418. case THRESHOLD_GROUP_TYPES.PATH: {
  419. const coverage = combineCoverage(
  420. getFilesInThresholdGroup(thresholdGroup)
  421. );
  422. if (coverage) {
  423. errors = errors.concat(
  424. check(
  425. thresholdGroup,
  426. coverageThreshold[thresholdGroup],
  427. coverage
  428. )
  429. );
  430. }
  431. break;
  432. }
  433. case THRESHOLD_GROUP_TYPES.GLOB:
  434. getFilesInThresholdGroup(thresholdGroup).forEach(
  435. fileMatchingGlob => {
  436. errors = errors.concat(
  437. check(
  438. fileMatchingGlob,
  439. coverageThreshold[thresholdGroup],
  440. map.fileCoverageFor(fileMatchingGlob).toSummary()
  441. )
  442. );
  443. }
  444. );
  445. break;
  446. default:
  447. // If the file specified by path is not found, error is returned.
  448. if (thresholdGroup !== THRESHOLD_GROUP_TYPES.GLOBAL) {
  449. errors = errors.concat(
  450. `Jest: Coverage data for ${thresholdGroup} was not found.`
  451. );
  452. }
  453. // Sometimes all files in the coverage data are matched by
  454. // PATH and GLOB threshold groups in which case, don't error when
  455. // the global threshold group doesn't match any files.
  456. }
  457. });
  458. errors = errors.filter(
  459. err => err !== undefined && err !== null && err.length > 0
  460. );
  461. if (errors.length > 0) {
  462. this.log(`${FAIL_COLOR(errors.join('\n'))}`);
  463. this._setError(new Error(errors.join('\n')));
  464. }
  465. }
  466. }
  467. async _getCoverageResult() {
  468. if (this._globalConfig.coverageProvider === 'v8') {
  469. const mergedCoverages = (0, _v8Coverage().mergeProcessCovs)(
  470. this._v8CoverageResults.map(cov => ({
  471. result: cov.map(r => r.result)
  472. }))
  473. );
  474. const fileTransforms = new Map();
  475. this._v8CoverageResults.forEach(res =>
  476. res.forEach(r => {
  477. if (r.codeTransformResult && !fileTransforms.has(r.result.url)) {
  478. fileTransforms.set(r.result.url, r.codeTransformResult);
  479. }
  480. })
  481. );
  482. const transformedCoverage = await Promise.all(
  483. mergedCoverages.result.map(async res => {
  484. var _fileTransform$wrappe;
  485. const fileTransform = fileTransforms.get(res.url);
  486. let sourcemapContent = undefined;
  487. if (
  488. fileTransform &&
  489. fileTransform.sourceMapPath &&
  490. fs().existsSync(fileTransform.sourceMapPath)
  491. ) {
  492. sourcemapContent = JSON.parse(
  493. fs().readFileSync(fileTransform.sourceMapPath, 'utf8')
  494. );
  495. }
  496. const converter = (0, _v8ToIstanbul().default)(
  497. res.url,
  498. (_fileTransform$wrappe =
  499. fileTransform === null || fileTransform === void 0
  500. ? void 0
  501. : fileTransform.wrapperLength) !== null &&
  502. _fileTransform$wrappe !== void 0
  503. ? _fileTransform$wrappe
  504. : 0,
  505. fileTransform && sourcemapContent
  506. ? {
  507. originalSource: fileTransform.originalCode,
  508. source: fileTransform.code,
  509. sourceMap: {
  510. sourcemap: sourcemapContent
  511. }
  512. }
  513. : {
  514. source: fs().readFileSync(res.url, 'utf8')
  515. }
  516. );
  517. await converter.load();
  518. converter.applyCoverage(res.functions);
  519. return converter.toIstanbul();
  520. })
  521. );
  522. const map = _istanbulLibCoverage().default.createCoverageMap({});
  523. transformedCoverage.forEach(res => map.merge(res));
  524. const reportContext = _istanbulLibReport().default.createContext({
  525. coverageMap: map,
  526. dir: this._globalConfig.coverageDirectory,
  527. watermarks: (0, _getWatermarks.default)(this._globalConfig)
  528. });
  529. return {
  530. map,
  531. reportContext
  532. };
  533. }
  534. const map = await this._sourceMapStore.transformCoverage(this._coverageMap);
  535. const reportContext = _istanbulLibReport().default.createContext({
  536. coverageMap: map,
  537. dir: this._globalConfig.coverageDirectory,
  538. sourceFinder: this._sourceMapStore.sourceFinder,
  539. watermarks: (0, _getWatermarks.default)(this._globalConfig)
  540. });
  541. return {
  542. map,
  543. reportContext
  544. };
  545. }
  546. }
  547. exports.default = CoverageReporter;