From 1b45b08c61857dfcc5824ae0356d7ce98082f378 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 17:54:11 +0000 Subject: [PATCH 1/4] Initial plan From 948217323da0b8234ac7035458d14795823b6de0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 17:59:51 +0000 Subject: [PATCH 2/4] test(cli): cover explicit config-path and loader error handling Co-authored-by: night-slayer18 <83979018+night-slayer18@users.noreply.github.com> Agent-Logs-Url: https://github.com/OpenSyntaxHQ/autodocs/sessions/f018fbba-31c9-4748-8396-6f1f1c90265c --- packages/cli/tests/config-loader.test.ts | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/packages/cli/tests/config-loader.test.ts b/packages/cli/tests/config-loader.test.ts index b31be18..f715970 100644 --- a/packages/cli/tests/config-loader.test.ts +++ b/packages/cli/tests/config-loader.test.ts @@ -31,6 +31,38 @@ describe('config loader', () => { expect(config?.output.dir).toBe('./docs'); }); + it('loads JSON config from an explicit config path', async () => { + const tempDir = await createTempDir(); + const configPath = path.join(tempDir, 'autodocs.config.json'); + await fs.writeFile( + configPath, + JSON.stringify({ include: ['lib/**/*.ts'], output: { dir: './explicit', format: 'json' } }), + 'utf-8' + ); + + const config = await loadConfig(configPath); + expect(config).not.toBeNull(); + expect(config?.include).toContain('lib/**/*.ts'); + expect(config?.output.dir).toBe('./explicit'); + expect(config?.output.format).toBe('json'); + }); + + it('wraps loader errors with a clear message', async () => { + await jest.isolateModulesAsync(async () => { + jest.doMock('cosmiconfig', () => ({ + cosmiconfig: () => ({ + search: jest.fn().mockRejectedValue(new Error('broken loader')), + load: jest.fn(), + }), + })); + + const { loadConfig: isolatedLoadConfig } = await import('../src/config/loader'); + await expect(isolatedLoadConfig('/tmp')).rejects.toThrow( + 'Failed to load config: broken loader' + ); + }); + }); + it('resolves relative paths', async () => { const tempDir = await createTempDir(); const config = resolveConfigPaths( From a2ce4eda24d6f59670dab939f3e61311947d69e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 18:02:39 +0000 Subject: [PATCH 3/4] test(cli): increase config loader branch coverage for codecov patch Co-authored-by: night-slayer18 <83979018+night-slayer18@users.noreply.github.com> Agent-Logs-Url: https://github.com/OpenSyntaxHQ/autodocs/sessions/f018fbba-31c9-4748-8396-6f1f1c90265c --- packages/cli/tests/config-loader.test.ts | 71 ++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/packages/cli/tests/config-loader.test.ts b/packages/cli/tests/config-loader.test.ts index f715970..94ac5be 100644 --- a/packages/cli/tests/config-loader.test.ts +++ b/packages/cli/tests/config-loader.test.ts @@ -31,6 +31,21 @@ describe('config loader', () => { expect(config?.output.dir).toBe('./docs'); }); + it('loads TypeScript config files', async () => { + const tempDir = await createTempDir(); + const configPath = path.join(tempDir, 'autodocs.config.ts'); + await fs.writeFile( + configPath, + `export default { include: ['src/**/*.ts'], output: { dir: './typed', format: 'json' } };`, + 'utf-8' + ); + + const config = await loadConfig(tempDir); + expect(config).not.toBeNull(); + expect(config?.output.dir).toBe('./typed'); + expect(config?.output.format).toBe('json'); + }); + it('loads JSON config from an explicit config path', async () => { const tempDir = await createTempDir(); const configPath = path.join(tempDir, 'autodocs.config.json'); @@ -47,6 +62,62 @@ describe('config loader', () => { expect(config?.output.format).toBe('json'); }); + it('returns null when no config file exists', async () => { + const tempDir = await createTempDir(); + const config = await loadConfig(tempDir); + expect(config).toBeNull(); + }); + + it('falls back to manual JSON parsing when explicit load returns empty', async () => { + const tempDir = await createTempDir(); + const configPath = path.join(tempDir, 'autodocs.config.json'); + await fs.writeFile( + configPath, + JSON.stringify({ output: { dir: './fallback-json', format: 'json' } }), + 'utf-8' + ); + + await jest.isolateModulesAsync(async () => { + jest.doMock('cosmiconfig', () => ({ + cosmiconfig: () => ({ + search: jest.fn(), + load: jest.fn().mockResolvedValue(null), + }), + })); + + const { loadConfig: isolatedLoadConfig } = await import('../src/config/loader'); + const config = await isolatedLoadConfig(configPath); + expect(config).not.toBeNull(); + expect(config?.output.dir).toBe('./fallback-json'); + expect(config?.output.format).toBe('json'); + }); + }); + + it('falls back to jiti for explicit JS config when explorer returns empty', async () => { + const tempDir = await createTempDir(); + const configPath = path.join(tempDir, 'autodocs.config.js'); + await fs.writeFile( + configPath, + `module.exports = { output: { dir: './fallback-js', format: 'json' } };`, + 'utf-8' + ); + + await jest.isolateModulesAsync(async () => { + jest.doMock('cosmiconfig', () => ({ + cosmiconfig: () => ({ + search: jest.fn(), + load: jest.fn().mockResolvedValue(null), + }), + })); + + const { loadConfig: isolatedLoadConfig } = await import('../src/config/loader'); + const config = await isolatedLoadConfig(configPath); + expect(config).not.toBeNull(); + expect(config?.output.dir).toBe('./fallback-js'); + expect(config?.output.format).toBe('json'); + }); + }); + it('wraps loader errors with a clear message', async () => { await jest.isolateModulesAsync(async () => { jest.doMock('cosmiconfig', () => ({ From f2cc198a90e69c38361c648526a6c2e0ebdedb2d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 18:05:00 +0000 Subject: [PATCH 4/4] test(cli): refine config loader fallback test coverage Co-authored-by: night-slayer18 <83979018+night-slayer18@users.noreply.github.com> Agent-Logs-Url: https://github.com/OpenSyntaxHQ/autodocs/sessions/f018fbba-31c9-4748-8396-6f1f1c90265c --- packages/cli/tests/config-loader.test.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/cli/tests/config-loader.test.ts b/packages/cli/tests/config-loader.test.ts index 94ac5be..5934e12 100644 --- a/packages/cli/tests/config-loader.test.ts +++ b/packages/cli/tests/config-loader.test.ts @@ -68,7 +68,7 @@ describe('config loader', () => { expect(config).toBeNull(); }); - it('falls back to manual JSON parsing when explicit load returns empty', async () => { + it('falls back to manual JSON parsing when cosmiconfig returns null for explicit path', async () => { const tempDir = await createTempDir(); const configPath = path.join(tempDir, 'autodocs.config.json'); await fs.writeFile( @@ -93,7 +93,7 @@ describe('config loader', () => { }); }); - it('falls back to jiti for explicit JS config when explorer returns empty', async () => { + it('falls back to jiti for explicit JS config when cosmiconfig returns null for explicit path', async () => { const tempDir = await createTempDir(); const configPath = path.join(tempDir, 'autodocs.config.js'); await fs.writeFile( @@ -119,6 +119,8 @@ describe('config loader', () => { }); it('wraps loader errors with a clear message', async () => { + const tempDir = await createTempDir(); + await jest.isolateModulesAsync(async () => { jest.doMock('cosmiconfig', () => ({ cosmiconfig: () => ({ @@ -128,7 +130,7 @@ describe('config loader', () => { })); const { loadConfig: isolatedLoadConfig } = await import('../src/config/loader'); - await expect(isolatedLoadConfig('/tmp')).rejects.toThrow( + await expect(isolatedLoadConfig(tempDir)).rejects.toThrow( 'Failed to load config: broken loader' ); });