Skip to content

Commit 6c7279b

Browse files
authored
Merge pull request #3 from smnandre/feat/metrics-dimensions
Rework Dimension Metrics & Add Charts
2 parents ddd1540 + ee25326 commit 6c7279b

File tree

87 files changed

+7600
-2582
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+7600
-2582
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ endef
2929
GIT_VERSION := $(shell git describe --tags --abbrev=0 2>/dev/null || echo "dev-main")
3030
PHP_VERSION := $(shell php -r 'echo PHP_VERSION;' 2>/dev/null || echo "n/a")
3131
PROJECT_NAME := TWIG METRICS
32-
REPO_URL := https://github.com/smnandre/twig-metrics
32+
REPO_URL := https://github.com/smnandre/twigmetrics
3333

3434
about:
3535
@echo "┌───────────────────────────── 🌿 ────────────────────────────────┐"; \

README.md

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ $ bin/twigmetrics analyze templates/
4646

4747

4848
╭─ Template Files ─────╮ ╭─ Logical Comp... ────╮ ╭─ Twig Callables ─────╮
49-
│ ● ● ● ● ○ ○ C │ │ ● ● ● ● ● A+ │ │ ● ● ● ● ● A+
49+
│ ● ● ● ● ○ ○ C │ │ ● ● ● ● ● B │ │ ● ● ● ● ● B
5050
╰──────────────────────╯ ╰──────────────────────╯ ╰──────────────────────╯
5151

