8258ed804a
Standards Compliance / Secret Scanning (push) Successful in 3s
Standards Compliance / License Header Validation (push) Successful in 4s
Standards Compliance / Repository Structure Validation (push) Successful in 5s
Standards Compliance / Coding Standards Check (push) Failing after 3s
Standards Compliance / Version Consistency Check (push) Successful in 3s
Standards Compliance / Workflow Configuration Check (push) Failing after 2s
Standards Compliance / Documentation Quality Check (push) Successful in 3s
Standards Compliance / README Completeness Check (push) Successful in 3s
Standards Compliance / Git Repository Hygiene (push) Successful in 2s
Standards Compliance / Script Integrity Validation (push) Successful in 4s
Standards Compliance / Line Length Check (push) Failing after 4s
Standards Compliance / File Naming Standards (push) Successful in 2s
Standards Compliance / Insecure Code Pattern Detection (push) Successful in 3s
Standards Compliance / Code Complexity Analysis (push) Successful in 3s
Standards Compliance / Code Duplication Detection (push) Successful in 4s
Standards Compliance / Dead Code Detection (push) Successful in 3s
Standards Compliance / File Size Limits (push) Successful in 2s
CodeQL Security Scanning / Analyze (javascript) (push) Failing after 1m9s
Standards Compliance / Binary File Detection (push) Successful in 4s
CodeQL Security Scanning / Analyze (actions) (push) Failing after 1m11s
Standards Compliance / TODO/FIXME Tracking (push) Successful in 3s
Standards Compliance / Dependency Vulnerability Scanning (push) Successful in 5s
Standards Compliance / Broken Link Detection (push) Successful in 5s
Standards Compliance / Unused Dependencies Check (push) Successful in 7s
Standards Compliance / API Documentation Coverage (push) Successful in 3s
Standards Compliance / Accessibility Check (push) Successful in 3s
Standards Compliance / Performance Metrics (push) Successful in 3s
Standards Compliance / Enterprise Readiness Check (push) Successful in 3s
Standards Compliance / Repository Health Check (push) Successful in 4s
Standards Compliance / Terraform Configuration Validation (push) Successful in 6s
CodeQL Security Scanning / Security Scan Summary (push) Successful in 1s
Standards Compliance / Compliance Summary (push) Successful in 1s
Repo Health / Access control (push) Successful in 1s
Repo Health / Release configuration (push) Failing after 3s
Repo Health / Scripts governance (push) Successful in 3s
Repo Health / Repository health (push) Failing after 3s
Auto-Update SHA Hash / Update SHA-256 Hash in updates.xml (release) Failing after 5s
All files renamed from mokocassiopeia to mokoonyx. Update server points to MokoOnyx repo. Bridge migration removed (clean standalone template). Version reset to 01.00.00. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
166 lines
4.8 KiB
PHP
166 lines
4.8 KiB
PHP
<?php
|
|
/**
|
|
* Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
|
|
*
|
|
* This file is part of a Moko Consulting project.
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
/**
|
|
* CSS/JS minifier — generates .min files from source when dev mode is off,
|
|
* deletes them when dev mode is on.
|
|
*/
|
|
|
|
defined('_JEXEC') or die;
|
|
|
|
class MokoMinifyHelper
|
|
{
|
|
/**
|
|
* Files to minify: source path relative to template media root.
|
|
* The .min variant is derived automatically (template.css → template.min.css).
|
|
*/
|
|
private const CSS_FILES = [
|
|
'css/template.css',
|
|
'css/offline.css',
|
|
'css/editor.css',
|
|
'css/a11y-high-contrast.css',
|
|
'css/theme/light.standard.css',
|
|
'css/theme/dark.standard.css',
|
|
'css/theme/light.custom.css',
|
|
'css/theme/dark.custom.css',
|
|
];
|
|
|
|
private const JS_FILES = [
|
|
'js/template.js',
|
|
];
|
|
|
|
/**
|
|
* When dev mode is ON: delete all .min files.
|
|
* When dev mode is OFF: regenerate .min files if source is newer.
|
|
*
|
|
* @param string $mediaRoot Absolute path to the template media directory.
|
|
* @param bool $devMode Whether development mode is enabled.
|
|
*/
|
|
public static function sync(string $mediaRoot, bool $devMode): void
|
|
{
|
|
$mediaRoot = rtrim($mediaRoot, '/\\');
|
|
|
|
foreach (self::CSS_FILES as $relPath) {
|
|
$source = $mediaRoot . '/' . $relPath;
|
|
$min = self::minPath($source);
|
|
|
|
if ($devMode) {
|
|
self::deleteIfExists($min);
|
|
} else {
|
|
self::buildIfStale($source, $min, 'css');
|
|
}
|
|
}
|
|
|
|
foreach (self::JS_FILES as $relPath) {
|
|
$source = $mediaRoot . '/' . $relPath;
|
|
$min = self::minPath($source);
|
|
|
|
if ($devMode) {
|
|
self::deleteIfExists($min);
|
|
} else {
|
|
self::buildIfStale($source, $min, 'js');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Derive the .min path from a source path.
|
|
* template.css → template.min.css
|
|
*/
|
|
private static function minPath(string $path): string
|
|
{
|
|
$info = pathinfo($path);
|
|
return $info['dirname'] . '/' . $info['filename'] . '.min.' . $info['extension'];
|
|
}
|
|
|
|
/**
|
|
* Delete a file if it exists.
|
|
*/
|
|
private static function deleteIfExists(string $path): void
|
|
{
|
|
if (is_file($path)) {
|
|
@unlink($path);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Build the minified file if the source is newer or the min file is missing.
|
|
*/
|
|
private static function buildIfStale(string $source, string $min, string $type): void
|
|
{
|
|
if (!is_file($source)) {
|
|
return;
|
|
}
|
|
|
|
// Skip if min file exists and is newer than source
|
|
if (is_file($min) && filemtime($min) >= filemtime($source)) {
|
|
return;
|
|
}
|
|
|
|
$content = file_get_contents($source);
|
|
if ($content === false) {
|
|
return;
|
|
}
|
|
|
|
$minified = ($type === 'css')
|
|
? self::minifyCss($content)
|
|
: self::minifyJs($content);
|
|
|
|
file_put_contents($min, $minified);
|
|
}
|
|
|
|
/**
|
|
* Minify CSS by stripping comments, excess whitespace, and unnecessary characters.
|
|
*/
|
|
private static function minifyCss(string $css): string
|
|
{
|
|
// Remove comments (but keep IE hacks like /*\*/)
|
|
$css = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $css);
|
|
|
|
// Remove whitespace around { } : ; , > + ~
|
|
$css = preg_replace('/\s*([{}:;,>+~])\s*/', '$1', $css);
|
|
|
|
// Remove remaining newlines and tabs
|
|
$css = preg_replace('/\s+/', ' ', $css);
|
|
|
|
// Remove spaces around selectors
|
|
$css = str_replace(['{ ', ' {', '; ', ' ;'], ['{', '{', ';', ';'], $css);
|
|
|
|
// Remove trailing semicolons before closing braces
|
|
$css = str_replace(';}', '}', $css);
|
|
|
|
// Remove leading/trailing whitespace
|
|
return trim($css);
|
|
}
|
|
|
|
/**
|
|
* Minify JS by stripping single-line comments, multi-line comments,
|
|
* and collapsing whitespace. Preserves string literals.
|
|
*/
|
|
private static function minifyJs(string $js): string
|
|
{
|
|
// Remove multi-line comments
|
|
$js = preg_replace('!/\*.*?\*/!s', '', $js);
|
|
|
|
// Remove single-line comments (but not URLs like http://)
|
|
$js = preg_replace('!(?<=^|[\s;{}()\[\]])//[^\n]*!m', '', $js);
|
|
|
|
// Collapse whitespace
|
|
$js = preg_replace('/\s+/', ' ', $js);
|
|
|
|
// Remove spaces around operators and punctuation
|
|
$js = preg_replace('/\s*([{}();,=+\-*\/<>!&|?:])\s*/', '$1', $js);
|
|
|
|
// Restore necessary spaces (after keywords)
|
|
$js = preg_replace('/(var|let|const|return|typeof|instanceof|new|delete|throw|case|in|of)([^\s;})><=!&|?:,])/', '$1 $2', $js);
|
|
|
|
return trim($js);
|
|
}
|
|
}
|