UNPKG

eslint-rule-benchmark

Version:

Benchmark ESLint rules with detailed performance metrics for CI and plugin development

176 lines (175 loc) 5.49 kB
import { collectSystemInfo } from './collect-system-info.js' import { formatDeviation } from './format-deviation.js' import { formatHz } from './format-hz.js' import { formatMs } from './format-ms.js' const MIN_COLUMN_WIDTH = 5 const CELL_PADDING = 1 const TABLE_HEADERS = [ 'Sample', 'Ops/sec', 'Avg Time', 'Median', 'Min', 'Max', 'StdDev', ] const EMPTY_ROW_VALUES = [ 'No samples', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A', ] async function useConsoleReport(results, _userConfig) { let outputLines = [] if (results.length === 0) { return 'No benchmark results available.' } let uniformColumnWidths = calculateUniformColumnWidths(results) for (let testSpecResult of results) { if (testSpecResult.testCaseResults.length === 0) { outputLines.push( ' No test cases found or all failed for this specification.', ) continue } let tableRows = [[testSpecResult.name], TABLE_HEADERS] let alignments = Array.from({ length: TABLE_HEADERS.length }).fill('left') for (let testCaseResult of testSpecResult.testCaseResults) { if (testCaseResult.samplesResults.length === 0) { tableRows.push(EMPTY_ROW_VALUES) continue } for (let sampleResult of testCaseResult.samplesResults) { let sampleName = extractSampleName( sampleResult.name, testCaseResult.name, ) tableRows.push(formatMetricsRow(sampleName, sampleResult)) } } outputLines.push(renderTable(tableRows, uniformColumnWidths, alignments)) } let systemInfo = await collectSystemInfo() outputLines.unshift('') outputLines.push('', formatSystemInfo(systemInfo), '') return outputLines.join('\n') } function renderTable(rows, fixedColumnWidths, columnAlignments) { let columnCount = Math.max(...rows.map(row => row.length)) let leftPads = fixedColumnWidths.map((_, i) => (i === 0 ? 0 : CELL_PADDING)) let rightPads = fixedColumnWidths.map((_, i) => i === columnCount - 1 ? 0 : CELL_PADDING, ) let separator = buildSeparator(fixedColumnWidths, leftPads, rightPads) let tableWidth = separator.length let lines = [] let processedRows = rows if (processedRows[0] && processedRows[0].length === 1) { lines.push( separator, padCell(processedRows[0][0], tableWidth, 'center'), separator, ) processedRows = processedRows.slice(1) } for (let row of processedRows) { let rendered = row .map((cell, col) => { let alignment = columnAlignments?.[col] let content = padCell(cell, fixedColumnWidths[col], alignment) let leftSpace = ' '.repeat(leftPads[col]) let rightSpace = ' '.repeat(rightPads[col]) return leftSpace + content + rightSpace }) .join('|') lines.push(rendered) } if (processedRows.length > 0) { lines.push(separator) } return lines.join('\n') } function calculateUniformColumnWidths(results) { let columnWidths = TABLE_HEADERS.map(header => header.length) for (let testSpecResult of results) { for (let testCaseResult of testSpecResult.testCaseResults) { if (testCaseResult.samplesResults.length === 0) { for (let [i, value] of EMPTY_ROW_VALUES.entries()) { columnWidths[i] = Math.max(columnWidths[i], value.length) } continue } for (let sampleResult of testCaseResult.samplesResults) { let sampleName = extractSampleName( sampleResult.name, testCaseResult.name, ) let rowValues = formatMetricsRow(sampleName, sampleResult) for (let [i, value] of rowValues.entries()) { columnWidths[i] = Math.max(columnWidths[i], value.length) } } } } return columnWidths.map(width => Math.max(width, MIN_COLUMN_WIDTH)) } function formatSystemInfo(systemInfo) { let runTime = [ `Node.js ${systemInfo.nodeVersion}`, `V8 ${systemInfo.v8Version}`, `ESLint ${systemInfo.eslintVersion}`, ] let platform = [ `${systemInfo.platform} ${systemInfo.arch} (${systemInfo.osRelease})`, ] let hardware = [ `${systemInfo.cpuModel} (${systemInfo.cpuCount} cores, ${systemInfo.cpuSpeedMHz} MHz)`, `${systemInfo.totalMemoryGb} GB RAM`, ] let formatList = new Intl.ListFormat('en-US', { type: 'conjunction', style: 'narrow', }) return [ 'System Information:', '', `Runtime: ${formatList.format(runTime)}`, `Platform: ${formatList.format(platform)}`, `Hardware: ${formatList.format(hardware)}`, ].join('\n') } function padCell(value, targetWidth, alignment) { if (value.length >= targetWidth) { return value } let gap = targetWidth - value.length if (alignment === 'left') { return value + ' '.repeat(gap) } let left = Math.floor(gap / 2) let right = gap - left return ' '.repeat(left) + value + ' '.repeat(right) } function formatMetricsRow(sampleName, sample) { return [ sampleName, formatHz(sample.metrics.hz), formatMs(sample.metrics.mean), formatMs(sample.metrics.median), formatMs(sample.metrics.min), formatMs(sample.metrics.max), formatDeviation(sample.metrics.stdDev), ] } function buildSeparator(columnWidths, leftPads, rightPads) { return columnWidths .map((width, i) => '-'.repeat(width + leftPads[i] + rightPads[i])) .join('-') } function extractSampleName(fullName, testCaseName) { return fullName.replace(`${testCaseName} on `, '') } export { useConsoleReport }