or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdcollection.mdconfiguration.mdhooks.mdindex.mdinstrumentation.mdreporting.mdstorage.mdtree-summarizer.mdutilities.md
tile.json

utilities.mddocs/

0

# Coverage Utilities

1

2

Coverage utilities process and manipulate coverage objects including merging, summarization, format conversion, and derived metric calculation. These functions work with the raw coverage data structures generated by instrumented code.

3

4

## Capabilities

5

6

### Coverage Processing

7

8

Process coverage objects to add derived information and calculate metrics.

9

10

```javascript { .api }

11

const utils = {

12

/**

13

* Adds line coverage information to all file coverage objects

14

* @param {Object} coverage - Coverage object containing file coverage data

15

*/

16

addDerivedInfo(coverage: Object): void;

17

18

/**

19

* Adds line coverage information to a single file coverage object

20

* @param {Object} fileCoverage - Single file coverage object

21

*/

22

addDerivedInfoForFile(fileCoverage: Object): void;

23

24

/**

25

* Removes line coverage information from coverage objects

26

* @param {Object} coverage - Coverage object to clean

27

*/

28

removeDerivedInfo(coverage: Object): void;

29

30

/**

31

* Returns a blank summary metrics object

32

* @returns {Object} Empty summary with zero counts

33

*/

34

blankSummary(): Object;

35

36

/**

37

* Returns summary metrics for a single file coverage object

38

* @param {Object} fileCoverage - File coverage object

39

* @returns {Object} Summary metrics (totals, covered, skipped, percentages)

40

*/

41

summarizeFileCoverage(fileCoverage: Object): Object;

42

43

/**

44

* Returns summary metrics for entire coverage object

45

* @param {Object} coverage - Complete coverage object

46

* @returns {Object} Aggregated summary metrics

47

*/

48

summarizeCoverage(coverage: Object): Object;

49

50

/**

51

* Merges two file coverage objects

52

* @param {Object} first - First file coverage object

53

* @param {Object} second - Second file coverage object

54

* @returns {Object} Merged file coverage object

55

*/

56

mergeFileCoverage(first: Object, second: Object): Object;

57

58

/**

59

* Merges multiple summary metrics objects

60

* @param {...Object} summaries - Summary objects to merge

61

* @returns {Object} Merged summary metrics

62

*/

63

mergeSummaryObjects(...summaries: Object[]): Object;

64

65

/**

66

* Converts coverage object to YUI Test coverage format

67

* @param {Object} coverage - Istanbul coverage object

68

* @returns {Object} YUI Test coverage format

69

*/

70

toYUICoverage(coverage: Object): Object;

71

72

/**

73

* Increments hit counts on items marked as ignored/skipped

74

* @param {Object} cov - File coverage object to process

75

* @returns {Object} New file coverage object with incremented ignored totals

76

*/

77

incrementIgnoredTotals(cov: Object): Object;

78

};

79

```

80

81

**Usage Examples:**

82

83

```javascript

84

const { utils } = require('istanbul');

85

86

// Process coverage data after collection

87

const collector = new Collector();

88

collector.add(global.__coverage__);

89

const coverage = collector.getFinalCoverage();

90

91

// Add line coverage information (derived from statements)

92

utils.addDerivedInfo(coverage);

93

94

// Get summary metrics

95

const summary = utils.summarizeCoverage(coverage);

96

console.log('Overall coverage:', summary);

97

98

// Get summary for individual files

99

Object.keys(coverage).forEach(filename => {

100

const fileSummary = utils.summarizeFileCoverage(coverage[filename]);

101

console.log(`${filename}: ${fileSummary.statements.pct}% statements`);

102

});

103

```

104

105

### Summary Metrics Structure

106

107

Summary objects returned by utility functions contain comprehensive coverage metrics:

108

109

```javascript { .api }

110

interface SummaryMetrics {

111

/** Statement coverage metrics */

112

statements: CoverageMetric;

113

114

/** Branch coverage metrics */

115

branches: CoverageMetric;

116

117

/** Function coverage metrics */

118

functions: CoverageMetric;

119

120

/** Line coverage metrics */

121

lines: CoverageMetric;

122

}

123

124

interface CoverageMetric {

125

/** Total number of items */

126

total: number;

127

128

/** Number of covered items */

129

covered: number;

130

131

/** Number of skipped/ignored items */

132

skipped: number;

133

134

/** Coverage percentage (0-100) */

135

pct: number;

136

}

137

```

138

139

**Example Summary Output:**

140

141

