From 31bd75ff393de73c4eaa5741f4861da15fdcc073 Mon Sep 17 00:00:00 2001 From: Elijah Ahianyo Date: Wed, 26 Jun 2024 13:23:07 -0700 Subject: [PATCH] [REF-3185][REF-3180]Dont escape backticks in JS string interpolation (#3566) * Dont escape backticks in JS string interpolation * add unit tests * Fix darglint * add a note to re-visit after new Var API is implemented * tests should have a good meaning --- reflex/utils/format.py | 29 +++++++++++++++++++++++++---- tests/utils/test_format.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/reflex/utils/format.py b/reflex/utils/format.py index 207de1edb..e163ebaac 100644 --- a/reflex/utils/format.py +++ b/reflex/utils/format.py @@ -210,10 +210,31 @@ def _escape_js_string(string: str) -> str: Returns: The escaped string. """ - # Escape backticks. - string = string.replace(r"\`", "`") - string = string.replace("`", r"\`") - return string + + # TODO: we may need to re-vist this logic after new Var API is implemented. + def escape_outside_segments(segment): + """Escape backticks in segments outside of `${}`. + + Args: + segment: The part of the string to escape. + + Returns: + The escaped or unescaped segment. + """ + if segment.startswith("${") and segment.endswith("}"): + # Return the `${}` segment unchanged + return segment + else: + # Escape backticks in the segment + segment = segment.replace(r"\`", "`") + segment = segment.replace("`", r"\`") + return segment + + # Split the string into parts, keeping the `${}` segments + parts = re.split(r"(\$\{.*?\})", string) + escaped_parts = [escape_outside_segments(part) for part in parts] + escaped_string = "".join(escaped_parts) + return escaped_string def _wrap_js_string(string: str) -> str: diff --git a/tests/utils/test_format.py b/tests/utils/test_format.py index e9c79a4a2..5e43cfc39 100644 --- a/tests/utils/test_format.py +++ b/tests/utils/test_format.py @@ -96,6 +96,36 @@ def test_wrap(text: str, open: str, expected: str, check_first: bool, num: int): assert format.wrap(text, open, check_first=check_first, num=num) == expected +@pytest.mark.parametrize( + "string,expected_output", + [ + ("This is a random string", "This is a random string"), + ( + "This is a random string with `backticks`", + "This is a random string with \\`backticks\\`", + ), + ( + "This is a random string with `backticks`", + "This is a random string with \\`backticks\\`", + ), + ( + "This is a string with ${someValue[`string interpolation`]} unescaped", + "This is a string with ${someValue[`string interpolation`]} unescaped", + ), + ( + "This is a string with `backticks` and ${someValue[`string interpolation`]} unescaped", + "This is a string with \\`backticks\\` and ${someValue[`string interpolation`]} unescaped", + ), + ( + "This is a string with `backticks`, ${someValue[`the first string interpolation`]} and ${someValue[`the second`]}", + "This is a string with \\`backticks\\`, ${someValue[`the first string interpolation`]} and ${someValue[`the second`]}", + ), + ], +) +def test_escape_js_string(string, expected_output): + assert format._escape_js_string(string) == expected_output + + @pytest.mark.parametrize( "text,indent_level,expected", [