diff --git a/src/utils/init-script-schema.ts b/src/utils/init-script-schema.ts index 66e0b0a..434bc6f 100644 --- a/src/utils/init-script-schema.ts +++ b/src/utils/init-script-schema.ts @@ -11,13 +11,23 @@ export const InitScriptSchemaVersions = z.object({ solana: z.string().optional(), }) -export const InitScriptSchemaRename = z.record( - z.object({ - // TODO: Rename 'paths' to 'in' (breaking change) - paths: z.array(z.string()), - to: z.string(), - }), -) +const InitScriptSchemaRenameEntryBase = z.object({ + // Accept alias `in` for backward/forward compatibility and normalize to `paths` + in: z.array(z.string()).optional(), + paths: z.array(z.string()).optional(), + to: z.string(), +}) + +export const InitScriptSchemaRename = z.record(InitScriptSchemaRenameEntryBase).transform((input) => { + // Normalize entries: if `in` is provided, move to `paths` + const normalized: Record = {} + for (const key of Object.keys(input)) { + const entry = input[key] as { in?: string[]; paths?: string[]; to: string } + const paths = entry.paths ?? entry.in ?? [] + normalized[key] = { paths, to: entry.to } + } + return normalized +}) export const InitScriptSchema = z.object({ instructions: InitScriptSchemaInstructions.optional(), diff --git a/test/init-script-schema.test.ts b/test/init-script-schema.test.ts new file mode 100644 index 0000000..a2a35b1 --- /dev/null +++ b/test/init-script-schema.test.ts @@ -0,0 +1,46 @@ +import { describe, expect, it } from 'vitest' +import { InitScriptSchema } from '../src/utils/init-script-schema' + +describe('InitScriptSchema - rename alias', () => { + const parseRename = (rename: unknown) => InitScriptSchema.parse({ rename }).rename + + it('should accept `in` alias and normalize to `paths`', () => { + const parsed = parseRename({ example: { in: ['some/path/to/file'], to: '{{name}}Example' } } as unknown) + + // @ts-expect-error normalized by schema transform + expect(parsed.example.in).toBeUndefined() + expect(parsed?.example.paths).toEqual(['some/path/to/file']) + expect(parsed?.example.to).toBe('{{name}}Example') + }) + + it('should accept `paths` field without changes', () => { + const parsed = parseRename({ example: { paths: ['some/path/to/file'], to: '{{name}}Example' } }) + + expect(parsed?.example.paths).toEqual(['some/path/to/file']) + expect(parsed?.example.to).toBe('{{name}}Example') + }) + + it('should prioritize `paths` over `in` when both provided', () => { + const entry = { in: ['path/from/in'], paths: ['path/from/paths'], to: '{{name}}Example' } as unknown + const parsed = parseRename({ example: entry }) + + expect(parsed?.example.paths).toEqual(['path/from/paths']) + }) + + it('should handle empty arrays', () => { + const parsed = parseRename({ example: { in: [], to: '{{name}}Example' } } as unknown) + + expect(parsed?.example.paths).toEqual([]) + }) + + it('should handle mixed `in` and `paths` usage', () => { + const rename = { + example1: { in: ['some/path/to/file1'], to: '{{name}}Example1' }, + example2: { paths: ['some/path/to/file2'], to: '{{name}}Example2' }, + } as unknown + const parsed = parseRename(rename) + + expect(parsed?.example1.paths).toEqual(['some/path/to/file1']) + expect(parsed?.example2.paths).toEqual(['some/path/to/file2']) + }) +}) diff --git a/test/search-and-replace.test.ts b/test/search-and-replace.test.ts index bbf34e9..de4a663 100644 --- a/test/search-and-replace.test.ts +++ b/test/search-and-replace.test.ts @@ -98,7 +98,7 @@ describe('searchAndReplace', () => { }) it('should handle errors gracefully', async () => { - const consoleErrorSpy = vi.spyOn(console, 'error') + const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) // Mock the file system and simulate an error for readFile mockFs({