(root: ResolvedOpenSpecRoot, scope: { changes: boolean; specs: boolean }, opts: { strict: boolean; json: boolean; concurrency?: string; noInteractive?: boolean })
| 233 | } |
| 234 | |
| 235 | private async runBulkValidation(root: ResolvedOpenSpecRoot, scope: { changes: boolean; specs: boolean }, opts: { strict: boolean; json: boolean; concurrency?: string; noInteractive?: boolean }): Promise<void> { |
| 236 | const spinner = !opts.json && !opts.noInteractive ? ora('Validating...').start() : undefined; |
| 237 | const [changeIds, specIds] = await Promise.all([ |
| 238 | scope.changes ? getActiveChangeIds(root.path) : Promise.resolve<string[]>([]), |
| 239 | scope.specs ? getSpecIds(root.path) : Promise.resolve<string[]>([]), |
| 240 | ]); |
| 241 | |
| 242 | const DEFAULT_CONCURRENCY = 6; |
| 243 | const maxSuggestions = 5; // used by nearestMatches |
| 244 | const concurrency = normalizeConcurrency(opts.concurrency) ?? normalizeConcurrency(process.env.OPENSPEC_CONCURRENCY) ?? DEFAULT_CONCURRENCY; |
| 245 | const validator = new Validator(opts.strict); |
| 246 | const queue: Array<() => Promise<BulkItemResult>> = []; |
| 247 | |
| 248 | for (const id of changeIds) { |
| 249 | queue.push(async () => { |
| 250 | const start = Date.now(); |
| 251 | const changeDir = path.join(root.changesDir, id); |
| 252 | const report = await validator.validateChangeDeltaSpecs(changeDir); |
| 253 | const durationMs = Date.now() - start; |
| 254 | return { id, type: 'change' as const, valid: report.valid, issues: report.issues, durationMs }; |
| 255 | }); |
| 256 | } |
| 257 | for (const id of specIds) { |
| 258 | queue.push(async () => { |
| 259 | const start = Date.now(); |
| 260 | const file = path.join(root.specsDir, id, 'spec.md'); |
| 261 | const report = await validator.validateSpec(file); |
| 262 | const durationMs = Date.now() - start; |
| 263 | return { id, type: 'spec' as const, valid: report.valid, issues: report.issues, durationMs }; |
| 264 | }); |
| 265 | } |
| 266 | |
| 267 | if (queue.length === 0) { |
| 268 | spinner?.stop(); |
| 269 | |
| 270 | const summary = { |
| 271 | totals: { items: 0, passed: 0, failed: 0 }, |
| 272 | byType: { |
| 273 | ...(scope.changes ? { change: { items: 0, passed: 0, failed: 0 } } : {}), |
| 274 | ...(scope.specs ? { spec: { items: 0, passed: 0, failed: 0 } } : {}), |
| 275 | }, |
| 276 | } as const; |
| 277 | |
| 278 | if (opts.json) { |
| 279 | const out = { items: [] as BulkItemResult[], summary, version: '1.0', root: toRootOutput(root) }; |
| 280 | console.log(JSON.stringify(out, null, 2)); |
| 281 | } else { |
| 282 | console.log('No items found to validate.'); |
| 283 | } |
| 284 | |
| 285 | process.exitCode = 0; |
| 286 | return; |
| 287 | } |
| 288 | |
| 289 | const results: BulkItemResult[] = []; |
| 290 | let index = 0; |
| 291 | let running = 0; |
| 292 | let passed = 0; |
no test coverage detected