fix: use single quotes for x-data attributes with tojson
The Jinja |tojson filter outputs JSON with double quotes. When used
inside a double-quoted HTML attribute, these quotes break the attribute
parsing causing "expected expression, got '}'" errors.
Solution: Use single quotes for x-data attributes so JSON double quotes
don't conflict:
<div x-data='languageSelector("fr", {{ langs|tojson }})'>
Updated:
- language_selector.html macro (all 3 variants)
- shop/base.html language selector
- LANG-002 and LANG-003 architecture rules documentation
- Validator to detect double-quoted x-data with tojson
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -48,12 +48,12 @@ language_rules:
|
||||
...
|
||||
}">
|
||||
|
||||
RIGHT (function with tojson - NO safe in HTML attributes):
|
||||
<div x-data="languageSelector('{{ lang }}', {{ langs|tojson }})">
|
||||
RIGHT (function call with single quotes for x-data attribute):
|
||||
<div x-data='languageSelector("{{ lang }}", {{ langs|tojson }})'>
|
||||
|
||||
NOTE: Use |tojson (without |safe) in HTML attributes so quotes
|
||||
become " which the browser correctly decodes. Using |safe
|
||||
would output raw quotes that break the attribute parsing.
|
||||
IMPORTANT: Use SINGLE QUOTES for the x-data attribute value because
|
||||
|tojson outputs double quotes in JSON arrays. Single quotes on the
|
||||
outside prevent the JSON double quotes from breaking HTML parsing.
|
||||
|
||||
The languageSelector function must be defined in:
|
||||
- static/shop/js/shop-layout.js (for storefront)
|
||||
@@ -75,9 +75,12 @@ language_rules:
|
||||
When passing Python lists to JavaScript, use tojson appropriately:
|
||||
|
||||
IN HTML ATTRIBUTES (x-data, data-*, etc.):
|
||||
Use |tojson WITHOUT |safe - quotes become " which browsers decode:
|
||||
<div x-data="languageSelector('fr', {{ langs|tojson }})">
|
||||
<!-- Renders: x-data="languageSelector('fr', ["fr", "de"])" -->
|
||||
Use SINGLE QUOTES for the attribute and |tojson for the array:
|
||||
<div x-data='languageSelector("fr", {{ langs|tojson }})'>
|
||||
<!-- Renders: x-data='languageSelector("fr", ["fr", "de"])' -->
|
||||
|
||||
The single quotes on x-data prevent JSON double quotes from
|
||||
breaking the HTML attribute parsing.
|
||||
|
||||
IN <script> BLOCKS:
|
||||
Use |tojson|safe - raw JSON is valid inside script tags:
|
||||
@@ -85,13 +88,9 @@ language_rules:
|
||||
const languages = {{ vendor.storefront_languages|tojson|safe }};
|
||||
</script>
|
||||
|
||||
WRONG (raw output - Python syntax not valid JS):
|
||||
languages: {{ vendor.storefront_languages }}
|
||||
<!-- Outputs: ['fr', 'de'] - single quotes invalid in JSON -->
|
||||
|
||||
WRONG (|safe in HTML attributes - breaks attribute parsing):
|
||||
<div x-data="init({{ data|tojson|safe }})">
|
||||
<!-- Raw quotes break the attribute -->
|
||||
WRONG (double quotes with tojson - JSON quotes break the attribute):
|
||||
<div x-data="init({{ data|tojson }})">
|
||||
<!-- Outputs: x-data="init(["a", "b"])" - breaks at first [ -->
|
||||
pattern:
|
||||
file_pattern: "app/templates/**/*.html"
|
||||
required_with_jinja_array:
|
||||
|
||||
@@ -57,8 +57,9 @@
|
||||
{% set current = current_language if current_language in langs else langs[0] %}
|
||||
{% set positions = {'left': 'left-0', 'right': 'right-0'} %}
|
||||
{# Uses languageSelector() function per LANG-002 architecture rule #}
|
||||
{# Use single quotes for x-data so JSON double quotes don't break the attribute #}
|
||||
<div
|
||||
x-data="languageSelector('{{ current }}', {{ langs | tojson }})"
|
||||
x-data='languageSelector("{{ current }}", {{ langs | tojson }})'
|
||||
class="relative inline-block"
|
||||
>
|
||||
<button
|
||||
@@ -120,8 +121,9 @@
|
||||
{% set current = current_language if current_language in langs else langs[0] %}
|
||||
{% set positions = {'left': 'left-0', 'right': 'right-0'} %}
|
||||
{# Uses languageSelector() function per LANG-002 architecture rule #}
|
||||
{# Use single quotes for x-data so JSON double quotes don't break the attribute #}
|
||||
<div
|
||||
x-data="languageSelector('{{ current }}', {{ langs | tojson }})"
|
||||
x-data='languageSelector("{{ current }}", {{ langs | tojson }})'
|
||||
class="relative"
|
||||
>
|
||||
<button
|
||||
@@ -178,8 +180,9 @@
|
||||
{% set langs = enabled_languages[:2] if enabled_languages else ['fr', 'de'] %}
|
||||
{% set current = current_language if current_language in langs else langs[0] %}
|
||||
{# Uses languageSelector() function per LANG-002 architecture rule #}
|
||||
{# Use single quotes for x-data so JSON double quotes don't break the attribute #}
|
||||
<div
|
||||
x-data="languageSelector('{{ current }}', {{ langs | tojson }})"
|
||||
x-data='languageSelector("{{ current }}", {{ langs | tojson }})'
|
||||
class="inline-flex items-center gap-1 p-1 bg-gray-100 dark:bg-gray-700 rounded-lg"
|
||||
>
|
||||
<template x-for="lang in languages" :key="lang">
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
{# Language Selector #}
|
||||
{% set enabled_langs = vendor.storefront_languages if vendor and vendor.storefront_languages else ['fr', 'de', 'en'] %}
|
||||
{% if enabled_langs|length > 1 %}
|
||||
<div class="relative" x-data="languageSelector('{{ request.state.language|default('fr') }}', {{ enabled_langs|tojson }})">
|
||||
<div class="relative" x-data='languageSelector("{{ request.state.language|default("fr") }}", {{ enabled_langs|tojson }})'>
|
||||
<button
|
||||
@click="isLangOpen = !isLangOpen"
|
||||
@click.outside="isLangOpen = false"
|
||||
|
||||
@@ -2809,22 +2809,22 @@ class ArchitectureValidator:
|
||||
line_number=i,
|
||||
message="Complex language selector should use languageSelector() function",
|
||||
context=line.strip()[:80],
|
||||
suggestion="Use: x-data=\"languageSelector('{{ lang }}', {{ langs|tojson }})\"",
|
||||
suggestion="Use: x-data='languageSelector(\"{{ lang }}\", {{ langs|tojson }})'",
|
||||
)
|
||||
|
||||
# LANG-003: Check for tojson|safe in HTML attributes (breaks parsing)
|
||||
# In x-data attributes, |tojson WITHOUT |safe is correct (quotes become ")
|
||||
# In <script> blocks, |tojson|safe is correct (raw JSON is valid)
|
||||
if "|tojson|safe" in line and "x-data=" in line:
|
||||
# LANG-003: Check for double-quoted x-data with tojson (breaks parsing)
|
||||
# Double quotes + tojson outputs raw JSON double quotes that break HTML
|
||||
# Use single quotes for x-data when using tojson
|
||||
if 'x-data="' in line and "|tojson" in line:
|
||||
self._add_violation(
|
||||
rule_id="LANG-003",
|
||||
rule_name="Do not use tojson|safe in HTML attributes",
|
||||
rule_name="Use single quotes for x-data with tojson",
|
||||
severity=Severity.ERROR,
|
||||
file_path=file_path,
|
||||
line_number=i,
|
||||
message="|tojson|safe in x-data breaks HTML attribute parsing",
|
||||
message="Double-quoted x-data with |tojson breaks HTML (JSON has double quotes)",
|
||||
context=line.strip()[:80],
|
||||
suggestion="Remove |safe: {{ variable|tojson }} - quotes become " which browsers decode",
|
||||
suggestion="Use single quotes: x-data='func({{ data|tojson }})'",
|
||||
)
|
||||
except Exception:
|
||||
pass # Skip files that can't be read
|
||||
|
||||
Reference in New Issue
Block a user