aboutsummaryrefslogtreecommitdiffhomepage
path: root/scripts/plugin-class-classifier/src/Report.php
blob: e24363fe96046536a649c0e95ead2f0d86a2143f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
<?php

declare(strict_types=1);

namespace Shirabe\PluginClassifier;

final class Report
{
    public function __construct(private readonly Classifier $classifier)
    {
    }

    public function writeJson(string $path): void
    {
        $vendor = [];
        foreach ($this->classifier->closure->vendorReachable as $fqcn => $bits) {
            $info = VendorPackages::lookup($fqcn);
            $vendor[] = [
                'fqcn' => $fqcn,
                'package' => $info['package'],
                'category' => $info['category'],
                'direction' => $bits === 3 ? 'both' : ($bits === 1 ? 'provided' : 'consumed'),
            ];
        }
        usort($vendor, static fn (array $a, array $b) => strcmp($a['fqcn'], $b['fqcn']));

        $builtins = array_keys($this->classifier->closure->builtinReachable);
        sort($builtins);

        $vendorPackages = [];
        foreach (VendorPackages::PREFIXES as $prefix => $info) {
            $vendorPackages[$info['package']] = $info['category'];
        }
        ksort($vendorPackages);

        $data = [
            'categories' => $this->countByCategory(),
            'classes' => array_values($this->classifier->rows),
            'vendorPackages' => $vendorPackages,
            'vendorTypes' => $vendor,
            'reachableBuiltins' => $builtins,
            'violations' => $this->classifier->violations,
        ];

        $json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
        if (file_put_contents($path, $json . "\n") === false) {
            throw new \RuntimeException("cannot write $path");
        }
    }

    public function printSummary(): void
    {
        $counts = $this->countByCategory();
        echo "# Plugin boundary classification\n\n";
        echo "| category | classes |\n|---|---|\n";
        foreach ($counts as $category => $count) {
            echo "| $category | $count |\n";
        }

        echo "\n## Reachable surface\n\n";
        foreach (['rust-proxy', 'rust-snapshot', 'contract'] as $category) {
            $names = [];
            foreach ($this->classifier->rows as $row) {
                if ($row['category'] === $category && $row['reachable']) {
                    $names[] = $row['fqcn'] . ($row['direction'] === 'both' ? ' (both)' : '');
                }
            }
            echo '### ' . $category . ' (' . count($names) . ")\n\n";
            foreach ($names as $name) {
                echo "- $name\n";
            }
            echo "\n";
        }

        $overridden = array_filter($this->classifier->rows, static fn (array $r) => isset($r['computedCategory']));
        if ($overridden !== []) {
            echo "## Overridden\n\n";
            foreach ($overridden as $row) {
                echo "- {$row['fqcn']}: {$row['computedCategory']} -> {$row['category']}\n";
            }
            echo "\n";
        }

        if ($this->classifier->violations !== []) {
            echo "## Violations\n\n";
            foreach ($this->classifier->violations as $violation) {
                echo "- $violation\n";
            }
            echo "\n";
        }
    }

    /** @return array<string, int> */
    private function countByCategory(): array
    {
        $counts = array_fill_keys(Classifier::CATEGORIES, 0);
        foreach ($this->classifier->rows as $row) {
            $counts[$row['category']]++;
        }

        return $counts;
    }
}