Code Monkey home page Code Monkey logo

twigcs's Introduction

Twigcs

Integrate

Code Coverage Type Coverage

Latest Stable Version Total Downloads Monthly Downloads

The missing checkstyle for twig!

Twigcs aims to be what phpcs is to php. It checks your codebase for violations on coding standards.

How to install

Run

composer require --dev friendsoftwig/twigcs

to install friendsoftwig/twigcs with composer.

Run

phive install friendsoftwig/twigcs

to install friendsoftwig/twigcs with phive.

How to run

Basically, just run:

twigcs /path/to/views

On Symfony projects, you can run, for instance:

twigcs /project/dir/app/Resources/views

You will get a summary of the violations in the console. The exit code of the command is based on the severity of any violation found. By default, twigcs only tolerates info, this can be changed at run time:

twigcs /path/to/views --severity error   # Allows info and warnings
twigcs /path/to/views --severity warning # Allows info
twigcs /path/to/views --severity info    # Disallows info
twigcs /path/to/views --severity ignore  # Allows everything

With the example above, info is still displayed but not altering the exit code.

You can also exclude relative subfolders of path like this:

twigcs /path/to/views --exclude vendor

Tips: You can use multiple exclude parameters.

Restricting output

By default TwigCS will output all lines that have violations regardless of whether they match the severity level specified or not. If you only want to see violations that are greater than or equal to the severity level you've specified you can use the --display option. For example.

twigcs /path/to/views --severity error --display blocking

Would only display errors and not warnings.

Alternatively you can use --display all which is the default behaviour as described above.

Continuous Integration

Twigcs can be used with your favorite CI server. The command itself will return a consistent exit code telling the CI job if it failed or succeeded. You can also have a nice xml report (checkstyle format):

twigcs /path/to/views --reporter checkstyle > /path/to/report.xml

Reporters

Twigcs currently supports to following reporters:

twigcs /path/to/views --reporter console
twigcs /path/to/views --reporter checkstyle
twigcs /path/to/views --reporter junit
twigcs /path/to/views --reporter emacs
twigcs /path/to/views --reporter json
twigcs /path/to/views --reporter csv
twigcs /path/to/views --reporter githubAction
twigcs /path/to/views --reporter gitlab

Using older twig versions

By default twigcs is using Twig 3. This means that features like filter tags or filtered loops using if are not supported anymore. You can use an older twig version using the twig-version option:

twigcs /path/to/views --twig-version 2

Custom coding standard

At the moment the only available standard is the official one from twig.

You can create a class implementing RulesetInterface and supply it as a --ruleset option to the CLI script:

twigcs /path/to/views --ruleset \MyApp\TwigCsRuleset

Note: twigcs needs to be used via composer and the ruleset class must be reachable via composer's autoloader for this feature to work. Also note that depending on your shell, you might need to escape backslashes in the fully qualified class name:

twigcs /path/to/views --ruleset \\MyApp\\TwigCsRuleset

For more complex needs, have a look at the custom ruleset documentation.

File-based configuration

Using configuration, you can easily store per-project settings:

// ~/.twig_cs.dist.php
<?php

declare(strict_types=1);

use FriendsOfTwig\Twigcs;

return Twigcs\Config\Config::create()
    ->setName('my-config')
    ->setSeverity('warning')
    ->setReporter('json')
    ->setRuleSet(Twigcs\Ruleset\Official::class)
    ->setSpecificRuleSets([ // Every file matching the pattern will use a different ruleset.
        '*/template.html.twig' => Acme\Project\CustomRuleset::class,
    ])
;

This configuration will be applied if you call twigcs from the ~/ directory. If you run twigcs from outside this directory, you must use the --config option:

cd ~/dirA
twigcs --config ~/dirB/.twig_cs.dist.php # Will lint templates in ~/dirA with the config of ~/dirB

By default, the files

  • .twig_cs.php
  • .twig_cs
  • .twig_cs.dist.php
  • .twig_cs.dist