5252
╭─ Code Style ─────────╮ ╭─ Architecture ───────╮ ╭─ Maintainability ────╮
53-
│ ● ● ● ● ● A+ │ │ ● ● ● ● C │ │ ● ● ● ● ● ● A+ │
53+
│ ● ● ● ● ● C │ │ ● ● ● ● B │ │ ● ● ● ● ● ● A+ │
5454
╰──────────────────────╯ ╰──────────────────────╯ ╰──────────────────────╯
5555
```
5656

@@ -92,10 +92,10 @@ vendor/bin/twigmetrics path/to/templates
9292
```
9393
╭─ Template Files ───────────────────────────────────────────────────────────╮
9494
│ │
95-
│ Templates ................. 188 Directories ................ 19
96-
Total Lines ............ 11,204 Avg Lines/Template ....... 59.6
97-
Characters ............. 503.8k Chars/Template .......... 2,680
98-
Dir Depth Avg ............. 1.6 File Size CV % .......... 76.3%
95+
Total Templates ........... 188 Total Lines .............. 11,213
96+
Average Lines/File ....... 59.6 Median Lines ................. 48
97+
Size Coefficient (CV) .... 0.77 Gini Index ................ 0.380
98+
Directories ................ 19 Characters ............... 503.8k
9999
│ │
100100
╰────────────────────────────────────────────────────────────────────────────╯
101101
```
@@ -105,10 +105,9 @@ vendor/bin/twigmetrics path/to/templates
105105
```
106106
╭─ Logical Complexity ───────────────────────────────────────────────────────╮
107107
│ │
108-
│ Avg Complexity ............ 8.3 Max Complexity ............. 79 │
109-
│ Avg Depth ................. 1.2 Max Depth ................... 6 │
110-
│ IFs/Template .............. 1.3 FORs/Template ............. 0.6 │
111-
│ Nested Control Depth ........ 6 │
108+
│ Avg Complexity ............. 8.3 Max Complexity .............. 79 │
109+
│ Avg Depth .................. 1.2 Max Depth .................... 6 │
110+
│ IFs/Template ............... 1.3 FORs/Template .............. 0.6 │
112111
│ │
113112
╰────────────────────────────────────────────────────────────────────────────╯
114113
```
@@ -118,9 +117,9 @@ vendor/bin/twigmetrics path/to/templates
118117
```
119118
╭─ Twig Callables ───────────────────────────────────────────────────────────╮
120119
│ │
121-
Funcs/Template ............ 2.9 Filters/Template ......... 18.9
122-
Vars/Template ............ 13.5 Unique Funcs ............... 23
123-
Unique Filters ............. 31 Macros Defined .............. 5
120+
Total Calls ............. 4,632 Unique Functions ............. 23
121+
Unique Filters ............. 32 Unique Tests .................. 7
122+
Funcs/Template ............ 2.9 Filters/Template ........... 18.9
124123
│ │
125124
╰────────────────────────────────────────────────────────────────────────────╯
126125
```
@@ -130,10 +129,10 @@ vendor/bin/twigmetrics path/to/templates
130129
```
131130
╭─ Code Style ───────────────────────────────────────────────────────────────╮
132131
│ │
133-
│ Avg Line Length .......... 41.0 Comments/Template ......... 0.6
134-
Comment Ratio ............ 1.0% Trail Spaces/Line ........ 0.00
135-
Empty Lines % ............ 8.2% Formatting Score ......... 92.7
136-
Indent Consistency % ... 100.0% Naming Conv. Score % .... 97.5%
132+
Avg Line Length ........... 41.0 Max Line Length ............ 217
133+
Indent Consistency ...... 100.0% P95 Length ................. 217
134+
Consistency Score ........ 92.7% Style Violations ........... 128
135+
Comments/Template .......... 0.6 Mixed Indentation ............ 0
137136
│ │
138137
╰────────────────────────────────────────────────────────────────────────────╯
139138
```
@@ -143,9 +142,9 @@ vendor/bin/twigmetrics path/to/templates
143142
```
144143
╭─ Architecture ─────────────────────────────────────────────────────────────╮
145144
│ │
146-
Extends/Template ......... 0.22 Includes/Template ........ 0.57
147-
Embeds/Template .......... 0.04 Imports/Template ......... 0.00
148-
Avg Inherit Depth ......... 0.2 Standalone Files .......... 122
145+
Imports/Template ......... 0.00 Extends/Template ........... 0.22
146+
Avg Inherit Depth ......... 0.2 Includes/Template .......... 0.57
147+
Embeds/Template .......... 0.04 Blocks/Template ............ 1.13
149148
│ │
150149
╰────────────────────────────────────────────────────────────────────────────╯
151150
```
@@ -155,9 +154,9 @@ vendor/bin/twigmetrics path/to/templates
155154
```
156155
╭─ Maintainability ──────────────────────────────────────────────────────────╮
157156
│ │
158-
Large Templates (>200L) ..... 4 High Complexity (>20) ...... 17
159-
Deep Nesting (>5) ........... 1 Empty Templates ............. 0
160-
Standalone ................ 122 Risk Score .................. A
157+
Empty Lines Ratio ....... 10.0% MI Average ................ 107.2
158+
MI Median ............... 106.7 Comment Density ............ 1.3%
159+
High Risk ................... 3 Medium Risk .................. 40
161160
│ │
162161
╰────────────────────────────────────────────────────────────────────────────╯
163162
```

bin/twigmetrics

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ foreach ($possibleFiles as $possibleFile) {
1717
}
1818

1919
if (null === $file) {
20-
throw new \RuntimeException('Unable to locate autoload.php file.');
20+
throw new RuntimeException('Unable to locate autoload.php file.');
2121
}
2222

2323
require_once $file;

src/Analyzer/BatchAnalyzer.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@ public function analyze(array $files): BatchAnalysisResult
6060

6161
$dependencyGraph = $this->buildDependencyGraph($results);
6262

63-
$enhancedResults = $this->enhanceWithCrossTemplateInsights($results, $dependencyGraph);
63+
$augmentedResults = $this->addCrossTemplateInsights($results, $dependencyGraph);
6464

6565
$totalTime = microtime(true) - $startTime;
6666

67-
return new BatchAnalysisResult($enhancedResults, $dependencyGraph, $totalTime, $errors);
67+
return new BatchAnalysisResult($augmentedResults, $dependencyGraph, $totalTime, $errors);
6868
}
6969

7070
/**
@@ -95,13 +95,13 @@ private function buildDependencyGraph(array $results): array
9595
*
9696
* @return AnalysisResult[]
9797
*/
98-
private function enhanceWithCrossTemplateInsights(array $results, array $dependencyGraph): array
98+
private function addCrossTemplateInsights(array $results, array $dependencyGraph): array
9999
{
100100
$referenceCounter = $this->calculateReferenceFrequency($dependencyGraph);
101101
$this->analyzeBlockUsage($results);
102102
$architecturalRoles = $this->determineArchitecturalRoles($results, $referenceCounter);
103103

104-
$enhancedResults = [];
104+
$augmented = [];
105105
foreach ($results as $result) {
106106
$templatePath = $result->getRelativePath();
107107
$metrics = $result->getData();
@@ -114,10 +114,10 @@ private function enhanceWithCrossTemplateInsights(array $results, array $depende
114114

115115
$metrics['potential_issues'] = $this->identifyPotentialIssues($metrics);
116116

117-
$enhancedResults[] = new AnalysisResult($result->file, $metrics, $result->analysisTime);
117+
$augmented[] = new AnalysisResult($result->file, $metrics, $result->analysisTime);
118118
}
119119

120-
return $enhancedResults;
120+
return $augmented;
121121
}
122122

123123
/**

src/Analyzer/BlockUsageAnalyzer.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TwigMetrics\Analyzer;
6+
7+
use TwigMetrics\Metric\BlockMetrics;
8+
9+
/**
10+
* @author Simon André <smn.andre@gmail.com>
11+
*/
12+
final class BlockUsageAnalyzer
13+
{
14+
/**
15+
* @param AnalysisResult[] $results
16+
*/
17+
public function analyzeBlockUsage(array $results): BlockMetrics
18+
{
19+
$defined = [];
20+
$used = [];
21+
$orphaned = [];
22+
23+
foreach ($results as $result) {
24+
$blocks = $result->getMetric('provided_blocks') ?? $result->getMetric('blocksDefinitions') ?? [];
25+
if (is_array($blocks)) {
26+
foreach ($blocks as $blockName) {
27+
$defined[$blockName] = ($defined[$blockName] ?? 0) + 1;
28+
}
29+
}
30+
}
31+
32+
foreach ($results as $result) {
33+
$usages = $result->getMetric('used_blocks') ?? $result->getMetric('blocksUsage') ?? [];
34+
if (is_array($usages)) {
35+
foreach ($usages as $blockName) {
36+
$used[$blockName] = ($used[$blockName] ?? 0) + 1;
37+
}
38+
}
39+
}
40+
41+
foreach ($defined as $blockName => $count) {
42+
if (!isset($used[$blockName])) {
43+
$orphaned[] = (string) $blockName;
44+
}
45+
}
46+
47+
$usageCount = count($used);
48+
$definedCount = count($defined);
49+
50+
return new BlockMetrics(
51+
totalDefined: array_sum($defined),
52+
totalUsed: array_sum($used),
53+
orphanedBlocks: $orphaned,
54+
usageRatio: $definedCount > 0 ? $usageCount / $definedCount : 0.0,
55+
averageReuse: $usageCount > 0 ? array_sum($used) / $usageCount : 0.0,
56+
);
57+
}
58+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TwigMetrics\Analyzer;
6+
7+
use TwigMetrics\Metric\SecurityMetrics;
8+
9+
/**
10+
* @author Simon André <smn.andre@gmail.com>
11+
*/
12+
final class CallableSecurityAnalyzer
13+
{
14+
private const RISKY_FUNCTIONS = ['dump', 'eval', 'include_raw'];
15+
private const RISKY_FILTERS = ['raw', 'unsafe'];
16+
17+
/**
18+
* @param AnalysisResult[] $results
19+
*/
20+
public function analyzeSecurityScore(array $results): SecurityMetrics
21+
{
22+
$risks = [];
23+
$score = 100;
24+
25+
foreach ($results as $result) {
26+
$functions = $result->getMetric('functions_detail') ?? [];
27+
$filters = $result->getMetric('filters_detail') ?? [];
28+
29+
if (is_array($functions)) {
30+
foreach ($functions as $func => $count) {
31+
if (in_array((string) $func, self::RISKY_FUNCTIONS, true)) {
32+
$risks[(string) $func] = ($risks[(string) $func] ?? 0) + (int) $count;
33+
$score -= 5;
34+
}
35+
}
36+
}
37+
38+
if (is_array($filters)) {
39+
foreach ($filters as $filter => $count) {
40+
if (in_array((string) $filter, self::RISKY_FILTERS, true)) {
41+
$risks[(string) $filter] = ($risks[(string) $filter] ?? 0) + (int) $count;
42+
$score -= 3;
43+
}
44+
}
45+
}
46+
}
47+
48+
return new SecurityMetrics(
49+
score: max(0, $score),
50+
risks: $risks,
51+
deprecatedCount: $this->countDeprecated($results),
52+
);
53+
}
54+
55+
/**
56+
* @param AnalysisResult[] $results
57+
*/
58+
private function countDeprecated(array $results): int
59+
{
60+
$count = 0;
61+
foreach ($results as $result) {
62+
$deprecated = $result->getMetric('deprecated_callables') ?? 0;
63+
$count += (int) (is_numeric($deprecated) ? $deprecated : 0);
64+
}
65+
66+
return $count;
67+
}
68+
}

0 commit comments

Comments
 (0)