refactor: Divi-Reiter und divi-check in die Divi-Integration verschoben; CoreIndependenceTest prüft auch Cli, ChangeLog, Pods und die Wurzeldateien, erkennt Alias-Importe und kennt nur noch Plugin.php als Ausnahme
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d0d3488df8
commit
7f9a087b8b
@@ -38,8 +38,11 @@ pauschale Sperre der Divi-Absicherung (2026-09-29) durch eine Freigabe je Fähig
|
|||||||
- **Zustand:** Code-, Signatur- und Konstanten-Prüfungen laufen je Request live. Gecacht wird nur die Mirror-Prüfung
|
- **Zustand:** Code-, Signatur- und Konstanten-Prüfungen laufen je Request live. Gecacht wird nur die Mirror-Prüfung
|
||||||
(Transient `lit_mcp_divi_state`, Format 2: Mirror-Probleme mit Art und Fähigkeiten, ein Tag); ein Eintrag im alten
|
(Transient `lit_mcp_divi_state`, Format 2: Mirror-Probleme mit Art und Fähigkeiten, ein Tag); ein Eintrag im alten
|
||||||
Format zählt als Miss. Ein Divi-Hotfix ohne Versionssprung wird so sofort erkannt.
|
Format zählt als Miss. Ein Divi-Hotfix ohne Versionssprung wird so sofort erkannt.
|
||||||
- **Kern ohne Divi:** `CoreIndependenceTest` erzwingt, dass `Abilities`, `Integrations/{Core,WordPress,Media}`, `Admin`
|
- **Kern ohne Divi:** `CoreIndependenceTest` erzwingt, dass `Abilities`, `Admin`, `ChangeLog`, `Cli`, `Guides`,
|
||||||
(außer `DiviTab`), `Guides` und `Server` nichts aus `Integrations\Divi` importieren.
|
`Integrations/{Core,Media,Pods,WordPress}`, `Server` sowie die Dateien direkt unter `src/` und `src/Integrations/`
|
||||||
|
nichts aus `Integrations\Divi` importieren (auch kein Alias-Import). Einzige Ausnahme ist `Plugin.php` als
|
||||||
|
Composition Root. Die Divi-Oberfläche liegt in der Divi-Integration: `Integrations/Divi/Admin/DiviTab.php` und
|
||||||
|
`Integrations/Divi/Cli/DiviCheckCommand.php`.
|
||||||
|
|
||||||
## Ergänzungen bei der Umsetzung
|
## Ergänzungen bei der Umsetzung
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace LIT\MCP\Admin;
|
namespace LIT\MCP\Integrations\Divi\Admin;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
|
use LIT\MCP\Admin\AdminPostAction;
|
||||||
|
use LIT\MCP\Admin\AdminTab;
|
||||||
|
use LIT\MCP\Admin\SettingsPage;
|
||||||
use LIT\MCP\ChangeLog\ChangeLog;
|
use LIT\MCP\ChangeLog\ChangeLog;
|
||||||
use LIT\MCP\Integrations\Divi\Release\CheckReport;
|
use LIT\MCP\Integrations\Divi\Release\CheckReport;
|
||||||
use LIT\MCP\Integrations\Divi\Release\CheckReportStore;
|
use LIT\MCP\Integrations\Divi\Release\CheckReportStore;
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace LIT\MCP\Cli;
|
namespace LIT\MCP\Integrations\Divi\Cli;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use LIT\MCP\Integrations\Divi\Release\CheckReport;
|
use LIT\MCP\Integrations\Divi\Release\CheckReport;
|
||||||
@@ -7,11 +7,11 @@ namespace LIT\MCP\Integrations\Divi;
|
|||||||
use Closure;
|
use Closure;
|
||||||
use LIT\MCP\Abilities\Ability;
|
use LIT\MCP\Abilities\Ability;
|
||||||
use LIT\MCP\Abilities\ToolAvailability;
|
use LIT\MCP\Abilities\ToolAvailability;
|
||||||
use LIT\MCP\Admin\DiviTab;
|
|
||||||
use LIT\MCP\Admin\SettingsPage;
|
use LIT\MCP\Admin\SettingsPage;
|
||||||
use LIT\MCP\ChangeLog\ChangeLog;
|
use LIT\MCP\ChangeLog\ChangeLog;
|
||||||
use LIT\MCP\Cli\DiviCheckCommand;
|
|
||||||
use LIT\MCP\Integrations\Bootable;
|
use LIT\MCP\Integrations\Bootable;
|
||||||
|
use LIT\MCP\Integrations\Divi\Admin\DiviTab;
|
||||||
|
use LIT\MCP\Integrations\Divi\Cli\DiviCheckCommand;
|
||||||
use LIT\MCP\Integrations\Divi\BlockTree\Parser;
|
use LIT\MCP\Integrations\Divi\BlockTree\Parser;
|
||||||
use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
|
use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
|
||||||
use LIT\MCP\Integrations\Divi\Design\DesignSystemWriter;
|
use LIT\MCP\Integrations\Divi\Design\DesignSystemWriter;
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ declare(strict_types=1);
|
|||||||
namespace LIT\MCP\Integrations\Divi\Release;
|
namespace LIT\MCP\Integrations\Divi\Release;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use LIT\MCP\Admin\DiviTab;
|
|
||||||
use LIT\MCP\Admin\SettingsPage;
|
use LIT\MCP\Admin\SettingsPage;
|
||||||
|
use LIT\MCP\Integrations\Divi\Admin\DiviTab;
|
||||||
use LIT\MCP\Log;
|
use LIT\MCP\Log;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
use WP_REST_Response;
|
use WP_REST_Response;
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ pass "site status: only page-write incompatible (problem and tools named), refus
|
|||||||
# The tab is taken from the settings page filter, as the plugin wires it (with the tools of every integration).
|
# The tab is taken from the settings page filter, as the plugin wires it (with the tools of every integration).
|
||||||
NOTICE=$(wp --user="$ADMIN_LOGIN" eval '$tab = null;
|
NOTICE=$(wp --user="$ADMIN_LOGIN" eval '$tab = null;
|
||||||
foreach (apply_filters(LIT\MCP\Admin\SettingsPage::TABS_FILTER, []) as $candidate) {
|
foreach (apply_filters(LIT\MCP\Admin\SettingsPage::TABS_FILTER, []) as $candidate) {
|
||||||
if ($candidate instanceof LIT\MCP\Admin\DiviTab) {
|
if ($candidate instanceof LIT\MCP\Integrations\Divi\Admin\DiviTab) {
|
||||||
$tab = $candidate;
|
$tab = $candidate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,7 +177,7 @@ TAB=$(wp --user="$ADMIN_LOGIN" eval '
|
|||||||
require_once ABSPATH . "wp-admin/includes/template.php";
|
require_once ABSPATH . "wp-admin/includes/template.php";
|
||||||
$tab = null;
|
$tab = null;
|
||||||
foreach (apply_filters(LIT\MCP\Admin\SettingsPage::TABS_FILTER, []) as $candidate) {
|
foreach (apply_filters(LIT\MCP\Admin\SettingsPage::TABS_FILTER, []) as $candidate) {
|
||||||
if ($candidate instanceof LIT\MCP\Admin\DiviTab) {
|
if ($candidate instanceof LIT\MCP\Integrations\Divi\Admin\DiviTab) {
|
||||||
$tab = $candidate;
|
$tab = $candidate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,7 +198,7 @@ echo "$STATUS" | jq -e '.components[] | select(.id == "divi") | .features | all(
|
|||||||
|| fail "every feature must be released again: $STATUS"
|
|| fail "every feature must be released again: $STATUS"
|
||||||
[ -z "$(wp --user="$ADMIN_LOGIN" eval '$tab = null;
|
[ -z "$(wp --user="$ADMIN_LOGIN" eval '$tab = null;
|
||||||
foreach (apply_filters(LIT\MCP\Admin\SettingsPage::TABS_FILTER, []) as $candidate) {
|
foreach (apply_filters(LIT\MCP\Admin\SettingsPage::TABS_FILTER, []) as $candidate) {
|
||||||
if ($candidate instanceof LIT\MCP\Admin\DiviTab) {
|
if ($candidate instanceof LIT\MCP\Integrations\Divi\Admin\DiviTab) {
|
||||||
$tab = $candidate;
|
$tab = $candidate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,27 +10,37 @@ use RecursiveDirectoryIterator;
|
|||||||
use RecursiveIteratorIterator;
|
use RecursiveIteratorIterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The generic core knows no Divi class: nothing below the CORE_PATHS imports or names a class of
|
* The generic core knows no Divi class: nothing below the CORE_PATHS and none of the CORE_ROOTS files imports or names
|
||||||
* LIT\MCP\Integrations\Divi. Divi plugs in through ports (AbilityGuard, ToolRefusal, BuilderDetector,
|
* a class of LIT\MCP\Integrations\Divi. Divi plugs in through ports (AbilityGuard, ToolRefusal, BuilderDetector,
|
||||||
* MediaUsageSource, EnvironmentComponent, ContentSchema's excluded post types) that Plugin.php – the composition
|
* MediaUsageSource, EnvironmentComponent, ContentSchema's excluded post types) that Plugin.php – the composition
|
||||||
* root, outside these paths – wires up. Divi's own names (et_* …) are DiviBoundaryTest's business, not this test's.
|
* root, the one listed exception – wires up. Divi's own UI (settings tab, WP-CLI command) lives in
|
||||||
|
* Integrations/Divi. Divi's own names (et_* …) are DiviBoundaryTest's business, not this test's.
|
||||||
*/
|
*/
|
||||||
final class CoreIndependenceTest extends TestCase
|
final class CoreIndependenceTest extends TestCase
|
||||||
{
|
{
|
||||||
/** Directories below src/ that must not use Divi classes. */
|
/** Directories below src/ (scanned recursively) that must not use Divi classes. */
|
||||||
private const CORE_PATHS = [
|
private const CORE_PATHS = [
|
||||||
'Abilities',
|
'Abilities',
|
||||||
'Integrations/Core',
|
|
||||||
'Integrations/WordPress',
|
|
||||||
'Integrations/Media',
|
|
||||||
'Admin',
|
'Admin',
|
||||||
|
'ChangeLog',
|
||||||
|
'Cli',
|
||||||
'Guides',
|
'Guides',
|
||||||
|
'Integrations/Core',
|
||||||
|
'Integrations/Media',
|
||||||
|
'Integrations/Pods',
|
||||||
|
'Integrations/WordPress',
|
||||||
'Server',
|
'Server',
|
||||||
];
|
];
|
||||||
|
|
||||||
/** Files inside CORE_PATHS that may use Divi classes, each with its reason. */
|
/** CORE_PATHS that may be absent: no generic WP-CLI command exists yet (Divi's lives in Integrations/Divi/Cli). */
|
||||||
|
private const OPTIONAL_PATHS = ['Cli'];
|
||||||
|
|
||||||
|
/** Directories below src/ whose PHP files directly inside (not below) must not use Divi classes either. */
|
||||||
|
private const CORE_ROOTS = ['', 'Integrations'];
|
||||||
|
|
||||||
|
/** Files of the scan that may use Divi classes, each with its reason. */
|
||||||
private const EXCEPTIONS = [
|
private const EXCEPTIONS = [
|
||||||
'Admin/DiviTab.php' => 'The settings tab "Divi" is Divi UI: release state, admin check and release/withdraw.',
|
'Plugin.php' => 'Composition root: builds DiviIntegration and wires its ports (DiviFeatureGate) into the core.',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function testTheCoreUsesNoDiviClass(): void
|
public function testTheCoreUsesNoDiviClass(): void
|
||||||
@@ -63,7 +73,7 @@ final class CoreIndependenceTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testTheScanFindsImportsQualifiedNamesGroupUsesAndClassStrings(): void
|
public function testTheScanFindsImportsQualifiedNamesGroupUsesAliasesAndClassStrings(): void
|
||||||
{
|
{
|
||||||
$source = <<<'PHP'
|
$source = <<<'PHP'
|
||||||
<?php
|
<?php
|
||||||
@@ -72,11 +82,13 @@ final class CoreIndependenceTest extends TestCase
|
|||||||
$a = \LIT\MCP\Integrations\Divi\Schema\DiviModules::isAvailable();
|
$a = \LIT\MCP\Integrations\Divi\Schema\DiviModules::isAvailable();
|
||||||
$b = 'LIT\\MCP\\Integrations\\Divi\\Design\\DesignSystemReader';
|
$b = 'LIT\\MCP\\Integrations\\Divi\\Design\\DesignSystemReader';
|
||||||
$c = "LIT\\MCP\\Integrations\\Divi\\Library\\LibraryAccess";
|
$c = "LIT\\MCP\\Integrations\\Divi\\Library\\LibraryAccess";
|
||||||
|
use LIT\MCP\Integrations\Divi as D;
|
||||||
PHP;
|
PHP;
|
||||||
|
|
||||||
self::assertSame(
|
self::assertSame(
|
||||||
[
|
[
|
||||||
'Divi\Pages\DiviPages',
|
'Divi\Pages\DiviPages',
|
||||||
|
'LIT\MCP\Integrations\Divi',
|
||||||
'LIT\MCP\Integrations\Divi\Design\DesignSystemReader',
|
'LIT\MCP\Integrations\Divi\Design\DesignSystemReader',
|
||||||
'LIT\MCP\Integrations\Divi\Library\LibraryAccess',
|
'LIT\MCP\Integrations\Divi\Library\LibraryAccess',
|
||||||
'LIT\MCP\Integrations\Divi\Release\ReleaseGate',
|
'LIT\MCP\Integrations\Divi\Release\ReleaseGate',
|
||||||
@@ -114,7 +126,8 @@ final class CoreIndependenceTest extends TestCase
|
|||||||
T_CONSTANT_ENCAPSED_STRING => ltrim(str_replace('\\\\', '\\', substr($token[1], 1, -1)), '\\'),
|
T_CONSTANT_ENCAPSED_STRING => ltrim(str_replace('\\\\', '\\', substr($token[1], 1, -1)), '\\'),
|
||||||
default => '',
|
default => '',
|
||||||
};
|
};
|
||||||
if (preg_match('/^(?:LIT\\\\MCP\\\\Integrations\\\\)?Divi\\\\[A-Za-z0-9_\\\\]+$/', $text) === 1) {
|
$diviClass = '/^(?:LIT\\\\MCP\\\\Integrations\\\\)?Divi\\\\[A-Za-z0-9_\\\\]+$/';
|
||||||
|
if (preg_match($diviClass, $text) === 1 || $text === 'LIT\\MCP\\Integrations\\Divi') {
|
||||||
$names[] = $text;
|
$names[] = $text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,12 +137,44 @@ final class CoreIndependenceTest extends TestCase
|
|||||||
return $names;
|
return $names;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array<string, string> Path below src/ => absolute path of every PHP file in CORE_PATHS. */
|
public function testEveryScannedPathExists(): void
|
||||||
|
{
|
||||||
|
$root = self::root();
|
||||||
|
foreach ([...self::CORE_PATHS, ...self::CORE_ROOTS] as $directory) {
|
||||||
|
if (! in_array($directory, self::OPTIONAL_PATHS, true)) {
|
||||||
|
self::assertDirectoryExists($root . $directory, $directory . ' fehlt – Scan-Liste anpassen');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTheDiviUiLivesInTheDiviIntegration(): void
|
||||||
|
{
|
||||||
|
$files = self::coreFiles();
|
||||||
|
|
||||||
|
self::assertArrayHasKey('Plugin.php', $files, 'root files are scanned');
|
||||||
|
self::assertArrayHasKey('Integrations/IntegrationRegistry.php', $files, 'Integrations root files are scanned');
|
||||||
|
self::assertArrayNotHasKey('Admin/DiviTab.php', $files, 'the Divi tab belongs to Integrations/Divi/Admin');
|
||||||
|
self::assertFileExists(self::root() . 'Integrations/Divi/Admin/DiviTab.php');
|
||||||
|
self::assertFileExists(self::root() . 'Integrations/Divi/Cli/DiviCheckCommand.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function root(): string
|
||||||
|
{
|
||||||
|
return dirname(__DIR__, 3) . '/src/';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, string> Path below src/ => absolute path of every PHP file in CORE_PATHS (recursively) and
|
||||||
|
* directly in CORE_ROOTS.
|
||||||
|
*/
|
||||||
private static function coreFiles(): array
|
private static function coreFiles(): array
|
||||||
{
|
{
|
||||||
$root = dirname(__DIR__, 3) . '/src/';
|
$root = self::root();
|
||||||
$files = [];
|
$files = [];
|
||||||
foreach (self::CORE_PATHS as $directory) {
|
foreach (self::CORE_PATHS as $directory) {
|
||||||
|
if (! is_dir($root . $directory)) {
|
||||||
|
continue; // Only an OPTIONAL_PATHS entry may be missing (testEveryScannedPathExists).
|
||||||
|
}
|
||||||
$iterator = new RecursiveIteratorIterator(
|
$iterator = new RecursiveIteratorIterator(
|
||||||
new RecursiveDirectoryIterator($root . $directory, FilesystemIterator::SKIP_DOTS)
|
new RecursiveDirectoryIterator($root . $directory, FilesystemIterator::SKIP_DOTS)
|
||||||
);
|
);
|
||||||
@@ -139,6 +184,11 @@ final class CoreIndependenceTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
foreach (self::CORE_ROOTS as $directory) {
|
||||||
|
foreach (glob($root . ($directory === '' ? '' : $directory . '/') . '*.php') ?: [] as $path) {
|
||||||
|
$files[substr($path, strlen($root))] = $path;
|
||||||
|
}
|
||||||
|
}
|
||||||
ksort($files);
|
ksort($files);
|
||||||
|
|
||||||
return $files;
|
return $files;
|
||||||
|
|||||||
+2
-2
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace LIT\MCP\Tests\Unit\Admin;
|
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Admin;
|
||||||
|
|
||||||
use Brain\Monkey\Actions;
|
use Brain\Monkey\Actions;
|
||||||
use Brain\Monkey\Functions;
|
use Brain\Monkey\Functions;
|
||||||
use LIT\MCP\Admin\AdminPostAction;
|
use LIT\MCP\Admin\AdminPostAction;
|
||||||
use LIT\MCP\Admin\DiviTab;
|
use LIT\MCP\Integrations\Divi\Admin\DiviTab;
|
||||||
use LIT\MCP\Integrations\Divi\Release\CheckReport;
|
use LIT\MCP\Integrations\Divi\Release\CheckReport;
|
||||||
use LIT\MCP\Integrations\Divi\Release\CheckReportStore;
|
use LIT\MCP\Integrations\Divi\Release\CheckReportStore;
|
||||||
use LIT\MCP\Integrations\Divi\Release\CheckStep;
|
use LIT\MCP\Integrations\Divi\Release\CheckStep;
|
||||||
+2
-2
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace LIT\MCP\Tests\Unit\Cli;
|
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Cli;
|
||||||
|
|
||||||
use Brain\Monkey\Functions;
|
use Brain\Monkey\Functions;
|
||||||
use LIT\MCP\Cli\DiviCheckCommand;
|
use LIT\MCP\Integrations\Divi\Cli\DiviCheckCommand;
|
||||||
use LIT\MCP\Integrations\Divi\Release\CheckReport;
|
use LIT\MCP\Integrations\Divi\Release\CheckReport;
|
||||||
use LIT\MCP\Integrations\Divi\Release\CheckReportStore;
|
use LIT\MCP\Integrations\Divi\Release\CheckReportStore;
|
||||||
use LIT\MCP\Integrations\Divi\Release\CheckStep;
|
use LIT\MCP\Integrations\Divi\Release\CheckStep;
|
||||||
@@ -11,7 +11,7 @@ use LIT\MCP\Abilities\Ability;
|
|||||||
use LIT\MCP\Abilities\ExposurePolicy;
|
use LIT\MCP\Abilities\ExposurePolicy;
|
||||||
use LIT\MCP\Abilities\ToolAvailability;
|
use LIT\MCP\Abilities\ToolAvailability;
|
||||||
use LIT\MCP\Admin\AdminTab;
|
use LIT\MCP\Admin\AdminTab;
|
||||||
use LIT\MCP\Admin\DiviTab;
|
use LIT\MCP\Integrations\Divi\Admin\DiviTab;
|
||||||
use LIT\MCP\Admin\SettingsPage;
|
use LIT\MCP\Admin\SettingsPage;
|
||||||
use LIT\MCP\Integrations\Core\EnvironmentComponent;
|
use LIT\MCP\Integrations\Core\EnvironmentComponent;
|
||||||
use LIT\MCP\Integrations\Divi\DiviBuilderDetector;
|
use LIT\MCP\Integrations\Divi\DiviBuilderDetector;
|
||||||
|
|||||||
Reference in New Issue
Block a user