diff --git a/CHANGELOG.md b/CHANGELOG.md index 4187667113..e7394a7940 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ Our versioning strategy is as follows: * `[sitecore-jss-nextjs]` Fixed handling of ? inside square brackets [] in regex patterns to prevent incorrect escaping ([#1999](https://github.com/Sitecore/jss/pull/1999)) * `[sitecore-jss-nextjs]` Improve performance for redirect middleware ([#2003](https://github.com/Sitecore/jss/pull/2003)) * `[templates/nextjs]` `[templates/nextjs-sxa]` Fixed condition of DISABLE_FETCH_SSG ([#2007](https://github.com/Sitecore/jss/pull/2007)) +* `[sitecore-jss]` Fixed incorrect escaping of question marks in negative lookahead patterns in `escapeNonSpecialQuestionMarks` function ([#2014](https://github.com/Sitecore/jss/pull/2014)) + ### 🛠 Breaking Change diff --git a/packages/sitecore-jss/src/utils/utils.test.ts b/packages/sitecore-jss/src/utils/utils.test.ts index 5cd4b554a4..34fbe057b7 100644 --- a/packages/sitecore-jss/src/utils/utils.test.ts +++ b/packages/sitecore-jss/src/utils/utils.test.ts @@ -297,45 +297,57 @@ describe('utils', () => { }); describe('escapeNonSpecialQuestionMarks', () => { - it('should escape non-special "?" in plain strings', () => { - const input = 'What? is this? really?'; - const expected = 'What\\? is this\\? really\\?'; + it('should escape simple unescaped question marks', () => { + const input = 'abc?def?ghi'; + const expected = 'abc\\?def\\?ghi'; expect(escapeNonSpecialQuestionMarks(input)).to.equal(expected); }); - it('should not escape special regex "?" characters', () => { - const input = '(abc)? .*? [a-z]?'; - const expected = '(abc)? .*? [a-z]?'; + it('should not escape question marks in negative lookaheads', () => { + const input = 'abc(?!def)?ghi'; + const expected = 'abc(?!def)?ghi'; expect(escapeNonSpecialQuestionMarks(input)).to.equal(expected); }); - it('should handle mixed cases with special and non-special "?"', () => { - const input = 'Is this (true)? or false?'; - const expected = 'Is this (true)? or false\\?'; + it('should not escape question marks following special regex symbols', () => { + const input = 'abc.*?def+?ghi'; + const expected = 'abc.*?def+?ghi'; expect(escapeNonSpecialQuestionMarks(input)).to.equal(expected); }); - it('should escape "?" in a string with no special characters', () => { - const input = 'Just a plain string?'; - const expected = 'Just a plain string\\?'; + it('should escape mixed cases correctly', () => { + const input = 'abc?de(?!f)?g?hi.*?'; + const expected = 'abc\\?de(?!f)?g\\?hi.*?'; expect(escapeNonSpecialQuestionMarks(input)).to.equal(expected); }); - it('should handle strings with escaped "?" already', () => { - const input = 'This \\? should stay escaped?'; - const expected = 'This \\? should stay escaped\\?'; + it('should handle strings without question marks', () => { + const input = 'abcdefghi'; + const expected = 'abcdefghi'; expect(escapeNonSpecialQuestionMarks(input)).to.equal(expected); }); - it('should handle an empty string', () => { + it('should handle escaped question marks', () => { + const input = 'abc\\?def?ghi'; + const expected = 'abc\\?def\\?ghi'; + expect(escapeNonSpecialQuestionMarks(input)).to.equal(expected); + }); + + it('should handle empty strings', () => { const input = ''; const expected = ''; expect(escapeNonSpecialQuestionMarks(input)).to.equal(expected); }); - it('should handle strings without any "?"', () => { - const input = 'No question marks here.'; - const expected = 'No question marks here.'; + it('should handle consecutive unescaped question marks', () => { + const input = 'abc??def'; + const expected = 'abc\\?\\?def'; + expect(escapeNonSpecialQuestionMarks(input)).to.equal(expected); + }); + + it('should handle consecutive special symbols with question marks', () => { + const input = 'abc.*??ghi'; + const expected = 'abc.*?\\?ghi'; expect(escapeNonSpecialQuestionMarks(input)).to.equal(expected); }); }); diff --git a/packages/sitecore-jss/src/utils/utils.ts b/packages/sitecore-jss/src/utils/utils.ts index cf117a4165..f472cfb108 100644 --- a/packages/sitecore-jss/src/utils/utils.ts +++ b/packages/sitecore-jss/src/utils/utils.ts @@ -197,34 +197,38 @@ export const areURLSearchParamsEqual = (params1: URLSearchParams, params2: URLSe * Escapes non-special "?" characters in a string or regex. * - For regular strings, it escapes all unescaped "?" characters by adding a backslash (`\`). * - For regex patterns (strings enclosed in `/.../`), it analyzes each "?" to determine if it has special meaning - * (e.g., `?` in `(abc)?`, `.*?`) or is just a literal character. Only literal "?" characters are escaped. + * (e.g., `?` in `(abc)?`, `.*?`, `(?!...)`) or is just a literal character. Only literal "?" characters are escaped. * @param {string} input - The input string or regex pattern. * @returns {string} - The modified string or regex with non-special "?" characters escaped. */ export const escapeNonSpecialQuestionMarks = (input: string): string => { - const regexPattern = /(?