Ludtwig

GitHub GitHub Workflow Status (branch) GitHub release (latest by date including pre-releases) Crates.io GitHub all releases Crates.io

A CLI tool for developers that tries to speedup the development workflow while working with templating (.twig) files. It focuses mainly on formatting the files with a uniform code style and detecting mistakes. It is only a "formatter" that can be run locally or in the pipeline, it will not report anything to your IDE. It is easy to configure with a config file or environment variables.

Status / Disclaimer

Ludtwig is currently in an early development state. Please use the tool with caution and validate the changes that is has made (backup your files before running this). Feel free to create new issues and help to steer this project in the right direction.

Overview

Example

Before*

```twig {% block mycomponent %}

{% block mycomponentheader %}

{{ header }}

{% endblock %} {% block my
component_body %} (whitespaces around this) (but here are no whitespaces)

This is a paragraph. And the browser sees only whitespace and doesn't care about many spaces. Linebreaks are also no problem. they are kept.

                The browser also does not care about empty lines.
                So why not format text like this how the browser displays it (but keep single line breaks for visibility)?
            </p>
        </my-component-body>
    {% endblock %}
</div>

{% endblock %} ``` *This is not what a normal template should look like, but it demonstrates that ludtwig can work with any combination of Html / Twig / Vue.js (or other solutions that only need the {{...}} syntax and bring custom tags / attributes). For example you can use the powerful block feature of twig.js, but also every feature from vue.js and ludtwig can still work with the templates.

After running ludtwig

```twig {% block my_component %}

    {% block my_component_header %}
        <h2 :style="style"
            class="whitespace-sensitive">{{ header }}</h2>
    {% endblock %}

    {% block my_component_body %}
        <my-component-body
                class="component-body"
                v-model="body"
                @change="if a > 0 { onChange(); }"
                {% if isDisabled %}
                    disabled
                {% elseif hasCustomAttribute %}
                    {{ customAttrName }}="{{ customAttrValue }}"
                {% else %}
                    {{ completeCustomAttr }}
                {% endif %}>
            <charlong9
                    some="custom"
                    attributes="that"
                    are="at least 3 or make the line long enough">
                (whitespaces around this)
            </charlong9>
            <span>(but here are no whitespaces)</span>
            <p>
                This is a paragraph.
                And the browser sees only whitespace and doesn't care about many spaces.
                Linebreaks are also no problem. they are kept.
                The browser also does not care about empty lines.
                So why not format text like this how the browser displays it (but keep single line breaks for visibility)?
            </p>
        </my-component-body>
    {% endblock %}

</div>

{% endblock %} ```

It also catches errors / problems during parsing*

```text Parsing files...

File: "./fixtures/showcase.html.twig" [Error] Parsing goes wrong in line 7 and column 38 :

Files scanned: 1, Errors: 1, Warnings: 0 Happy bug fixing ;) ``` *The example template was changed with missing quotes

And if the parsing succeeds it checks the AST (abstract syntax tree) for mistakes / best practices*

```text Parsing files...

File: "./fixtures/showcase.html.twig" [Warning] Duplicate twig block name found: 'my_component'

Files scanned: 1, Errors: 0, Warnings: 1 Happy bug fixing ;) ``` *The example template was extended with another twig block with the name 'my_component'.

Current features

  • Fast + concurrent execution
  • Parsing of idiomatic Html / Twig / Vue.js templating files
    • It will not parse non idiomatic Html where for example closing tags are forgotten (that otherwise could still work in the browser). In this case ludtwig tries to produce a helpful error message.
  • Write the AST (abstract syntax tree) in a formatted way back into files. The formatting can be configured with a config file (create one with ludtwig -C which also contains documentation).
  • Analyse the AST for common mistakes / suggestions

Current limitations

  • Twig syntax is still not fully supported (Some hierarchical syntax is missing)
  • You may encounter edge cases that result in parsing errors. Please create issues for them.
  • The analyzing of the AST can currently not be configured and is pretty much in a WIP state.

Installation

Cargo (rust toolchain)

Run the following cargo command to install or update ludtwig: cargo install ludtwig
You can install cargo here: https://www.rust-lang.org/learn/get-started
If you don't want to install the rust toolchain / cargo you can still use the manual installation below.

Manual

Download the latest release binary for your operating system and put it in your PATH for easy access.

How to use Ludtwig?

After the installation have a look at ludtwig --help for more information. It should be self-explanatory. Also have a look at the default config file if you want to customize the way how ludtwig formats your files. To create it in your current working directory run ludtwig -C.

Basic Concepts

  • Every file is parsed concurrently and independent of each other into an AST (abstract syntax tree)
    • Parsing errors will result in not writing / analysing the file
  • After the parsing was successful the following happens concurrently with the AST:
    • the writer prints the AST in a formatted way back into a file
    • the analyzer checks the AST for warnings and report them back to the user
    • the analyzer can not influence the writer or the other way around
  • After this is done for all files the output is presented to the user

Development setup

Make sure you have Rust installed on your system.
Clone this repository.

Run the project with parameters: cargo run -- filaA.twig
Build the project for production with: cargo build --release
(the produced binary will be here: target/release/ludtwig)
Run tests with: cargo test

If you want to benchmark the performance of the release build you could use Hyperfine and run it like so:
hyperfine -i 'ludtwig -o ./output ./my-template-folder'

License

Copyright (c) 2020 Malte Janz
ludtwig is distributed under the terms of the MIT License.
See the LICENSE file for details.

Dependencies / License notices*

If you build this project locally or use the distributed binary keep also the following licenses in mind: - ludtwig-parser - MIT - rayon - MIT / Apache 2.0 - structopt - MIT / Apache 2.0 - ansi_term - MIT - walkdir - MIT - figment - MIT / Apache 2.0 - serde - MIT / Apache 2.0 - regex - MIT / Apache 2.0

For testing purposes this repository also includes code from the following sources (not included in distributed binary): - Shopware - MIT - SwagMigrationAssistant - MIT

Special thanks goes to the authors of these dependencies.
*This list, and the links may not be up to date, you should do your own research. Deeper dependencies are not listed.