#!/usr/bin/env node // usage: flow-coverage // // Run flow coverage on project. const childProcess = require('child_process') const flow = require('flow-bin') const fs = require('fs') const {join} = require('path') const execFile = (file, args) => new Promise((resolve, reject) => { childProcess.execFile( file, args, { maxBuffer: Infinity }, (error, stdout, stderr) => { if (error) { reject(error) } else { resolve({stdout, stderr}) } } ) }) async function execFileJSON(file, args) { args.push('--json') const {stdout, stderr} = await execFile(file, args) if (stderr) { return JSON.parse(stderr) } else { return JSON.parse(stdout) } } function computeCoverage(covered, uncovered) { const total = covered + uncovered if (total) { return 100 * (covered / total) } else { return 100 } } async function getCoverage(path) { const json = await execFileJSON(flow, ['coverage', path]) if (json && json.expressions) { const uncoveredCount = json.expressions['uncovered_count'] const coveredCount = json.expressions['covered_count'] const covered = computeCoverage(coveredCount, uncoveredCount) return {path, uncoveredCount, coveredCount, covered} } else { return {path, uncoveredCount: 0, coveredCount: 0, covered: 0} } } async function startFlow() { try { await execFile(flow, ['start', '--wait']) } catch (error) { if (error.code === 11) { /* already running */ } else { throw error } } } // const ignore = [/\.flowconfig$/, /\.json$/, /\.test\.js$/, /\/__generated__\//, /\/flow-typed\//, /\/node_modules\//] // // async function flowList() { // execFile('git', ['grep', '--name-only', '--', '@flow']) // // const paths = await execFileJSON(flow, ['ls']) // return paths.filter(path => !ignore.some(re => re.test(path))) // } async function grepFlowFiles() { const {stdout} = await execFile('git', ['grep', '--null', '--name-only', '--', '@flow']) return stdout.split('\0').filter(path => path) } ;(async function() { let threshold = 0 const packageJsonPath = join(process.cwd(), 'package.json') if (fs.existsSync(packageJsonPath)) { const packageJson = require(packageJsonPath) threshold = (packageJson.flow && packageJson.flow.coverageThreshold) || 0 } await startFlow() const files = await grepFlowFiles() let totalCoveredCount = 0 let totalUncoveredCount = 0 for (const file of files) { const {path, covered, coveredCount, uncoveredCount} = await getCoverage(file) process.stdout.write(`${covered.toFixed()}\t${path}\n`) totalCoveredCount += coveredCount totalUncoveredCount += uncoveredCount } const totalCoverage = computeCoverage(totalCoveredCount, totalUncoveredCount) process.stdout.write(`${totalCoverage.toFixed()}\t(total)\n`) if (totalCoverage < threshold) { process.stderr.write(`expected at least ${threshold}% coverage, but was ${totalCoverage.toFixed()}%\n`) process.exit(1) } })().catch(error => { process.stderr.write(`${error}\n`) process.exit(2) })