diff --git a/src/hooks/preparse.ts b/src/hooks/preparse.ts index 4fdadc01..b4459448 100644 --- a/src/hooks/preparse.ts +++ b/src/hooks/preparse.ts @@ -96,8 +96,24 @@ const hook: Hook.Preparse = async function ({ argv, options, context }) { } const crlf = contents.search('\r\n') !== -1; - const values = - ext === '.json' ? [JSON.stringify(JSON.parse(contents))] : contents?.trim().split(crlf ? '\r\n' : '\n'); + let values: string[]; + + if (ext === '.json') { + // JSON files: parse and re-stringify (existing behavior) + values = [JSON.stringify(JSON.parse(contents))]; + } else { + // Non-JSON files: split by lines and filter full-line comments + const lines = contents?.trim().split(crlf ? '\r\n' : '\n') || []; + values = lines.filter((line) => { + const trimmed = line.trim(); + // Filter out lines that are only whitespace + comment (full-line comments) + if (trimmed.startsWith('#') || trimmed.startsWith('//')) { + return false; + } + // Keep all other lines unchanged, including empty lines + return true; + }); + } return [name, values] satisfies [string, string[]]; }) diff --git a/test/hooks/preparse.test.ts b/test/hooks/preparse.test.ts index 78cc0ef0..07e619c9 100644 --- a/test/hooks/preparse.test.ts +++ b/test/hooks/preparse.test.ts @@ -326,4 +326,88 @@ describe('preparse hook test', () => { ]); }); }); + + describe('comment filtering', () => { + it('should filter full-line comments starting with #', async () => { + const argv = [...baseArgs]; + const flags = { + ...baseFlags, + str: Flags.string(), + }; + makeStubs([{ name: 'str', content: '# This is a comment\nactual-value\n# Another comment' }]); + const results = await config.runHook('preparse', { argv, options: { flags } }); + expect(results.successes[0]).to.be.ok; + expect(results.successes[0].result).to.deep.equal([...baseArgs, '--str', 'actual-value']); + }); + + it('should filter full-line comments starting with //', async () => { + const argv = [...baseArgs]; + const flags = { + ...baseFlags, + str: Flags.string(), + }; + makeStubs([{ name: 'str', content: '// This is a comment\nactual-value\n// Another comment' }]); + const results = await config.runHook('preparse', { argv, options: { flags } }); + expect(results.successes[0]).to.be.ok; + expect(results.successes[0].result).to.deep.equal([...baseArgs, '--str', 'actual-value']); + }); + + it('should filter comments with leading whitespace', async () => { + const argv = [...baseArgs]; + const flags = { + ...baseFlags, + str: Flags.string(), + }; + makeStubs([{ name: 'str', content: ' # Indented hash comment\nactual-value\n\t// Tab-indented slash comment' }]); + const results = await config.runHook('preparse', { argv, options: { flags } }); + expect(results.successes[0]).to.be.ok; + expect(results.successes[0].result).to.deep.equal([...baseArgs, '--str', 'actual-value']); + }); + + it('should preserve lines that contain comments but are not full-line comments', async () => { + const argv = [...baseArgs]; + const flags = { + ...baseFlags, + str: Flags.string(), + }; + makeStubs([{ name: 'str', content: 'value-with#hash\nvalue-with//slashes' }]); + const results = await config.runHook('preparse', { argv, options: { flags } }); + expect(results.successes[0]).to.be.ok; + expect(results.successes[0].result).to.deep.equal([ + ...baseArgs, + '--str', + 'value-with#hash', + '--str', + 'value-with//slashes', + ]); + }); + + it('should not filter comments in .json files', async () => { + const argv = [...baseArgs]; + const flags = { + ...baseFlags, + str: Flags.string(), + }; + const jsonContent = { + comment: '# This should not be filtered', + slashes: '// This should not be filtered either', + }; + makeStubs([{ name: 'str.json', content: JSON.stringify(jsonContent, null, 2) }]); + const results = await config.runHook('preparse', { argv, options: { flags } }); + expect(results.successes[0]).to.be.ok; + expect(results.successes[0].result).to.deep.equal([...baseArgs, '--str', JSON.stringify(jsonContent)]); + }); + + it('should preserve whitespace in non-comment lines', async () => { + const argv = [...baseArgs]; + const flags = { + ...baseFlags, + str: Flags.string(), + }; + makeStubs([{ name: 'str', content: '# Comment\n value with spaces \n// Another comment' }]); + const results = await config.runHook('preparse', { argv, options: { flags } }); + expect(results.successes[0]).to.be.ok; + expect(results.successes[0].result).to.deep.equal([...baseArgs, '--str', ' value with spaces ']); + }); + }); });