From 93dc5a15546b1b9b3c27c7a227c47298042d12e6 Mon Sep 17 00:00:00 2001 From: gnanam1990 Date: Wed, 8 Apr 2026 14:19:28 +0530 Subject: [PATCH] feat: add AutoFix config schema and reader module Implements AutoFixConfigSchema (Zod v4) with validation for lint/test commands, maxRetries (0-10, default 3), and timeout (1000-300000ms, default 30000). Adds getAutoFixConfig helper that returns null for disabled or invalid configs. All 9 unit tests pass. Co-Authored-By: Claude Sonnet 4.6 --- src/services/autoFix/autoFixConfig.test.ts | 77 ++++++++++++++++++++++ src/services/autoFix/autoFixConfig.ts | 52 +++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 src/services/autoFix/autoFixConfig.test.ts create mode 100644 src/services/autoFix/autoFixConfig.ts diff --git a/src/services/autoFix/autoFixConfig.test.ts b/src/services/autoFix/autoFixConfig.test.ts new file mode 100644 index 00000000..dd700048 --- /dev/null +++ b/src/services/autoFix/autoFixConfig.test.ts @@ -0,0 +1,77 @@ +import { describe, expect, test } from 'bun:test' +import { AutoFixConfigSchema, getAutoFixConfig, type AutoFixConfig } from './autoFixConfig.js' + +describe('AutoFixConfigSchema', () => { + test('parses valid full config', () => { + const input = { + enabled: true, + lint: 'eslint . --fix', + test: 'bun test', + maxRetries: 3, + timeout: 30000, + } + const result = AutoFixConfigSchema.safeParse(input) + expect(result.success).toBe(true) + if (result.success) { + expect(result.data.enabled).toBe(true) + expect(result.data.lint).toBe('eslint . --fix') + expect(result.data.test).toBe('bun test') + expect(result.data.maxRetries).toBe(3) + expect(result.data.timeout).toBe(30000) + } + }) + + test('parses minimal config with defaults', () => { + const input = { enabled: true, lint: 'eslint .' } + const result = AutoFixConfigSchema.safeParse(input) + expect(result.success).toBe(true) + if (result.success) { + expect(result.data.maxRetries).toBe(3) + expect(result.data.timeout).toBe(30000) + expect(result.data.test).toBeUndefined() + } + }) + + test('rejects config with enabled but no lint or test', () => { + const input = { enabled: true } + const result = AutoFixConfigSchema.safeParse(input) + expect(result.success).toBe(false) + }) + + test('accepts disabled config without commands', () => { + const input = { enabled: false } + const result = AutoFixConfigSchema.safeParse(input) + expect(result.success).toBe(true) + }) + + test('rejects negative maxRetries', () => { + const input = { enabled: true, lint: 'eslint .', maxRetries: -1 } + const result = AutoFixConfigSchema.safeParse(input) + expect(result.success).toBe(false) + }) + + test('rejects maxRetries above 10', () => { + const input = { enabled: true, lint: 'eslint .', maxRetries: 11 } + const result = AutoFixConfigSchema.safeParse(input) + expect(result.success).toBe(false) + }) +}) + +describe('getAutoFixConfig', () => { + test('returns null when settings have no autoFix', () => { + const result = getAutoFixConfig(undefined) + expect(result).toBeNull() + }) + + test('returns null when autoFix is disabled', () => { + const result = getAutoFixConfig({ enabled: false }) + expect(result).toBeNull() + }) + + test('returns parsed config when valid and enabled', () => { + const result = getAutoFixConfig({ enabled: true, lint: 'eslint .' }) + expect(result).not.toBeNull() + expect(result!.enabled).toBe(true) + expect(result!.lint).toBe('eslint .') + }) +}) diff --git a/src/services/autoFix/autoFixConfig.ts b/src/services/autoFix/autoFixConfig.ts new file mode 100644 index 00000000..c5b83416 --- /dev/null +++ b/src/services/autoFix/autoFixConfig.ts @@ -0,0 +1,52 @@ +import { z } from 'zod/v4' + +export const AutoFixConfigSchema = z + .object({ + enabled: z.boolean().describe('Whether auto-fix is enabled'), + lint: z + .string() + .optional() + .describe('Lint command to run after file edits (e.g. "eslint . --fix")'), + test: z + .string() + .optional() + .describe('Test command to run after file edits (e.g. "bun test")'), + maxRetries: z + .number() + .int() + .min(0) + .max(10) + .default(3) + .describe('Maximum number of auto-fix retry attempts (default: 3)'), + timeout: z + .number() + .int() + .min(1000) + .max(300000) + .default(30000) + .describe('Timeout in ms for each lint/test command (default: 30000)'), + }) + .refine( + data => !data.enabled || data.lint !== undefined || data.test !== undefined, + { + message: 'At least one of "lint" or "test" must be set when enabled', + }, + ) + +export type AutoFixConfig = z.infer + +export function getAutoFixConfig( + rawConfig: unknown, +): AutoFixConfig | null { + if (!rawConfig || typeof rawConfig !== 'object') { + return null + } + const parsed = AutoFixConfigSchema.safeParse(rawConfig) + if (!parsed.success) { + return null + } + if (!parsed.data.enabled) { + return null + } + return parsed.data +}