are looked up in your current working directory (CWD).

You can also provide finders inside config files, they will completely replace the path in the CLI:

// ~/.twig_cs.dist.php
<?php

declare(strict_types=1);

use FriendsOfTwig\Twigcs;

$finderA = Twigcs\Finder\TemplateFinder::create()->in(__DIR__.'/dirA');
$finderB = Twigcs\Finder\TemplateFinder::create()->in(__DIR__.'/dirB');

return Twigcs\Config\Config::create()
    // ...
    ->addFinder($finderA)
    ->addFinder($finderB)
    ->setName('my-config')
;

In this case, calling twigcs from the ~/ directory of the config will run the linter on the directories pointed by the finders. If you explicitly supply a path to the CLI, it will be added to the list of linted directories:

twigcs ~/dirC # This will lint ~/dirA, ~/dirB and ~/dirC using the configuration file of the current directory.

Template resolution

Using file based configuration, you can provide a way for twigcs to resolve template. This enables better unused variable/macro detection. Here's the simplest example when you have only one directory of templates.

<?php

declare(strict_types=1);

use FriendsOfTwig\Twigcs;

return Twigcs\Config\Config::create()
    // ...
    ->setTemplateResolver(new Twigcs\TemplateResolver\FileResolver(__DIR__))
    ->setRuleSet(FriendsOfTwig\Twigcs\Ruleset\Official::class)
;

Here is a more complex example that uses a chain resolver and a namespaced resolver to handle vendor templates:

<?php

declare(strict_types=1);

use FriendsOfTwig\Twigcs;

return Twigcs\Config\Config::create()
    ->setFinder($finder)
    ->setTemplateResolver(new Twigcs\TemplateResolver\ChainResolver([
        new Twigcs\TemplateResolver\FileResolver(__DIR__ . '/templates'),
        new Twigcs\TemplateResolver\NamespacedResolver([
            'acme' =>  new Twigcs\TemplateResolver\FileResolver(__DIR__ . '/vendor/Acme/AcmeLib/templates')
        ]),
    ]))
;

This handles twig namespaces of the form @acme/<templatepath>.

Upgrading

If you're upgrading from 3.x to 4.x or later, please read the upgrade guide.

Community

Join us on Symfony Devs via the twigcs channel.

Changelog

Please have a look at CHANGELOG.md.

Contributing

The main branch is the development branch. If you find any bug or false positive during style checking, please open an issue or submit a pull request.

When creating or changing a class, don't forget to add you as an @author at the top of the file.

Please have a look at CONTRIBUTING.md.

twigcs's People

Contributors

2no avatar backendtea avatar benatespina avatar cedric-anne avatar chi-teck avatar ciloe avatar dependabot[bot] avatar dodenis avatar engrave-fr avatar frankdekker avatar franmomu avatar gaards avatar gfilliere avatar jklmnop avatar kristoftorfs avatar laurentmuller avatar localheinz avatar nicolas-grekas avatar nicwortel avatar oallain avatar owlycode avatar rajeshreeputra avatar samnela avatar stephanvierkant avatar stmh avatar stof avatar tomasfejfar avatar yguedidi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

twigcs's Issues

False positive no space after "]"

The following code gives a false positive:

{% for data in items[foo.id] if data.bar is not null %}

The error: ERROR There should be no space after "]".

Error on master (erroneous comma)

Using master for a project, getting this:

Parse error: syntax error, unexpected ')' in /Users/thomas/sites/theme/app/web/app/themes/pixels-starter-theme/vendor/friendsoftwig/twigcs/src/Rule/RegEngineRule.php on line 98

Line 97 has a comma at the end that isn't needed :)

False positive on {% for 1..10 %}

Twigcs shows a false positive on the .. operator inside for loops :

