Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: list and dict literals in tags + fix tag parser #898

Merged

Conversation

JuroOravec
Copy link
Collaborator

@JuroOravec JuroOravec commented Jan 9, 2025

Following up on #872, because, frankly, it was fun to solve 😄

This PR refactors the tag parser, which turns Django's template tag content of e.g.

{% component key=value key2="abc def" / %}

into an AST which can be worked with downstream.

  1. This PR fixes the bug in In-template component input that has filter(s) with whitespace don't work #894 - after this PR, it will be possible to have whitespace around filters and translation syntax:

    {% component key=_( "hello" ) key2="abc def" | lower / %}

  2. I added support for defining list and dict literals as inputs, and allowing to spread variables into those literal lists and dicts.

    I then took this idea to its logical conclusion, allowing nested lists, dicts, etc. So the syntax works as follows:

    Supported syntax:

    • Variables: val, key
    • Kwargs (attributes): key=val, key2='val2 two'
    • Quoted strings: "my string", 'my string'
    • Translation: _("my string")
    • Filters: val|filter, val|filter:arg
    • List literals: [value1, value2], key=[value1, [1, 2, 3]]
    • Dict literals: {"key1": value1, "key2": value2}, key={"key1": value1, "key2": {"nested": "value"}}
    • Trailing commas: [1, 2, 3,], {"key": "value", "key2": "value2",}
    • Spread operators: ..., *, **
    • Spread inside lists and dicts: key=[1, *val, 3], key={"key": val, **kwargs, "key2": 3}
    • Spread with list and dict literals: {**{"key": val2}, "key": val1}, [ ...[val1], val2 ]
    • Spread list and dict literals as attributes: {% component ...[val1] %}, {% component ...{"key" val1 } %}

    Invalid syntax:

    • Spread inside a filter: val|...filter
    • Spread inside a dictionary key: attr={...attrs: "value"}
    • Spread inside a dictionary value: attr={"key": ...val}
    • Misplaced spread: attr=[...val], attr={...val}, attr=[**val], attr={*val}
    • Spreading lists and dicts: ...[1, 2, 3], ...{"key": "value"}

    This tag content is parsed into an AST that looks like this:

    [
    TagAttr(
        key=None,
        value=TagValueStruct(
            type="simple",
            spread=None,
            meta={},
            entries=[
                TagValue(
                    parts=[
                        TagValuePart(
                            value="component", quoted=None, spread=None, translation=False, filter=None
                        ),
                    ]
                ),
            ],
        ),
        start_index=13,
    )
    ...
    ]

NOTE: I didn't make changes to documentation yet. For one, this is already a huge PR. For second, while I updated the parser, as of this PR, users cannot yet use the literal dicts and lists. Or rather, they can write it, but it will be treated as a string. So I plan to make a second PR to update that part and update documentation with it.

Closes #894

Copy link
Collaborator

@EmilStenstrom EmilStenstrom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a nice feature, but with ~3000 lines, it's not worth reviewing imho. I'll just trust the tests in this case :)

@JuroOravec
Copy link
Collaborator Author

Fair point. Just a note, that 2200 lines of that are purely tests, because it's about 30 tests, and the AST takes up a lot of space.

@JuroOravec JuroOravec merged commit a79b24b into django-components:master Jan 9, 2025
15 checks passed
@JuroOravec JuroOravec deleted the jo-tag-list-and-dict-literals branch January 9, 2025 20:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

In-template component input that has filter(s) with whitespace don't work
2 participants