```javascript

142

const summary = utils.summarizeCoverage(coverage);

143

console.log(JSON.stringify(summary, null, 2));

144

145

// Output:

146

{

147

"statements": {

148

"total": 45,

149

"covered": 38,

150

"skipped": 0,

151

"pct": 84.44

152

},

153

"branches": {

154

"total": 12,

155

"covered": 9,

156

"skipped": 0,

157

"pct": 75

158

},

159

"functions": {

160

"total": 8,

161

"covered": 7,

162

"skipped": 0,

163

"pct": 87.5

164

},

165

"lines": {

166

"total": 42,

167

"covered": 35,

168

"skipped": 0,

169

"pct": 83.33

170

}

171

}

172

```

173

174

### Coverage Merging

175

176

Merge coverage data from multiple sources or test runs:

177

178

```javascript

179

// Merge file coverage objects

180

const merged = utils.mergeFileCoverage(coverage1['app.js'], coverage2['app.js']);

181

182

// Example: coverage from two test runs

183

const testRun1 = {

184

s: { '1': 1, '2': 0, '3': 1 }, // statements

185

b: { '1': [1, 0] }, // branches

186

f: { '1': 1, '2': 0 } // functions

187

};

188

189

const testRun2 = {

190

s: { '1': 1, '2': 1, '3': 1 },

191

b: { '1': [1, 1] },

192

f: { '1': 1, '2': 1 }

193

};

194

195

const mergedFile = utils.mergeFileCoverage(testRun1, testRun2);

196

// Result: { s: { '1': 2, '2': 1, '3': 2 }, b: { '1': [2, 1] }, f: { '1': 2, '2': 1 } }

197

198

// Merge summary objects

199

const summary1 = utils.summarizeFileCoverage(coverage1['file1.js']);

200

const summary2 = utils.summarizeFileCoverage(coverage2['file2.js']);

201

const combinedSummary = utils.mergeSummaryObjects(summary1, summary2);

202

```

203

204

### Line Coverage Derivation

205

206

Add line coverage information derived from statement coverage:

207

208

```javascript

209

// Coverage object before adding derived info

210

const fileCoverage = {

211

path: 'app.js',

212

s: { '1': 1, '2': 0, '3': 1 },

213

statementMap: {

214

'1': { start: { line: 5, column: 0 }, end: { line: 5, column: 20 } },

215

'2': { start: { line: 8, column: 4 }, end: { line: 8, column: 15 } },

216

'3': { start: { line: 12, column: 0 }, end: { line: 12, column: 25 } }

217

}

218

// ... other coverage data

219

};

220

221

// Add line coverage (modifies object in place)

222

utils.addDerivedInfoForFile(fileCoverage);

223

224

// Now includes line coverage derived from statements

225

console.log(fileCoverage.l);

226

// Output: { '5': 1, '8': 0, '12': 1 }

227

228

// Remove derived info if needed

229

utils.removeDerivedInfo({ 'app.js': fileCoverage });

230

```

231

232

### Format Conversion

233

234

Convert between Istanbul and other coverage formats:

235

236

```javascript

237

// Convert to YUI Test format

238

const yuiCoverage = utils.toYUICoverage(coverage);

239

240

// YUI format is different structure optimized for YUI Test

241

console.log('YUI coverage format:', yuiCoverage);

242

243

// Example conversion

244

const istanbulCoverage = {

245

'app.js': {

246

path: 'app.js',

247

s: { '1': 1, '2': 0 },

248

b: { '1': [1, 0] },

249

f: { '1': 1 }

250

// ... other data

251

}

252

};

253

254

const yui = utils.toYUICoverage(istanbulCoverage);

255

// Converts to YUI Test's expected coverage object structure

256

```

257

258

### Advanced Processing Examples

259

260

#### Coverage Aggregation Pipeline

261

262

```javascript

263

function processCoverageData(coverageFiles) {

264

const allCoverage = {};

265

266

// Merge all coverage files

267

coverageFiles.forEach(file => {

268

const coverage = require(file);

269

270

Object.keys(coverage).forEach(filename => {

271

if (allCoverage[filename]) {

272

// Merge with existing

273

allCoverage[filename] = utils.mergeFileCoverage(

274

allCoverage[filename],

275

coverage[filename]

276

);

277

} else {

278

// First occurrence

279

allCoverage[filename] = coverage[filename];

280

}

281

});

282

});

283

284

// Add derived information

285

utils.addDerivedInfo(allCoverage);

286

287

// Generate summary

288

const summary = utils.summarizeCoverage(allCoverage);

289

290

return {

291

coverage: allCoverage,

292

summary: summary

293

};

294

}

295

```

296

297

#### Coverage Filtering and Analysis

298

299

