-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Auto-add file extension when missing #954
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -12,6 +12,7 @@ import { | |||||||||||||||||||||||||
| type RepomixConfigCli, | ||||||||||||||||||||||||||
| type RepomixConfigFile, | ||||||||||||||||||||||||||
| type RepomixConfigMerged, | ||||||||||||||||||||||||||
| type RepomixOutputStyle, | ||||||||||||||||||||||||||
| repomixConfigFileSchema, | ||||||||||||||||||||||||||
| repomixConfigMergedSchema, | ||||||||||||||||||||||||||
| } from './configSchema.js'; | ||||||||||||||||||||||||||
|
|
@@ -167,6 +168,14 @@ const loadAndValidateConfig = async ( | |||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Mapping of output styles to their file extensions | ||||||||||||||||||||||||||
| const styleToExtensionMap: Record<RepomixOutputStyle, string> = { | ||||||||||||||||||||||||||
| xml: '.xml', | ||||||||||||||||||||||||||
| markdown: '.md', | ||||||||||||||||||||||||||
| plain: '.txt', | ||||||||||||||||||||||||||
| json: '.json', | ||||||||||||||||||||||||||
| } as const; | ||||||||||||||||||||||||||
|
Comment on lines
+172
to
+177
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While the current implementation is correct, the type assertion
Suggested change
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| export const mergeConfigs = ( | ||||||||||||||||||||||||||
| cwd: string, | ||||||||||||||||||||||||||
| fileConfig: RepomixConfigFile, | ||||||||||||||||||||||||||
|
|
@@ -205,6 +214,15 @@ export const mergeConfigs = ( | |||||||||||||||||||||||||
| mergedOutput.filePath = desiredPath; | ||||||||||||||||||||||||||
| logger.trace('Adjusted output file path to match style:', mergedOutput.filePath); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||
| // If filePath is explicitly set, check if it has an extension | ||||||||||||||||||||||||||
| const currentExtension = path.extname(mergedOutput.filePath); | ||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential Issue: Edge Case with Dotfiles The current logic uses Example: // Current behavior:
path.extname('.myoutput') // returns ''
// Result: '.myoutput.xml'
// Expected behavior: probably preserve '.myoutput' as-is?Suggested fix: const currentExtension = path.extname(mergedOutput.filePath);
const basename = path.basename(mergedOutput.filePath);
const isDotfile = basename.startsWith('.') && !basename.includes('.', 1);
if (!currentExtension && !isDotfile) {
const extensionToAdd = styleToExtensionMap[style];
mergedOutput.filePath = `${mergedOutput.filePath}${extensionToAdd}`;
logger.trace('Added file extension to output path:', mergedOutput.filePath);
}This ensures dotfiles are preserved unchanged. |
||||||||||||||||||||||||||
| if (!currentExtension) { | ||||||||||||||||||||||||||
| // No extension found, add the appropriate extension based on style | ||||||||||||||||||||||||||
| const extensionToAdd = styleToExtensionMap[style]; | ||||||||||||||||||||||||||
| mergedOutput.filePath = `${mergedOutput.filePath}${extensionToAdd}`; | ||||||||||||||||||||||||||
| logger.trace('Added file extension to output path:', mergedOutput.filePath); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
Comment on lines
+219
to
+225
|
||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return mergedOutput; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -329,5 +329,65 @@ describe('configLoad', () => { | |
| expect(merged.output.filePath).toBe('repomix-output.txt'); | ||
| expect(merged.output.style).toBe('plain'); | ||
| }); | ||
|
|
||
| test('should add extension when CLI filePath has no extension (default style)', () => { | ||
| const merged = mergeConfigs(process.cwd(), {}, { output: { filePath: 'myoutput' } }); | ||
| expect(merged.output.filePath).toBe('myoutput.xml'); | ||
| expect(merged.output.style).toBe('xml'); | ||
| }); | ||
|
|
||
| test('should add extension when CLI filePath has no extension (markdown style)', () => { | ||
| const merged = mergeConfigs(process.cwd(), {}, { output: { filePath: 'myoutput', style: 'markdown' } }); | ||
| expect(merged.output.filePath).toBe('myoutput.md'); | ||
| expect(merged.output.style).toBe('markdown'); | ||
| }); | ||
|
|
||
| test('should add extension when CLI filePath has no extension (plain style)', () => { | ||
| const merged = mergeConfigs(process.cwd(), {}, { output: { filePath: 'myoutput', style: 'plain' } }); | ||
| expect(merged.output.filePath).toBe('myoutput.txt'); | ||
| expect(merged.output.style).toBe('plain'); | ||
| }); | ||
|
|
||
| test('should add extension when CLI filePath has no extension (json style)', () => { | ||
| const merged = mergeConfigs(process.cwd(), {}, { output: { filePath: 'myoutput', style: 'json' } }); | ||
| expect(merged.output.filePath).toBe('myoutput.json'); | ||
| expect(merged.output.style).toBe('json'); | ||
| }); | ||
|
Comment on lines
+333
to
+355
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These tests are great for ensuring correctness! To improve maintainability and reduce code duplication, you could parameterize these related test cases using test.each([
{ description: 'default style', config: { output: { filePath: 'myoutput' } }, expectedStyle: 'xml', expectedExt: '.xml' },
{ description: 'markdown style', config: { output: { filePath: 'myoutput', style: 'markdown' } }, expectedStyle: 'markdown', expectedExt: '.md' },
{ description: 'plain style', config: { output: { filePath: 'myoutput', style: 'plain' } }, expectedStyle: 'plain', expectedExt: '.txt' },
{ description: 'json style', config: { output: { filePath: 'myoutput', style: 'json' } }, expectedStyle: 'json', expectedExt: '.json' },
])('should add extension when CLI filePath has no extension ($description)', ({ config, expectedStyle, expectedExt }) => {
const merged = mergeConfigs(process.cwd(), {}, config);
expect(merged.output.filePath).toBe(`myoutput${expectedExt}`);
expect(merged.output.style).toBe(expectedStyle);
}); |
||
|
|
||
| test('should keep extension when CLI filePath already has extension', () => { | ||
| const merged = mergeConfigs(process.cwd(), {}, { output: { filePath: 'myoutput.txt', style: 'markdown' } }); | ||
| expect(merged.output.filePath).toBe('myoutput.txt'); | ||
| expect(merged.output.style).toBe('markdown'); | ||
| }); | ||
|
|
||
| test('should add extension when file config filePath has no extension', () => { | ||
| const merged = mergeConfigs(process.cwd(), { output: { filePath: 'myoutput', style: 'markdown' } }, {}); | ||
| expect(merged.output.filePath).toBe('myoutput.md'); | ||
| expect(merged.output.style).toBe('markdown'); | ||
| }); | ||
|
|
||
| test('should keep extension when file config filePath already has extension', () => { | ||
| const merged = mergeConfigs(process.cwd(), { output: { filePath: 'myoutput.custom', style: 'markdown' } }, {}); | ||
| expect(merged.output.filePath).toBe('myoutput.custom'); | ||
| expect(merged.output.style).toBe('markdown'); | ||
| }); | ||
|
|
||
| test('should add extension for paths with directories when no extension', () => { | ||
| const merged = mergeConfigs(process.cwd(), {}, { output: { filePath: 'output/myfile', style: 'json' } }); | ||
| expect(merged.output.filePath).toBe('output/myfile.json'); | ||
| expect(merged.output.style).toBe('json'); | ||
| }); | ||
|
|
||
| test('should keep extension for paths with directories when extension exists', () => { | ||
| const merged = mergeConfigs(process.cwd(), {}, { output: { filePath: 'output/myfile.txt', style: 'json' } }); | ||
| expect(merged.output.filePath).toBe('output/myfile.txt'); | ||
| expect(merged.output.style).toBe('json'); | ||
| }); | ||
|
|
||
| test('should add extension when style is changed via CLI but filePath has no extension', () => { | ||
| const merged = mergeConfigs(process.cwd(), { output: { filePath: 'myfile' } }, { output: { style: 'markdown' } }); | ||
| expect(merged.output.filePath).toBe('myfile.md'); | ||
| expect(merged.output.style).toBe('markdown'); | ||
| }); | ||
| }); | ||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Quality: Consider Making Map More Maintainable
The
styleToExtensionMapduplicates information fromdefaultFilePathMap. Consider deriving one from the other to maintain a single source of truth.Suggested approach:
This ensures consistency and reduces maintenance burden when adding new output styles.