Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Twigcs Laravel Package

friendsoftwig/twigcs

Twigcs is a checkstyle/linter for Twig templates, like phpcs for PHP. Scan template directories for coding standard violations, control exit codes via severity, and exclude paths. Install via Composer or PHIVE and run as a CLI tool.

View on GitHub
Deep Wiki
Context7

RegEngine

The RegEngine is an engine dedicated to fine grained syntax checking. It is mainly used to analyze spacing at the moment. It relies on 3 steps :

  • Sanitization: it transforms every string in a chain of A of the same length. {% set foo = '(bar)' %} become {% set foo = 'AAAAA' %}.
  • Extraction: it creates a hierarchy of expressions by isolating parentheses, hashes and ternaries content.
  • Checking: it parses using regular expressions the hierarchy created during the extraction and flags any violation encountered.

Custom rules using the configurator

The easiest way to customize the Regengine inside your custom ruleset is to use the configurator :

use FriendsOfTwig\Twigcs\RegEngine\RulesetBuilder;
use FriendsOfTwig\Twigcs\RegEngine\RulesetConfigurator;
use FriendsOfTwig\Twigcs\Rule;
use FriendsOfTwig\Twigcs\Validator\Violation;

class MyRuleset implements RulesetInterface
{
    /**
     * {[@inheritdoc](https://github.com/inheritdoc)}
     */
    public function getRules()
    {
        $configurator = new RulesetConfigurator();

        // from now on, every empty hash must have 2 spaces inside.
        $configurator->setEmptyHashSpacingPattern('{  }');

        // from now on, there will be no space after the coma in a for loop.
        $configurator->setForSpacingPattern('for <key,>item in expr< if expr>');

        $builder = new RulesetBuilder($configurator);

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

For each spacing pattern you must use a particular expression, but you can insert any space between the keyword and they will get enforced. Here's the list of expressions and their defaults:

$configurator->setArraySpacingPattern('[expr]');
$configurator->setBinaryOpSpacingPattern('expr op expr');
$configurator->setRangeOpSpacingPattern('expr..expr');
$configurator->setElseifSpacingPattern('elseif expr');
$configurator->setEmbedSpacingPattern('embed expr< ignore missing>< with list>< only>');
$configurator->setEmptyArraySpacingPattern('[]');
$configurator->setEmptyHashSpacingPattern('{}');
$configurator->setEmptyListWhitespaces(0);
$configurator->setEmptyParenthesesSpacingPattern('()');
$configurator->setForSpacingPattern('for <key, >item in expr< if expr>');
$configurator->setFromSpacingPattern('from expr import expr< as list>');
$configurator->setFuncSpacingPattern('func(expr)');
$configurator->setHashSpacingPattern('{key: expr, key: expr}');
$configurator->setIfSpacingPattern('if expr');
$configurator->setImportSpacingPattern('import expr as list, expr as list');
$configurator->setIncludeSpacingPattern('include expr< ignore missing>< with list>< only>');
$configurator->setListSpacingPattern('expr, expr');
$configurator->setMacroSpacingPattern('macro name(expr)');
$configurator->setParenthesesSpacingPattern('(expr)');
$configurator->setPrintStatementSpacingPattern('{{ expr }}');
$configurator->setPropertySpacingPattern('expr.expr|filter');
$configurator->setSetSpacingPattern('set expr = expr');
$configurator->setSliceSpacingPattern('[expr:expr]');
$configurator->setTagDefaultArgSpacing(1);
$configurator->setTagSpacingPattern('{% expr %}');
$configurator->setTernarySpacingPattern('expr ? expr : expr||expr ?: expr');
$configurator->setUnaryOpSpacingPattern('op expr');
$configurator->setArrowFunctionSpacingPattern('args => expr');
$configurator->setNamedArgsSpacingPattern('name=value, expr');

Fully custom rules : beware of the dragons !

If you are not satisfied with the configurator, you can still fully create your own rules by extending the FriendsOfTwig\Twigcs\RegEngine\RulesetBuilder class. Here's an example of a minimalistic checker that can only check variable declaration and additions :

namespace FriendsOfTwig\Twigcs\RegEngine;

use FriendsOfTwig\Twigcs\RegEngine\Checker\Handler;

class RulesetBuilder
{
    const PATTERNS = [
        ' ' => '\s*',
        '$' => '(?:.|\n|\r)+?',
        '@' => '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*',
        '<' => '{%[~-]?',
        '>' => '[~-]?%}',
    ];

    public function build(): array
    {
        $expr = [];

        $tags = self::using(self::PATTERNS, [
            ['< set @ = $ >',
                // Produces a regexp by replacing each chars by its associated string in RulesetBuilder::PATTERN.
                // If a char is not found, it stays unchanged.
                //
                // The regexp for this pattern is: {%[~-]?(\s*)set(\s*)([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(\s*)=(\s*)(?:.|\n|\r)+?(\s*)[~-]?%}
                Handler::create()
                // The expression captured by the $ is looped inside the rule checker
                ->delegate('$', 'expr')
                // The expressions captured as whitespace as checked to be exactly of length 1.
                ->enforceSize(' ', 1, 'There should be one space here.'),
                ->attach(function (RuleChecker $ruleChecker, Report $report, array $captures) {
                    foreach ($captures['@'] as $capture) {
                        if ($capture->getText() != 'foo') {
                            $report->addError(new RuleError('Your variable can only be named "foo".', $capture->getOffset(), $capture->getSource()));
                        }
                    }
                })
            ],
            ['$ + $', Handler::create()
                ->delegate('$', 'expr')
                ->enforceSize(' ', 1, 'There should be one space here.'),
            ],
        ]);

        return ['expr' => $tags];
    }
}
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
calmfox/watch-sylius
damienfern/grpc-symfony-bundle
atoolo/index-bundle
atoolo/genai-bundle
coprotoai/laravel-ticket
davidjln/llm-carbon-bundle
cryonighter/valid-request-bundle
coolms/taxonomy-bundle
coolms/field-bundle
articulate-orm/symfony
aaix/laravel-tall-architect
ephoto/akeneo-connector
emmanuelballery/eb-plantumlbundle
emielburgman/symfony-visitor-beacon
emielburgman/symfony-visit-storage
emielburgman/symfony-security-headers
emielburgman/symfony-log-viewer
emarref/xdebug-bundle
emarref/pubnub-bundle
elriseio/finance-money-bundle