```javascript

300

function analyzeCoverageQuality(coverage) {

301

utils.addDerivedInfo(coverage);

302

303

const fileAnalysis = [];

304

305

Object.keys(coverage).forEach(filename => {

306

const fileCoverage = coverage[filename];

307

const summary = utils.summarizeFileCoverage(fileCoverage);

308

309

fileAnalysis.push({

310

file: filename,

311

statements: summary.statements.pct,

312

branches: summary.branches.pct,

313

functions: summary.functions.pct,

314

lines: summary.lines.pct,

315

issues: []

316

});

317

318

// Identify coverage issues

319

const analysis = fileAnalysis[fileAnalysis.length - 1];

320

321

if (summary.statements.pct < 80) {

322

analysis.issues.push('Low statement coverage');

323

}

324

325

if (summary.branches.pct < 70) {

326

analysis.issues.push('Low branch coverage');

327

}

328

329

if (summary.functions.pct < 90) {

330

analysis.issues.push('Low function coverage');

331

}

332

});

333

334

return fileAnalysis;

335

}

336

```

337

338

#### Custom Summary Generation

339

340

```javascript

341

function generateCustomSummary(coverage) {

342

const blank = utils.blankSummary();

343

const files = Object.keys(coverage);

344

345

// Generate summary for each directory

346

const directorySummaries = {};

347

348

files.forEach(filename => {

349

const directory = path.dirname(filename);

350

351

if (!directorySummaries[directory]) {

352

directorySummaries[directory] = utils.blankSummary();

353

}

354

355

const fileSummary = utils.summarizeFileCoverage(coverage[filename]);

356

directorySummaries[directory] = utils.mergeSummaryObjects(

357

directorySummaries[directory],

358

fileSummary

359

);

360

});

361

362

// Overall summary

363

const overallSummary = utils.summarizeCoverage(coverage);

364

365

return {

366

overall: overallSummary,

367

directories: directorySummaries,

368

files: files.map(f => ({

369

name: f,

370

summary: utils.summarizeFileCoverage(coverage[f])

371

}))

372

};

373

}

374

```

375

376

### Working with Coverage Thresholds

377

378

```javascript

379

function checkCoverageThresholds(coverage, thresholds) {

380

const summary = utils.summarizeCoverage(coverage);

381

const results = {};

382

383

['statements', 'branches', 'functions', 'lines'].forEach(metric => {

384

const threshold = thresholds[metric];

385

const actual = summary[metric].pct;

386

387

results[metric] = {

388

threshold: threshold,

389

actual: actual,

390

passed: actual >= threshold,

391

difference: actual - threshold

392

};

393

});

394

395

return results;

396

}

397

398

// Usage

399

const thresholds = {

400

statements: 80,

401

branches: 75,

402

functions: 85,

403

lines: 80

404

};

405

406

const results = checkCoverageThresholds(coverage, thresholds);

407

console.log('Threshold results:', results);

408

409

// Check if all thresholds passed

410

const allPassed = Object.values(results).every(r => r.passed);

411

if (!allPassed) {

412

console.error('Coverage thresholds not met');

413

process.exit(1);

414

}

415

```

416

417

### Performance Optimization

418

419

For large coverage objects, optimize processing:

420

421

```javascript

422

// Process coverage in chunks for large datasets

423

function processLargeCoverage(coverage, chunkSize = 100) {

424

const files = Object.keys(coverage);

425

const results = [];

426

427

for (let i = 0; i < files.length; i += chunkSize) {

428

const chunk = files.slice(i, i + chunkSize);

429

const chunkCoverage = {};

430

431

chunk.forEach(file => {

432

chunkCoverage[file] = coverage[file];

433

});

434

435

// Process chunk

436

utils.addDerivedInfo(chunkCoverage);

437

const chunkSummary = utils.summarizeCoverage(chunkCoverage);

438

439

results.push(chunkSummary);

440

441

// Allow event loop to process other tasks

442

if (i % (chunkSize * 10) === 0) {

443

await new Promise(resolve => setImmediate(resolve));

444

}

445

}

446

447

// Merge all chunk summaries

448

return utils.mergeSummaryObjects(...results);

449

}

450

```

451

452

### Error Handling

453

454

Handle malformed coverage data:

455

456

```javascript

457

function safeCoverageProcessing(coverage) {

458

try {

459

// Validate coverage structure

460

if (typeof coverage !== 'object' || coverage === null) {

461

throw new Error('Invalid coverage object');

462

}

463

464

// Process each file safely

465

Object.keys(coverage).forEach(filename => {

466

const fileCoverage = coverage[filename];

467

468

if (!fileCoverage.s || !fileCoverage.b || !fileCoverage.f) {

469

console.warn(`Incomplete coverage data for ${filename}`);

470

return;

471

}

472

473

try {

474

utils.addDerivedInfoForFile(fileCoverage);

475

} catch (error) {

476

console.warn(`Failed to process ${filename}:`, error.message);

477

}

478

});

479

480

return utils.summarizeCoverage(coverage);

481

482

} catch (error) {

483

console.error('Coverage processing failed:', error.message);

484

return utils.blankSummary();

485

}

486

}

487

```