MCPcopy
hub / github.com/Fission-AI/OpenSpec / runBulkValidation

Method runBulkValidation

src/commands/validate.ts:235–353  ·  view source on GitHub ↗
(root: ResolvedOpenSpecRoot, scope: { changes: boolean; specs: boolean }, opts: { strict: boolean; json: boolean; concurrency?: string; noInteractive?: boolean })

Source from the content-addressed store, hash-verified

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;

Callers 2

executeMethod · 0.95

Calls 8

validateSpecMethod · 0.95
getActiveChangeIdsFunction · 0.85
getSpecIdsFunction · 0.85
normalizeConcurrencyFunction · 0.85
toRootOutputFunction · 0.85
summarizeTypeFunction · 0.85
isStoreSelectedRootFunction · 0.85

Tested by

no test coverage detected