aboutsummaryrefslogtreecommitdiffhomepage
path: root/scripts/plugin-class-classifier/src/Lists.php
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/plugin-class-classifier/src/Lists.php')
-rw-r--r--scripts/plugin-class-classifier/src/Lists.php84
1 files changed, 84 insertions, 0 deletions
diff --git a/scripts/plugin-class-classifier/src/Lists.php b/scripts/plugin-class-classifier/src/Lists.php
new file mode 100644
index 00000000..7e544a88
--- /dev/null
+++ b/scripts/plugin-class-classifier/src/Lists.php
@@ -0,0 +1,84 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Shirabe\PluginClassifier;
+
+/**
+ * The three versioned exception lists. Formats are line-based; `#` starts a
+ * comment, blank lines are skipped.
+ *
+ * two-world.list one namespace prefix (or exact FQCN) per line
+ * static-state.list "FQCN memo-cache|seed-once|needs-sync" per line
+ * overrides.list "FQCN category reason..." per line
+ */
+final class Lists
+{
+ /** @var list<string> */
+ public array $twoWorldPrefixes = [];
+
+ /** @var array<string, string> FQCN => 'memo-cache' | 'seed-once' | 'needs-sync' */
+ public array $staticDispositions = [];
+
+ /** @var array<string, array{category: string, reason: string}> */
+ public array $overrides = [];
+
+ public static function load(string $dir): self
+ {
+ $lists = new self();
+
+ foreach (self::lines("$dir/two-world.list") as $line) {
+ $lists->twoWorldPrefixes[] = $line;
+ }
+
+ foreach (self::lines("$dir/static-state.list") as $line) {
+ $parts = preg_split('/\s+/', $line, 2);
+ if (count($parts) !== 2 || !in_array($parts[1], ['memo-cache', 'seed-once', 'needs-sync'], true)) {
+ throw new \RuntimeException("static-state.list: malformed line: $line");
+ }
+ $lists->staticDispositions[$parts[0]] = $parts[1];
+ }
+
+ foreach (self::lines("$dir/overrides.list") as $line) {
+ $parts = preg_split('/\s+/', $line, 3);
+ if (count($parts) !== 3) {
+ throw new \RuntimeException("overrides.list: malformed line (need FQCN, category, reason): $line");
+ }
+ if (!in_array($parts[1], Classifier::CATEGORIES, true)) {
+ throw new \RuntimeException("overrides.list: unknown category {$parts[1]}: $line");
+ }
+ $lists->overrides[$parts[0]] = ['category' => $parts[1], 'reason' => $parts[2]];
+ }
+
+ return $lists;
+ }
+
+ public function isTwoWorld(string $fqcn): bool
+ {
+ foreach ($this->twoWorldPrefixes as $prefix) {
+ if ($fqcn === $prefix || str_starts_with($fqcn, rtrim($prefix, '\\') . '\\')) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /** @return list<string> */
+ private static function lines(string $path): array
+ {
+ if (!is_file($path)) {
+ throw new \RuntimeException("missing exception list: $path");
+ }
+ $out = [];
+ foreach (file($path, FILE_IGNORE_NEW_LINES) as $line) {
+ $line = trim($line);
+ if ($line === '' || str_starts_with($line, '#')) {
+ continue;
+ }
+ $out[] = $line;
+ }
+
+ return $out;
+ }
+}