UNPKG

eslint-rule-benchmark

Version:

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

138 lines (137 loc) 4.76 kB
import fs from 'node:fs/promises' import path from 'node:path' async function validateConfig(config, configDirectory) { let errors = [] if ( !config.tests || !Array.isArray(config.tests) || config.tests.length === 0 ) { errors.push( 'Configuration must include at least one test in the "tests" array.', ) return errors } errors.push(...validateBaseBenchmarkSettings(config)) let validationPromises = config.tests.map(async (testSpec, testIndex) => { let testSpecErrors = [] let testPrefix = `Test "${testSpec.name || `at index ${testIndex}`}"` if (!testSpec.name) { testSpecErrors.push(`Test at index ${testIndex}: "name" is required.`) } if (!testSpec.ruleId) { testSpecErrors.push(`${testPrefix}: "ruleId" is required.`) } if (testSpec.rulePath) { try { let rulePath = path.resolve(configDirectory, testSpec.rulePath) await fs.access(rulePath) } catch { testSpecErrors.push( `${testPrefix}: Rule file not found at "${testSpec.rulePath}".`, ) } } else { testSpecErrors.push(`${testPrefix}: "rulePath" is required.`) } let baseSettingsErrors = validateBaseBenchmarkSettings(testSpec) if (baseSettingsErrors.length > 0) { testSpecErrors.push( ...baseSettingsErrors.map(error => `${testPrefix}: ${error}`), ) } if (!Array.isArray(testSpec.cases) || testSpec.cases.length === 0) { testSpecErrors.push( `${testPrefix}: must include at least one case in the "cases" array.`, ) } else { let caseValidationPromises = testSpec.cases.map( async (caseItem, caseIndex) => { let caseErrors = [] let casePrefix = `${testPrefix}, Case ${caseIndex + 1}` if (caseItem.testPath) { let pathsToTest = Array.isArray(caseItem.testPath) ? caseItem.testPath : [caseItem.testPath] if (pathsToTest.length === 0) { caseErrors.push( `${casePrefix}: "testPath" array cannot be empty.`, ) } let pathCheckPromises = pathsToTest.map(async pathToTest => { if (typeof pathToTest !== 'string') { return `${casePrefix}: each item in "testPath" must be a string.` } try { let testFilePath = path.resolve(configDirectory, pathToTest) await fs.access(testFilePath) return null } catch { return `${casePrefix}: Test file/directory not found at "${pathToTest}".` } }) let pathErrors = (await Promise.all(pathCheckPromises)).filter( Boolean, ) caseErrors.push(...pathErrors) } else { caseErrors.push(`${casePrefix}: "testPath" is required.`) } if ( caseItem.severity !== void 0 && (typeof caseItem.severity !== 'number' || ![0, 1, 2].includes(caseItem.severity)) ) { caseErrors.push(`${casePrefix}: "severity" must be 0, 1, or 2.`) } if (caseItem.options !== void 0 && !Array.isArray(caseItem.options)) { caseErrors.push(`${casePrefix}: "options" must be an array.`) } return caseErrors }, ) let allCaseErrors = await Promise.all(caseValidationPromises) testSpecErrors.push(...allCaseErrors.flat()) } return testSpecErrors }) let allTestErrors = await Promise.all(validationPromises) errors.push(...allTestErrors.flat()) return errors } function validateBaseBenchmarkSettings(settings = {}) { let errors = [] if ( settings.iterations !== void 0 && (typeof settings.iterations !== 'number' || settings.iterations <= 0) ) { errors.push(`"iterations" must be a positive number`) } if ( settings.timeout !== void 0 && (typeof settings.timeout !== 'number' || settings.timeout <= 0) ) { errors.push(`"timeout" must be a positive number`) } if (settings.warmup !== void 0) { if (typeof settings.warmup === 'object') { if ( settings.warmup.iterations !== void 0 && (typeof settings.warmup.iterations !== 'number' || settings.warmup.iterations < 0) ) { errors.push(`"warmup.iterations" must be a non-negative number`) } if ( settings.warmup.enabled !== void 0 && typeof settings.warmup.enabled !== 'boolean' ) { errors.push(`"warmup.enabled" must be a boolean`) } } else { errors.push(`"warmup" must be an object`) } } return errors } export { validateConfig }