• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nette / latte / 20076624180

09 Dec 2025 07:53PM UTC coverage: 94.808% (+0.06%) from 94.744%
20076624180

push

github

dg
added LinterExtension for validating filters, functions, classes and methods

50 of 51 new or added lines in 1 file covered. (98.04%)

5478 of 5778 relevant lines covered (94.81%)

0.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.04
/src/Tools/LinterExtension.php
1
<?php
2

3
/**
4
 * This file is part of the Latte (https://latte.nette.org)
5
 * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6
 */
7

8
declare(strict_types=1);
9

10
namespace Latte\Tools;
11

12
use Latte;
13
use Latte\Compiler\Node;
14
use Latte\Compiler\Nodes\Php;
15
use Latte\Compiler\Nodes\Php\Expression;
16
use Latte\Compiler\Nodes\TemplateNode;
17
use Latte\Compiler\NodeTraverser;
18
use Latte\Compiler\Position;
19

20

21
/**
22
 * Linter extension for validating filters, functions, classes and methods.
23
 */
24
final class LinterExtension extends Latte\Extension
25
{
26
        private ?Latte\Engine $engine = null;
27

28

29
        public function beforeCompile(Latte\Engine $engine): void
1✔
30
        {
31
                $this->engine = $engine;
1✔
32
        }
1✔
33

34

35
        public function getPasses(): array
36
        {
37
                return [
38
                        'linter' => $this->linterPass(...),
1✔
39
                ];
40
        }
41

42

43
        private function linterPass(TemplateNode $node): void
1✔
44
        {
45
                (new NodeTraverser)->traverse($node, function (Node $node) {
1✔
46
                        if ($node instanceof Php\FilterNode) {
1✔
47
                                $this->validateFilter($node);
1✔
48
                        }
49

50
                        if ($node instanceof Expression\FunctionCallNode && $node->name instanceof Php\NameNode) {
1✔
51
                                $this->validateFunction($node);
1✔
52
                        }
53

54
                        if ($node instanceof Expression\NewNode && $node->class instanceof Php\NameNode) {
1✔
55
                                $this->validateClass($node);
1✔
56
                        }
57

58
                        if ($node instanceof Expression\StaticMethodCallNode
1✔
59
                                && $node->class instanceof Php\NameNode
1✔
60
                                && $node->name instanceof Php\IdentifierNode
1✔
61
                        ) {
62
                                $this->validateStaticMethod($node);
1✔
63
                        }
64
                });
1✔
65
        }
1✔
66

67

68
        private function validateFilter(Php\FilterNode $node): void
1✔
69
        {
70
                $name = $node->name->name;
1✔
71
                $filters = $this->engine->getFilters();
1✔
72

73
                if (!isset($filters[$name])) {
1✔
74
                        $this->reportWarning("Unknown filter |$name", $node->position);
1✔
75
                }
76
        }
1✔
77

78

79
        private function validateFunction(Expression\FunctionCallNode $node): void
1✔
80
        {
81
                $name = (string) $node->name;
1✔
82
                $functions = $this->engine->getFunctions();
1✔
83

84
                if (!isset($functions[$name]) && !function_exists($name)) {
1✔
85
                        $this->reportWarning("Unknown function $name()", $node->position);
1✔
86
                }
87
        }
1✔
88

89

90
        private function validateClass(Expression\NewNode $node): void
1✔
91
        {
92
                $className = (string) $node->class;
1✔
93
                if (!class_exists($className)) {
1✔
94
                        $this->reportWarning("Unknown class $className", $node->position);
1✔
95
                }
96
        }
1✔
97

98

99
        private function validateStaticMethod(Expression\StaticMethodCallNode $node): void
1✔
100
        {
101
                $className = (string) $node->class;
1✔
102
                $methodName = $node->name->name;
1✔
103

104
                if (!class_exists($className)) {
1✔
NEW
105
                        $this->reportWarning("Unknown class $className", $node->position);
×
106
                } elseif (!method_exists($className, $methodName)) {
1✔
107
                        $this->reportWarning("Unknown method $className::$methodName()", $node->position);
1✔
108
                }
109
        }
1✔
110

111

112
        private function reportWarning(string $message, ?Position $position): void
1✔
113
        {
114
                $pos = '';
1✔
115
                if ($position) {
1✔
116
                        $pos = ' on line ' . $position->line;
1✔
117
                        if ($position->column) {
1✔
118
                                $pos .= ' at column ' . $position->column;
1✔
119
                        }
120
                }
121
                trigger_error($message . $pos, E_USER_WARNING);
1✔
122
        }
1✔
123
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc