Public Access
feat(core): add SourceResolver for backwards-compatible src/ → source/ migration
Introduces SourceResolver utility class with source/ → src/ → htdocs/ fallback chain, replacing hardcoded src/ references across 28 files. This enables renaming root-level src/ to source/ in all repos while maintaining backwards compatibility during the transition. Phase 1: New lib/Enterprise/SourceResolver.php with resolve(), resolveAbsolute(), globSource(), findUnderSource(), warnIfLegacy() Phase 2: Updated 19 CLI/deploy tools to use SourceResolver Phase 3: Updated 7 validator/lib files (McpServerPlugin, PackageBuilder, RepositorySynchronizer, auto_detect_platform, check_dolibarr_module, check_client_theme, check_structure) Authored-by: Moko Consulting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,7 @@ declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use MokoEnterprise\CliFramework;
|
||||
use MokoEnterprise\{CliFramework, SourceResolver};
|
||||
|
||||
/**
|
||||
* Validates client theme packages that deliver CSS, JS, and images
|
||||
@@ -44,17 +44,17 @@ class CheckClientTheme extends CliFramework
|
||||
/** Recommended XML elements. */
|
||||
private const RECOMMENDED_ELEMENTS = ['updateservers', 'scriptfile', 'description', 'fileset'];
|
||||
|
||||
/** Required theme CSS files relative to repo root. */
|
||||
/** Required theme CSS files relative to the source directory. */
|
||||
private const REQUIRED_THEME_FILES = [
|
||||
'src/media/templates/site/mokoonyx/css/theme/light.custom.css',
|
||||
'src/media/templates/site/mokoonyx/css/theme/dark.custom.css',
|
||||
'media/templates/site/mokoonyx/css/theme/light.custom.css',
|
||||
'media/templates/site/mokoonyx/css/theme/dark.custom.css',
|
||||
];
|
||||
|
||||
/** Optional but expected files. */
|
||||
/** Optional but expected files (paths prefixed with ~ are relative to source dir). */
|
||||
private const EXPECTED_FILES = [
|
||||
'src/media/templates/site/mokoonyx/css/user.css',
|
||||
'src/media/templates/site/mokoonyx/js/user.js',
|
||||
'src/script.php',
|
||||
'~media/templates/site/mokoonyx/css/user.css',
|
||||
'~media/templates/site/mokoonyx/js/user.js',
|
||||
'~script.php',
|
||||
'updates.xml',
|
||||
];
|
||||
|
||||
@@ -81,10 +81,12 @@ class CheckClientTheme extends CliFramework
|
||||
|
||||
// ── Manifest ──────────────────────────────────────────
|
||||
$this->section('Manifest validation');
|
||||
$manifest = $path . '/src/templateDetails.xml';
|
||||
$srcName = SourceResolver::resolve($path);
|
||||
SourceResolver::warnIfLegacy($path);
|
||||
$manifest = $path . "/{$srcName}/templateDetails.xml";
|
||||
|
||||
if (!is_file($manifest)) {
|
||||
$this->status(false, 'Missing src/templateDetails.xml');
|
||||
$this->status(false, "Missing {$srcName}/templateDetails.xml");
|
||||
$this->printSummary(0, 1, $this->elapsed());
|
||||
return 1;
|
||||
}
|
||||
@@ -144,28 +146,36 @@ class CheckClientTheme extends CliFramework
|
||||
// ── Required files ────────────────────────────────────
|
||||
$this->section('Required files');
|
||||
foreach (self::REQUIRED_THEME_FILES as $file) {
|
||||
$full = $path . '/' . $file;
|
||||
$full = "{$path}/{$srcName}/{$file}";
|
||||
if (is_file($full)) {
|
||||
$this->status(true, basename($file));
|
||||
} else {
|
||||
$this->status(false, "Missing: {$file}");
|
||||
$this->status(false, "Missing: {$srcName}/{$file}");
|
||||
$errors++;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (self::EXPECTED_FILES as $file) {
|
||||
$full = $path . '/' . $file;
|
||||
// Paths prefixed with ~ are relative to source dir
|
||||
if (str_starts_with($file, '~')) {
|
||||
$relFile = substr($file, 1);
|
||||
$full = "{$path}/{$srcName}/{$relFile}";
|
||||
$display = "{$srcName}/{$relFile}";
|
||||
} else {
|
||||
$full = "{$path}/{$file}";
|
||||
$display = $file;
|
||||
}
|
||||
if (is_file($full)) {
|
||||
$this->status(true, basename($file));
|
||||
} else {
|
||||
$this->warning("Missing: {$file}");
|
||||
$this->warning("Missing: {$display}");
|
||||
$warns++;
|
||||
}
|
||||
}
|
||||
|
||||
// ── PHP syntax ────────────────────────────────────────
|
||||
$this->section('PHP syntax');
|
||||
$phpFiles = glob($path . '/src/*.php') ?: [];
|
||||
$phpFiles = glob("{$path}/{$srcName}/*.php") ?: [];
|
||||
foreach ($phpFiles as $phpFile) {
|
||||
$output = [];
|
||||
$ret = 0;
|
||||
@@ -179,20 +189,20 @@ class CheckClientTheme extends CliFramework
|
||||
}
|
||||
}
|
||||
if (empty($phpFiles)) {
|
||||
$this->warning('No PHP files in src/');
|
||||
$this->warning("No PHP files in {$srcName}/");
|
||||
}
|
||||
|
||||
// ── CSS validation ────────────────────────────────────
|
||||
$this->section('CSS validation');
|
||||
$cssFiles = array_merge(
|
||||
glob($path . '/src/media/templates/site/mokoonyx/css/theme/*.css') ?: [],
|
||||
glob($path . '/src/media/templates/site/mokoonyx/css/*.css') ?: [],
|
||||
glob("{$path}/{$srcName}/media/templates/site/mokoonyx/css/theme/*.css") ?: [],
|
||||
glob("{$path}/{$srcName}/media/templates/site/mokoonyx/css/*.css") ?: [],
|
||||
);
|
||||
foreach ($cssFiles as $cssFile) {
|
||||
$css = (string) file_get_contents($cssFile);
|
||||
$open = substr_count($css, '{');
|
||||
$close = substr_count($css, '}');
|
||||
$name = str_replace($path . '/src/', '', $cssFile);
|
||||
$name = str_replace("{$path}/{$srcName}/", '', $cssFile);
|
||||
|
||||
if ($open !== $close) {
|
||||
$this->status(false, "Unbalanced braces in {$name} (open: {$open}, close: {$close})");
|
||||
@@ -241,7 +251,7 @@ class CheckClientTheme extends CliFramework
|
||||
// ── Image sizes ───────────────────────────────────────
|
||||
$this->section('Image optimization');
|
||||
$largeImages = 0;
|
||||
$imageDir = $path . '/src/images';
|
||||
$imageDir = "{$path}/{$srcName}/images";
|
||||
if (is_dir($imageDir)) {
|
||||
$iter = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($imageDir, \FilesystemIterator::SKIP_DOTS)
|
||||
|
||||
Reference in New Issue
Block a user