{% for 1..10 %}
    <div></div>
{% endfor %}
l.1 c.8 : ERROR There should be 1 space between the ".." operator and its left operand.
l.1 c.10 : ERROR There should be 1 space between the ".." operator and its right operand.

For loop and variable usage

When using the following snippet :

{% set foo = false %}

{% for ... %}
    {% set foo = true %}
    ...
{% endfor %}

{% if foo %}
    ...
{% else %}

A false positive is generated : WARNING Unused variable "foo".

(I know the code above is quite a bad practice, it just highlights the problem)

How to contribute with stand-alone rules that aren't part of the Official ruleset?

Hello.

In one of my projects, I'm trying to enforce a custom ruleset which would hopefully make templates succinct and readable by a non-technical person, and was curious how I could contribute back here once I'm happy with the setup and once we have all the rules in place.

I see that there are functional tests which actually test pretty much everything, which are ran against the "Official" ruleset, which is basically just a couple of rules grouped together.
If I wanted to add new rules and test them, what would be the preferred way to do it with the current setup?

My understanding is that adding them to the current set/functional test set wouldn't cut it, as they aren't (nor should be) part of the official set, so I'm wondering what do you think would be the best approach to do so?

Now, back onto the custom ruleset โ€“ the idea is that a non-technical person should be able to open a template and figure out what is going on.
To achieve this, there are ground rules in place:

  • template must be data-type agnostic -> you should never check if something is exactly null, true or false, because by writing either of those keywords into the template your template is not data-type agnostic anymore
  • plain English must be used whenever possible

Following just these two rules arguably made the templates more readable in general (especially to non-technical person), with the extra bonus of having strict comparison in place for free.

Examples

