Skip to content

Commit d3231b5

Browse files
authored
fix: keyword replacement handling for special characters (#1174)
* feat: improve keyword replacement handling for special characters - src/tools/utils.ts: use function-based replacement to handle $ sequences in keywordArrayReplace and keywordStringReplace - test/tools/utils.test.js: add tests for handling dollar-apostrophe in replacement values for keywordStringReplace and keywordArrayReplace * rename test-case
1 parent 2a4d28f commit d3231b5

File tree

2 files changed

+23
-2
lines changed

2 files changed

+23
-2
lines changed

src/tools/utils.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,18 @@ export function keywordArrayReplace(input: string, mappings: KeywordMappings): s
2424
// Matching against two sets of patterns because a developer may provide their array replacement keyword with or without wrapping quotes. It is not obvious to the developer which to do depending if they're operating in YAML or JSON.
2525
const regex = keywordReplaceArrayRegExp(key);
2626

27-
input = input.replace(regex, JSON.stringify(mappings[key]));
27+
// Use function-based replacement to prevent $ sequences (e.g., $', $`, $&) from being interpreted as special replacement patterns to fixes issue #1153.
28+
input = input.replace(regex, () => JSON.stringify(mappings[key]));
2829
});
2930
return input;
3031
}
3132

3233
export function keywordStringReplace(input: string, mappings: KeywordMappings): string {
3334
Object.keys(mappings).forEach(function (key) {
3435
const regex = keywordReplaceStringRegExp(key);
36+
// Use function-based replacement to prevent $ sequences (e.g., $', $`, $&) from being interpreted as special replacement patterns to fixes issue #1153.
3537
// @ts-ignore TODO: come back and distinguish strings vs array replacement.
36-
input = input.replace(regex, mappings[key]);
38+
input = input.replace(regex, () => mappings[key]);
3739
});
3840
return input;
3941
}

test/tools/utils.test.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,15 @@ describe('#keywordReplacement', () => {
381381
`{ "foo": ${mapping.STRING_REPLACEMENT}, "bar": "OTHER_REPLACEMENT" }`
382382
);
383383
});
384+
385+
// Issue #1153: Test cases for $ character handling
386+
it('should handle dollar-apostrophe in replacement value', () => {
387+
const input = '{ "secret": "##PASSWORD##" }';
388+
const passwordMapping = { PASSWORD: "'mySecret$'" };
389+
const output = utils.keywordStringReplace(input, passwordMapping);
390+
expect(output).to.equal('{ "secret": "\'mySecret$\'" }');
391+
expect(() => JSON.parse(output)).to.not.throw();
392+
});
384393
});
385394

386395
describe('#keywordArrayReplace', () => {
@@ -429,6 +438,16 @@ describe('#keywordReplacement', () => {
429438
doubleQuotes: mapping.ARRAY_REPLACEMENT,
430439
});
431440
});
441+
442+
// Issue #1153: Test cases for $ character handling in arrays
443+
it('should handle dollar-apostrophe in array values', () => {
444+
const input = '{ "keys": @@KEYS@@ }';
445+
const arrayMapping = { KEYS: ["api-key$'", "secret$'"] };
446+
const output = utils.keywordArrayReplace(input, arrayMapping);
447+
expect(() => JSON.parse(output)).to.not.throw();
448+
const parsed = JSON.parse(output);
449+
expect(parsed.keys).to.deep.equal(arrayMapping.KEYS);
450+
});
432451
});
433452
});
434453

0 commit comments

Comments
 (0)