diff --git a/src/commands/templates.ts b/src/commands/templates.ts index 45620db..a8cec53 100644 --- a/src/commands/templates.ts +++ b/src/commands/templates.ts @@ -1,6 +1,11 @@ import { Command } from 'commander'; import { getStorage } from '../data/storage.js'; -import { Template, slugify, type TemplateExercise } from '../types.js'; +import { + Template, + slugify, + type Template as TemplateType, + type TemplateExercise, +} from '../types.js'; function parseExerciseSpec(spec: string): TemplateExercise { const match = spec.match(/^([^:]+):(\d+)x(.+)$/); @@ -124,6 +129,73 @@ export function createTemplatesCommand(getProfile: () => string | undefined): Co } ); + templates + .command('edit ') + .description('Edit an existing template') + .option('-n, --name ', 'New template name') + .option( + '-e, --exercises ', + 'Replace exercise specs (e.g., "bench-press:3x8-12, squat:4x5")' + ) + .option('-d, --description ', 'New template description') + .action( + ( + id: string, + options: { + name?: string; + exercises?: string; + description?: string; + } + ) => { + const storage = getStorage(getProfile()); + const existing = storage.getTemplate(id); + + if (!existing) { + console.error(`Template "${id}" not found.`); + process.exit(1); + } + + const updates: Partial = {}; + + if (options.name) { + updates.name = options.name; + } + + if (options.description) { + updates.description = options.description; + } + + if (options.exercises) { + const exerciseSpecs = options.exercises.split(',').map((s) => s.trim()); + const exercises: TemplateExercise[] = []; + + for (const spec of exerciseSpecs) { + try { + exercises.push(parseExerciseSpec(spec)); + } catch (err) { + console.error((err as Error).message); + process.exit(1); + } + } + + updates.exercises = exercises; + } + + if (Object.keys(updates).length === 0) { + console.error('No changes specified. Use --name, --exercises, or --description.'); + process.exit(1); + } + + try { + storage.updateTemplate(id, updates); + console.log(`Updated template: ${id}`); + } catch (err) { + console.error((err as Error).message); + process.exit(1); + } + } + ); + templates .command('delete ') .description('Delete a template') diff --git a/src/data/storage.ts b/src/data/storage.ts index c339173..b2c923a 100644 --- a/src/data/storage.ts +++ b/src/data/storage.ts @@ -159,6 +159,16 @@ export class Storage { this.saveTemplates(templates); } + updateTemplate(id: string, updates: Partial): void { + const templates = this.getTemplates(); + const index = templates.findIndex((t) => t.id === id); + if (index === -1) { + throw new Error(`Template "${id}" not found`); + } + templates[index] = { ...templates[index]!, ...updates }; + this.saveTemplates(templates); + } + deleteTemplate(id: string): void { const templates = this.getTemplates(); const index = templates.findIndex((t) => t.id === id); diff --git a/test/commands.test.ts b/test/commands.test.ts index 6ae25f8..a79f7a6 100644 --- a/test/commands.test.ts +++ b/test/commands.test.ts @@ -507,6 +507,47 @@ describe('template management', () => { expect(templates.map((t) => t.id).sort()).toEqual(['legs', 'pull', 'push']); }); + it('updates template name and description', () => { + storage.addTemplate({ + id: 'push-a', + name: 'Push A', + exercises: [{ exercise: 'bench-press', sets: 3, reps: '8-12' }], + }); + + storage.updateTemplate('push-a', { name: 'Push Day A', description: 'Updated push workout' }); + + const updated = storage.getTemplate('push-a')!; + expect(updated.name).toBe('Push Day A'); + expect(updated.description).toBe('Updated push workout'); + expect(updated.exercises).toHaveLength(1); + }); + + it('updates template exercises', () => { + storage.addTemplate({ + id: 'pull-b', + name: 'Pull B', + exercises: [{ exercise: 'deadlift', sets: 3, reps: '5' }], + }); + + storage.updateTemplate('pull-b', { + exercises: [ + { exercise: 'barbell-row', sets: 4, reps: '8-12' }, + { exercise: 'lat-pulldown', sets: 3, reps: '10-15' }, + ], + }); + + const updated = storage.getTemplate('pull-b')!; + expect(updated.name).toBe('Pull B'); + expect(updated.exercises).toHaveLength(2); + expect(updated.exercises[0]?.exercise).toBe('barbell-row'); + }); + + it('throws when updating non-existent template', () => { + expect(() => storage.updateTemplate('nonexistent', { name: 'Nope' })).toThrow( + 'Template "nonexistent" not found' + ); + }); + it('deletes template', () => { storage.addTemplate({ id: 'to-delete', name: 'Delete Me', exercises: [] }); expect(storage.getTemplate('to-delete')).toBeDefined();