{# bad #}
{% if product.price == 100 %}

{# good, plus strict comparison bonus for free #}
{% if product.price is same as (100) %}
{# bad #}
{% if 100 / 5 == 0 %}
{% if 100 / 5 is same as (0) %}

{# good #}
{% if 100 is divisible by (5) %}
{# bad #}
{% if number % 2 == 0 %}
{% if number % 2 is same as (0) %}

{# good #}
{% if number is even %}
{# bad #}
{% if number % 2 == 1 %}
{% if number % 2 is same as (1) %}

{# good #}
{% if number is odd %}

Making template data-type agnostic becomes even more obvious when it comes to booleans.

{# bad #}
{% if user.active is same as (false) %}
{# good #}
{% if not user.active %}

{# bad #}
{% if user.active is same as (true) %}
{# good #}
{% if user.active %}

When passing view-models to templating engine (i.e. Twig), they could have optional (i.e. nullable) properties.
Imagine a template which renders user profile, and among other things their address.

{# bad โ€“ unnecessarily long, breaks the data-type agnostic rule and not so readable, especially to non-technical people #}
{% if user.address is not same as (null) %}
    {{ user.address.zipCode }} {{ user.address.city }}
{% endif %}

{# good #}
{% if user.address %}
    {{ user.address.zipCode }} {{ user.address.city }}
{% endif %}

Anyway, there are more of these that I haven't listed, but I'm just wondering about your initial thoughts and the guidelines on how to contribute back.

Maybe there doesn't need to be a new ruleset in place in this repo, but since each of these examples are essentially standalone rules, I would like to contribute back by adding them so people can cherry-pick whichever ones they want into their own rulesets. But then I'm still wondering how to approach the (functional) testing aspect of it?

All constructive feedback and comments are more than welcome. :)

Cheers

Example of using a custom ruleset

First of thanks for the work on this, it's the only stand alone twig CS I can find ๐Ÿ™๐Ÿผ

I am trying to implement my own ruleset as I really need to have a fix on the issue with the arrays (see #56 ) but I need that fixed before I can use this in production and on projects.

Could you possibly give a detailed example of what needs to be done? I'm ok with Composer but certainly not an expert and I keep getting issues with the autoloader part. ( Ruleset class must implement FriendsOfTwig\Twigcs\Ruleset\RulesetInterface error all the time )

Thanks again for the awesome work!

Make a phar

This would allow to install the project globally without relying on composer global that can conflict with other tools.

Reworking the syntax checker

I'm currently reworking the way Twigcs handles basic style checks like counting the number of spaces, checking that something is lowercased etc... It will be a separated engine that can works along the unused macros/variable checkers. At the moment it is called "RegEngine" because it heavily uses regular expression.

The branch: https://github.com/OwlyCode/twigcs/commits/experimental

I expect this rework to fix the following issues :

  • #56 Array rule
  • #60 Does not respect both include syntaxes
  • #62 Support extended white space control operators in Twig templates
  • #63 False positive no space before "("
  • #64 False positive 1 space(s) after "-" with negative numbers

New tag?

Could be possible to publish a new tag with the last Composer's version improvements?

Disable rules via CLI option?

I'm unable to figure out how to load a custom ruleset within the context of my global composer instance. I'm unsure where to place the file, exactly how to get composer to see the file, how to reference it, etc.

Is it possible that there could be a way to disable specific rules via the command line?

I'm using twigcs within Craft CMS, and pascalCase is commonly used throughout our code for variable naming, and even Craft's internal templating, thus the LowerCaseVariable is a rule we'd like to exclude.

Phar: 'Allocine\Twigcs\Console\Application' not found

twigcs version: 3.2.2, 3.2.1, 3.2.0 (phar)

testen on version 3.2.2 windows (php 7.3) and linux (php 7.1)

wget https://github.com/friendsoftwig/twigcs/releases/download/v3.2.2/twigcs.phar
php twigcs.phar --version

PHP Fatal error:  Uncaught Error: Class 'Allocine\Twigcs\Console\Application' not found in phar:///home/username/twigcs.phar/bin/twigcs:12
Stack trace:
#0 /home/username/twigcs.phar(12): require()
#1 {main}
  thrown in phar:///home/username/twigcs.phar/bin/twigcs on line 12

False positive when there is a ternary in an inline tag

With

{% block myblock 'foo' ~ (mycondition ? 'bar' : 'baz') %}

or

{% set myvar = mycondition ? 'foo' : 'bar' %}

I get those complementary errors:

ERROR There should be 1 space between the "%" operator and its left operand.
ERROR There should be 1 space between the "%" operator and its right operand.

Twig 1 support

According to requirements in composer.json Twics should be compatible with Twig 1 but it's not.
PHP Fatal error: Declaration of Allocine\Twigcs\Compatibility\TwigLexer::tokenize(Twig_Source $source) must be compatible with Twig_Lexer::tokenize($code, $name = NULL) in /var/www/rocketsoftware/vendor/allocine/twigcs/src/Compatibility/TwigLexer.php on line 28

Detection of macros badly assumes import as being reserved

The detection of macro assumes than any import name token involves a macro import. but this is wrong. import can be used as a variable name, a function name (and even a macro name), which are all name tokens too.

Instead, the code should look for a {% import or {% from ... import combination ({% is a BLOCK_START_TYPE token).

Token type collision

I've tried printing the token stream for the following template:

{% if hello and
    world %}
{% endif %}

This was the result:

PHP Fatal error:  Method Twig\Token::__toString() must not throw an exception, caught LogicException: Token of type "13" does not exist.

Additionally, if I try to do the same for the following template:

{% if hello %}
{% endif %}

This is the result:

BLOCK_START_TYPE()
ARROW_TYPE( )
NAME_TYPE(if)
ARROW_TYPE( )
NAME_TYPE(hello)
ARROW_TYPE( )
BLOCK_END_TYPE()
BLOCK_START_TYPE()
ARROW_TYPE( )
NAME_TYPE(endif)
ARROW_TYPE( )
BLOCK_END_TYPE()

The ARROW_TYPE seemed odd to me, so after digging a bit it looks to me as the issue lies in the constants used by TwigCS which have conflicts with Twig.

More precisely, here is defined a constant which should represent whitespace, but eventually Twig caught up with the numbering.

So these two seem to be kinda connected.

As a reference, I was toying around with v3.2.2.

Unused macro checker does not handle scopes properly

The body of a macro is a fully isolated scope. So an import done inside a macro must be checked for usage only inside the macro. And an import done outside the macro must look for usages outside the macro too (finding a usage inside the macro is not valid, as it cannot reference the macro).
And the implementation must be careful that the same name can be used inside and outside the macro.

Does not respect both include syntaxes

This is a follow-up to #49


While the twigcs now correctly allows the following code to pass:

{% set foo %}1{% endset %}{{ include("foo.html.twig", {foo: foo}) }}

Valid as per: https://twig.symfony.com/doc/2.x/functions/include.html

It does not support:

{% set foo %}1{% endset %}{% include "foo.html.twig" with {foo: foo} %}

Valid as per: https://twig.symfony.com/doc/2.x/tags/include.html


The latter include tag is more popular in certain projects as the include function is then only called when trying to assign the inclusion result to a variable. When trying to output the include result, the tag syntax is preferred.

So please support both syntaxes as they are both valid.

You can add these lines to FunctionalTest.php:150 to check for the failure:

['{% set foo %}1{% endset %}{% include "foo.html.twig" with {foo: foo} %}', null],
['{% set foo %}1{% endset %}{% include "foo.html.twig" with {foo: foo} only %}', null],

False positive no space before "("

The following code gives a false positive:

{% block title ('page.title.' ~ type)|trans %}

The error: ERROR There should be no space before "(".

Error filter function

Hello,

I'm using the v3.2.2 twigcs library and i think find a problem.

For example:
{% set sizes = [34, 36, 38, 40, 42] %}
{{ sizes|filter(v => v > 38)|join(', ') }}

When execute twigcs i receive the following error:

ERROR There should be 1 space(s) before ">".

Obviously I can't separate the characters ( => ) because otherwise I get twig error.

Add JUnit reporter

It would be helpful to have such a reporter when the sniffer is running in CI.

errorformat for vim's syntastic

Hi.

I'm trying to make twigcs work with vim's syntastic. Although I had no problem adding the syntax checker, syntastic requires every warning/error line reported to include the file name.

twigcs' output only shows the file name right before the list of errors for that particular file. Is there any way to change that behavior to include the file name at the beginning of every warning/error reported?

Crash on non-closed ternary operator

Putting

['{% include "file" with {foo: bar ? baz } %}', null]

in the fixtures gives a crash because it can't find the else-part of the ternary.

Fixed by adding

            if ($token->getType() === \Twig_Token::EOF_TYPE) {
                return;
            }

to the seekTernaryElse in TernarySpacing.php, but I'm not sure this is the cleanest way to do it.

UnusedMacro rule is triggering an error about unexpected end of template

Here is the template triggering this issue:

{% extends 'WebBundle:Space:layout.html.twig' %}
{% from _self import folder_breadcrumb %}

{% block title %}
    {{ 'file.title.files'|trans }}
    - {{ space.name }}
{% endblock %}

{% block heading %}{{ 'space.heading.file_library'|trans }}{% endblock %}

{% block content %}
    {% if widgets is not empty %}
        <div class="row">
            <div class="col-xs-12 col-lg-8">
                {{ block('main_content') }}
            </div>
            {% include 'WebBundle:Space:right_column.html.twig' with {widgets: widgets} only %}
        </div>
    {% else %}
        {{ block('main_content') }}
    {% endif %}
{% endblock %}

{% block main_content %}
    {% set is_search = is_search|default(false) %}
    <div data-widget="list-search">
        <div class="row spacer-outer-bottom">
            {% set can_create_file = is_granted('CREATE_FILE', space) %}
            {% if can_create_file %}
                <div class="col-xs-7">
                    <div class="btn-group">
                        <button type="button" class="btn btn-sm button-info text-uppercase dropdown-toggle" data-toggle="dropdown">
                            <i class="fa fa-gears"></i> {{ 'file.menu.create'|trans }} <span class="caret"></span>
                        </button>
                        {% set menu = knp_menu_get('file/manage', [], {space: space}) %}
                        {{ knp_menu_render(menu) }}
                    </div>
                </div>
            {% endif %}
            <div class="{{ not can_create_file ? 'col-xs-offset-7 ' }}col-xs-5">

                <form action="{{ path('file_search', {space: space.id}) }}" method="GET" class="js-list-search-form">
                    <div class="input-group input-group-sm input-group-rounded">
                        <input type="search" name="q" autocomplete="off" class="form-control" {% if term is not empty %}value="{{ term }}"{% endif %}>
                        <span class="input-group-btn">
                            <button type="submit" class="btn btn-default"><i class="fa fa-search"></i></button>
                        </span>
                    </div>
                </form>
            </div>
        </div>
        <div class="js-list-search-container">

            {% if is_search %}
                {% include 'WebBundle:Space/File:searchList.html.twig' with {view: view, files: files, file_versions: file_versions, folders: folders, space: space, folders_data: folders_data} only %}
            {% else %}
                <ol class="breadcrumb breadcrumb-flat spacer-outer-bottom-tiny">
                    {{ folder_breadcrumb(view, space, current_folder, 3) }}
                </ol>

                {% if view == 'list' %}
                    {% include 'WebBundle:Space/File:listMixed.html.twig' with {view: view, files: files, file_versions: file_versions, folders: folders, folders_data: folders_data, current_folder: current_folder, space: space} only %}
                {% elseif view == 'grid' %}
                    {% include 'WebBundle:Space/File:gridMixed.html.twig' with {view: view, files: files, file_versions: file_versions, folders: folders, folders_data: folders_data, current_folder: current_folder, space: space} only %}
                {% endif %}
            {% endif %}
        </div>
    </div>
{% endblock %}

{% macro folder_breadcrumb(view, space, folder, limit = null, level = 0) %}
    {% from _self import folder_breadcrumb %}

    {% if folder is null %}
        <li><a href="{{ path('file_list', {space: space.id, view: view}) }}">{{ 'file.breadcrumb.file_library'|trans }}</a></li>
    {% elseif level is not null and level == limit %}
        {{ folder_breadcrumb(view, space, null, limit, level + 1) }}
        <li>...</li>
    {% elseif level == 0 %}
        {{ folder_breadcrumb(view, space, folder.parent, limit, level + 1) }}
        <li>{{ folder.name }}</li>
    {% else %}
        {{ folder_breadcrumb(view, space, folder.parent, limit,  level + 1) }}
        <li><a href="{{ path('file_list_folder', {space: space.id, folder: folder.id, view: view}) }}">{{ folder.name }}</a></li>
    {% endif %}
{% endmacro %}

The syntax of the template is valid for Twig. Only your linter breaks on it.

Support extended white space control operators in Twig templates

Those have been added recently.
twigphp/Twig#2925

Example:

  {%~ if foo ~%}
Test
  {%~ endif ~%}

The above code produces the following Twigcs violations.

  • ERROR There should be 1 space(s) after opening a block.
  • ERROR There should be 1 space(s) before closing a block.
  • ERROR There should be 1 space(s) before "~".
  • ERROR There should be 1 space(s) after "~".
  • ERROR There should be 1 space(s) after opening a block.
  • ERROR There should be 1 space(s) before closing a block.
  • ERROR There should be 1 space(s) before "~".
  • ERROR There should be 1 space(s) after "~".

Variable usage not detected when using include as a function

When using the following snippet :

{% set icon %}
    {{ block('svg_icon') }}
{% endset %}

{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: true, icon: icon }) }}

A false positive is generated : WARNING Unused variable "icon".

Code standard fixer

Salut !

Nice Twig linter. Would be great to have a coding standards fixer like phpcbf or php-cs-fixer.

Add support for PHP 7.3

I'm not sure if it's an issue with twigcs per se or with one of its dependencies, but I'm getting an error when trying to install it because the version of friendsofphp/php-cs-fixer something is using isn't up to date.

Here's the log in case it's of any help:

composer global require allocine/twigcs
Changed current directory to /Users/nestor/.composer
Using version ^3.1 for allocine/twigcs
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - friendsofphp/php-cs-fixer v2.11.1 requires php ^5.6 || >=7.0 <7.3 -> your PHP version (7.3.0) does not satisfy that requirement.
    - friendsofphp/php-cs-fixer v2.11.1 requires php ^5.6 || >=7.0 <7.3 -> your PHP version (7.3.0) does not satisfy that requirement.
    - friendsofphp/php-cs-fixer v2.11.1 requires php ^5.6 || >=7.0 <7.3 -> your PHP version (7.3.0) does not satisfy that requirement.
    - Installation request for friendsofphp/php-cs-fixer (locked at v2.11.1, required as ^2.11) -> satisfiable by friendsofphp/php-cs-fixer[v2.11.1].


Installation failed, reverting ./composer.json to its original content.

Fatal error: Uncaught Error: Class 'Allocine\Twigcs\Compatibility\Twig_Error_Syntax'

Mac OS 10.13.3 - PHP 7.1.8

/.bash-profile:
export PATH=
/.composer/vendor/bin:$PATH
(Sorry I don't know how to stop the markdown)

MBP-de-James:templates james$ twigcs lint .
PHP Fatal error:  Uncaught Error: Class 'Allocine\Twigcs\Compatibility\Twig_Error_Syntax' not found in /Users/james/.composer/vendor/allocine/twigcs/src/Compatibility/TwigLexer.php:255
Stack trace:
#0 /Users/james/.composer/vendor/allocine/twigcs/src/Lexer.php(38): Allocine\Twigcs\Compatibility\TwigLexer->lexExpression()
#1 /Users/james/.composer/vendor/allocine/twigcs/src/Lexer.php(53): Allocine\Twigcs\Lexer->lexExpression()
#2 /Users/james/.composer/vendor/allocine/twigcs/src/Compatibility/TwigLexer.php(111): Allocine\Twigcs\Lexer->lexBlock()
#3 /Users/james/.composer/vendor/twig/twig/lib/Twig/Environment.php(512): Allocine\Twigcs\Compatibility\TwigLexer->tokenize(Object(Twig_Source))
#4 /Users/james/.composer/vendor/allocine/twigcs/src/Console/LintCommand.php(52): Twig_Environment->tokenize(Object(Twig_Source))
#5 /Users/james/.composer/vendor/symfony/console/Command/Command.php(264): Allocine\Twigcs\Console\LintCommand->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\Conso in /Users/james/.composer/vendor/allocine/twigcs/src/Compatibility/TwigLexer.php on line 255

Fatal error: Uncaught Error: Class 'Allocine\Twigcs\Compatibility\Twig_Error_Syntax' not found in /Users/james/.composer/vendor/allocine/twigcs/src/Compatibility/TwigLexer.php on line 255

Error: Class 'Allocine\Twigcs\Compatibility\Twig_Error_Syntax' not found in /Users/james/.composer/vendor/allocine/twigcs/src/Compatibility/TwigLexer.php on line 255

Call Stack:
    0.0003     352928   1. {main}() /Users/james/.composer/vendor/allocine/twigcs/bin/twigcs:0
    0.0105    1376384   2. Allocine\Twigcs\Console\Application->run() /Users/james/.composer/vendor/allocine/twigcs/bin/twigcs:13

Array rule

Hi,

In a Twig template, I have something like:

{% for item in ['one', 'two'] if attribute(_context, item)) is not empty %}
{% endfor %}

Twigcs complains: ERROR There should be no space after "]".

But I think nothing's wrong is this syntax?

Tests should be moved outside src

currently, tests being in src are autoloadable by projects using this library as a dependency. It would be better to move them in a separate folder (tests is a common name) to avoid that.

Indentation checking

We should create a new rule about indentation checking. The official ruleset states:

Indent your code inside tags (use the same indentation as the one used for the target language of the rendered template)

But I also noticed a lot of people prefer to do:

<ul>
{% for a in 1..2 %}
    <li>{{ a }}</li>
{% endfor %}
</ul>

So the final html is indented as if there were no twig.

My take on this would be to create a rule that defaults to the official coding standard but has an option to tolerate that twig tags directly inside html code can "skip" one indentation level.

Maximum function nesting level reached

FWIW I've got xdebug 2.8.0, but I don't think this issue is specific to that version.

This is the ruleset in place:

$configurator = new RulesetConfigurator();
$builder = new RulesetBuilder($configurator);

$configurator->setTagSpacingPattern('{% expr %}');
$configurator->setPrintStatementSpacingPattern('{{ expr }}');
$configurator->setEmptyParenthesesSpacingPattern('()');
$configurator->setParenthesesSpacingPattern('(expr)');
$configurator->setListSpacingPattern('expr, expr');
$configurator->setArraySpacingPattern('[expr]');
$configurator->setEmptyArraySpacingPattern('[]');
$configurator->setHashSpacingPattern('{key: expr, key: expr}');
$configurator->setEmptyHashSpacingPattern('{}');
$configurator->setUnaryOpSpacingPattern('op expr');
$configurator->setBinaryOpSpacingPattern('expr op expr');
$configurator->setRangeOpSpacingPattern('expr..expr');
$configurator->setTernarySpacingPattern('expr ? expr : expr||expr ?: expr');

return [
    new Rule\RegEngineRule(Violation::SEVERITY_ERROR, $builder->build()),
];

And this is the template:

{% set
    map = {
        a: 'a',
        b: 'b',
        c: 'c',
        d: 'd',
        e: 'e',
        f: 'f',
        g: 'g',
        h: 'h',
        i: 'i',
        j: 'j',
        k: 'k',
        l: 'l',
        m: 'm',
        n: 'n',
        o: 'o',
        p: 'p',
        r: 'r'
    }
%}

The output is

PHP Fatal error: Uncaught Error: Maximum function nesting level of '256' reached, aborting!

If I omit just one element from the map, like so:

{% set
    map = {
        a: 'a',
        b: 'b',
        c: 'c',
        d: 'd',
        e: 'e',
        f: 'f',
        g: 'g',
        h: 'h',
        i: 'i',
        j: 'j',
        k: 'k',
        l: 'l',
        m: 'm',
        n: 'n',
        o: 'o',
        p: 'p'
    }
%}

Then the output is:

l.1 c.6 : ERROR There should be 1 space after the "set".
1 violation(s) found

Additionally, if I don't omit any items, but change the indentation, like so:

{% set
map = {
    a: 'a',
    b: 'b',
    c: 'c',
    d: 'd',
    e: 'e',
    f: 'f',
    g: 'g',
    h: 'h',
    i: 'i',
    j: 'j',
    k: 'k',
    l: 'l',
    m: 'm',
    n: 'n',
    o: 'o',
    p: 'p',
    r: 'r'
}
%}

then the output is:

No violation found.

In addition, if I run the script with xdebug.max_nesting_level=300, then the fatal error will not occur.

False positive "unused variable" when using block execution instead of include.

I use a block to declare a repetitive code in some loops.
For each loop, one var is set and used in the this block.
Twigcs trigger me a warning saying that my var is unused.

Exemple:

{% block repeated_content_block %} {% include my_module with { some_params, my_var } %} {% endblock %}

{% for item in something %} {% set my_var = loop.index %} {{ block("repeated_content_block") }} {% endfor %}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.