From 7b7e504de721e51cf4c5dcc8115540145a8eac23 Mon Sep 17 00:00:00 2001 From: jlw4049 Date: Sat, 15 Jul 2023 19:33:23 -0400 Subject: [PATCH 1/6] - Added some regex to ensure we have double quoted attributes for the whole of the file - Added code to handle extra spacing inside the double quotes, as well as ensure only single quotes - It also removes any extra white space based on teh word boundaries --- src/djlint/formatter/indent.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/djlint/formatter/indent.py b/src/djlint/formatter/indent.py index c73553427..24f634334 100644 --- a/src/djlint/formatter/indent.py +++ b/src/djlint/formatter/indent.py @@ -320,6 +320,10 @@ def fix_handlebars_template_tags(html: str, match: re.Match) -> str: if ignored_level == 0: is_block_raw = False + # set a rule for tmp content to have outer double quotes only for jinja + if config.profile == "jinja": + tmp = re.sub(r"=(')(.*?)(')", r'="\2"', tmp) + beautified_code = beautified_code + tmp # try to fix internal formatting of set tag @@ -396,7 +400,24 @@ def format_function(config: Config, html: str, match: re.Match) -> str: leading_space, ) - return f"{leading_space}{open_bracket} {tag}({contents}){index} {close_bracket}" + cleaned_match = ( + f"{leading_space}{open_bracket} {tag}({contents}){index} {close_bracket}" + ) + + if config.profile == "jinja": + # remove inconsistent quotes from the content + contents = contents.replace('"', "'") + + # check for trailing or leading spaces inside the single quotes and remove them + contents = re.sub(r"(?<=')\s+|\s+(?=')", "", contents) + + # update cleaned match + cleaned_match = f"{leading_space}{open_bracket} {tag}({contents}){index} {close_bracket}" + + # strip any potential white space from the cleaned match + cleaned_match = cleaned_match.strip() + + return cleaned_match if config.no_set_formatting is False: func = partial(format_set, config, beautified_code) From 4a1dc72a1c9abbb214cefdb50a5c59e95a10a31f Mon Sep 17 00:00:00 2001 From: jlw4049 Date: Sat, 15 Jul 2023 19:33:38 -0400 Subject: [PATCH 2/6] - Fixed testing to be in line with the single quotes inside and double quotes on the outside --- tests/test_jinja/test_parenthesis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_jinja/test_parenthesis.py b/tests/test_jinja/test_parenthesis.py index 4379f7cac..9e6d22085 100644 --- a/tests/test_jinja/test_parenthesis.py +++ b/tests/test_jinja/test_parenthesis.py @@ -10,7 +10,7 @@ test_data = [ pytest.param( ("{{ url('foo')}}"), - ('{{ url("foo") }}\n'), + ("{{ url('foo') }}\n"), id="parenthesis_tag", ), ] From 7d4d93fd6d1502da12478479ed77837f1adcd02d Mon Sep 17 00:00:00 2001 From: jlw4049 Date: Sat, 15 Jul 2023 19:40:28 -0400 Subject: [PATCH 3/6] - Fix comment --- src/djlint/formatter/indent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/djlint/formatter/indent.py b/src/djlint/formatter/indent.py index 24f634334..8a0c7b973 100644 --- a/src/djlint/formatter/indent.py +++ b/src/djlint/formatter/indent.py @@ -405,7 +405,7 @@ def format_function(config: Config, html: str, match: re.Match) -> str: ) if config.profile == "jinja": - # remove inconsistent quotes from the content + # remove double quotes from contents contents = contents.replace('"', "'") # check for trailing or leading spaces inside the single quotes and remove them From f8fc285e08b657fd43989bfdfccf9e37395e5873 Mon Sep 17 00:00:00 2001 From: jlw4049 Date: Sun, 16 Jul 2023 18:00:25 -0400 Subject: [PATCH 4/6] - Add both quote styles to the jinja parenthesis test --- tests/test_jinja/test_parenthesis.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/test_jinja/test_parenthesis.py b/tests/test_jinja/test_parenthesis.py index 9e6d22085..9da32da21 100644 --- a/tests/test_jinja/test_parenthesis.py +++ b/tests/test_jinja/test_parenthesis.py @@ -9,16 +9,22 @@ test_data = [ pytest.param( - ("{{ url('foo')}}"), - ("{{ url('foo') }}\n"), + "{{ url('foo') }}", + "{{ url('foo') }}\n", + '{{ url("foo") }}\n', id="parenthesis_tag", - ), + ) ] -@pytest.mark.parametrize(("source", "expected"), test_data) -def test_base(source, expected, jinja_config): +@pytest.mark.parametrize(("source", "expected1", "expected2"), test_data) +def test_base(source, expected1, expected2, jinja_config): output = formatter(jinja_config, source) - printer(expected, source, output) - assert expected == output + printer(expected1, source, output) + assert expected1 == output or expected2 == output + + output = formatter(jinja_config, source) + + printer(expected2, source, output) + assert expected1 == output or expected2 == output From e9dc2aaf7c977def61af6c75fd0b7fc87634d198 Mon Sep 17 00:00:00 2001 From: jlw4049 Date: Sun, 16 Jul 2023 18:01:46 -0400 Subject: [PATCH 5/6] - Add the ability to detect what ever the outer most quotes was for each section and correctly modify the inner quotes - This will always prioritize what ever the user had set on the outer quotes and will only activate for jinja templates --- src/djlint/formatter/indent.py | 51 ++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/src/djlint/formatter/indent.py b/src/djlint/formatter/indent.py index 8a0c7b973..1dca1c2dc 100644 --- a/src/djlint/formatter/indent.py +++ b/src/djlint/formatter/indent.py @@ -62,6 +62,7 @@ def fix_handlebars_template_tags(html: str, match: re.Match) -> str: in_set_tag = False is_raw_first_line = False is_block_raw = False + jinja_replace_list = [] slt_html = config.indent_html_tags @@ -320,9 +321,18 @@ def fix_handlebars_template_tags(html: str, match: re.Match) -> str: if ignored_level == 0: is_block_raw = False - # set a rule for tmp content to have outer double quotes only for jinja + # detect the outer quotes for jinja if config.profile == "jinja": - tmp = re.sub(r"=(')(.*?)(')", r'="\2"', tmp) + matches = re.findall( + r"=([\"'])(\{\{[\s\S]*?\}\})\1", tmp, flags=re.MULTILINE + ) + + for match in matches: + outer_quotes = match[0] + inner_content = match[1] + jinja_replace_list.append( + {"outer_quote": outer_quotes, "content": inner_content} + ) beautified_code = beautified_code + tmp @@ -400,22 +410,39 @@ def format_function(config: Config, html: str, match: re.Match) -> str: leading_space, ) + # # define cleaned match with both quote styles cleaned_match = ( f"{leading_space}{open_bracket} {tag}({contents}){index} {close_bracket}" ) if config.profile == "jinja": - # remove double quotes from contents - contents = contents.replace('"', "'") - - # check for trailing or leading spaces inside the single quotes and remove them - contents = re.sub(r"(?<=')\s+|\s+(?=')", "", contents) - - # update cleaned match - cleaned_match = f"{leading_space}{open_bracket} {tag}({contents}){index} {close_bracket}" + outer_quotes = None + inner_quotes = None + + # Determine user quote type + for jinja_content in jinja_replace_list: + content = cleaned_match.replace('"', "'") # Replace double quotes + if content == jinja_content.get("content"): + outer_quotes = jinja_content.get("outer_quote") + inner_quotes = "'" if outer_quotes == '"' else '"' + break + content = cleaned_match.replace("'", '"') # Replace single quotes + if content == jinja_content.get("content"): + outer_quotes = jinja_content.get("outer_quote") + inner_quotes = '"' if outer_quotes == "'" else "'" + break + + if outer_quotes is not None and inner_quotes is not None: + # Replace all content inner quotes and remove trailing/leading spaces + cleaned_contents = re.sub( + rf"(?<=\{re.escape(outer_quotes)})\s+|\s+(?=\{re.escape(outer_quotes)})", + "", + contents.replace(outer_quotes, inner_quotes), + ) - # strip any potential white space from the cleaned match - cleaned_match = cleaned_match.strip() + # Update cleaned match + cleaned_match = f"{leading_space}{open_bracket} {tag}({cleaned_contents}){index} {close_bracket}" + cleaned_match = cleaned_match.strip() return cleaned_match From 71698c098271b48d2218b841ca0107a5a9348db4 Mon Sep 17 00:00:00 2001 From: Christopher Pickering Date: Fri, 1 Sep 2023 14:00:28 +0200 Subject: [PATCH 6/6] updated test --- tests/test_jinja/test_parenthesis.py | 48 +++++++++++++++++++++------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/tests/test_jinja/test_parenthesis.py b/tests/test_jinja/test_parenthesis.py index 9da32da21..b84a7d0c5 100644 --- a/tests/test_jinja/test_parenthesis.py +++ b/tests/test_jinja/test_parenthesis.py @@ -10,21 +10,45 @@ test_data = [ pytest.param( "{{ url('foo') }}", - "{{ url('foo') }}\n", '{{ url("foo") }}\n', - id="parenthesis_tag", - ) + id="single_parenthesis_tag", + ), + pytest.param( + '', + '", + id="single_escaped quote", + ), + pytest.param( + 'Test reminders', + 'Test reminders\n', + id="single_url_for", + ), + pytest.param( + '{{ url("foo") }}', + '{{ url("foo") }}\n', + id="double_parenthesis_tag", + ), + pytest.param( + 'Test reminders', + 'Test reminders\n', + id="double_url_for", + ), ] -@pytest.mark.parametrize(("source", "expected1", "expected2"), test_data) -def test_base(source, expected1, expected2, jinja_config): - output = formatter(jinja_config, source) - - printer(expected1, source, output) - assert expected1 == output or expected2 == output - +@pytest.mark.parametrize(("source", "expected"), test_data) +def test_base(source, expected, jinja_config): output = formatter(jinja_config, source) - printer(expected2, source, output) - assert expected1 == output or expected2 == output + printer(expected, source, output) + assert expected == output