Files
kupshop/class/sacy/ext-translators.php
2025-08-02 16:30:27 +02:00

253 lines
6.6 KiB
PHP

<?php
namespace sacy;
abstract class ExternalProcessor
{
abstract protected function getCommandLine($filename, $opts = []);
public function transform($in, $filename, $opts = [])
{
$s = [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
];
$cmd = $this->getCommandLine($filename, $opts);
$p = proc_open($cmd, $s, $pipes, getcwd());
if (!is_resource($p)) {
throw new \Exception("Failed to execute {$cmd}");
}
fwrite($pipes[0], $in);
fclose($pipes[0]);
$out = stream_get_contents($pipes[1]);
$err = stream_get_contents($pipes[2]);
fclose($pipes[1]);
fclose($pipes[2]);
$r = proc_close($p);
if ($r != 0) {
throw new \Exception("Command returned {$r}: {$out} {$err}");
}
return $out;
}
}
class ExternalProcessorRegistry
{
private static $transformers;
private static $compressors;
public static function registerTransformer($type, $cls)
{
self::$transformers[$type] = $cls;
}
public static function registerCompressor($type, $cls)
{
self::$compressors[$type] = $cls;
}
private static function lookup($type, $in)
{
return (isset($in[$type])) ? new $in[$type]() : null;
}
public static function typeIsSupported($type)
{
return isset(self::$transformers[$type])
|| isset(self::$compressors[$type]);
}
/**
* @static
*
* @param $type string mime type of input
*
* @return ExternalProcessor
*/
public static function getTransformerForType($type)
{
return self::lookup($type, self::$transformers);
}
/**
* @static
*
* @param $type string mime type of input
*
* @return ExternalProcessor
*/
public static function getCompressorForType($type)
{
return self::lookup($type, self::$compressors);
}
}
class ProcessorUglify extends ExternalProcessor
{
protected function getCommandLine($filename, $opts = [])
{
if (!is_executable(SACY_COMPRESSOR_UGLIFY)) {
throw new Exception('SACY_COMPRESSOR_UGLIFY defined but not executable');
}
return SACY_COMPRESSOR_UGLIFY;
}
}
class ProcessorCoffee extends ExternalProcessor
{
protected function getCommandLine($filename, $opts = [])
{
if (!is_executable(SACY_TRANSFORMER_COFFEE)) {
throw new Exception('SACY_TRANSFORMER_COFFEE defined but not executable');
}
return sprintf('%s -c -s', SACY_TRANSFORMER_COFFEE);
}
}
class ProcessorEco extends ExternalProcessor
{
protected function getType()
{
return 'text/x-eco';
}
protected function getCommandLine($filename, $opts = [])
{
if (!is_executable(SACY_TRANSFORMER_ECO)) {
throw new Exception('SACY_TRANSFORMER_ECO defined but not executable');
}
// Calling eco with the filename here. Using stdin wouldn't
// cut it, as eco uses the filename to figure out the name of
// the js function it outputs.
$eco_root = $opts['eco-root'];
return sprintf('%s %s -p %s',
SACY_TRANSFORMER_ECO,
$eco_root ? sprintf('-i %s', escapeshellarg($eco_root)) : '',
escapeshellarg($filename)
);
}
}
class ProcessorSass extends ExternalProcessor
{
protected function getType()
{
return 'text/x-sass';
}
protected function getCommandLine($filename, $opts = [])
{
if (!is_executable(SACY_TRANSFORMER_SASS)) {
throw new Exception('SACY_TRANSFORMER_SASS defined but not executable');
}
$libpath = $opts['library_path'] ?: [dirname($filename)];
$libpath[] = $_SERVER['DOCUMENT_ROOT'] ?: getcwd();
$path =
implode(' ', array_map(function ($p) {
return '-I '.escapeshellarg($p);
}, array_unique($libpath)));
return sprintf('%s --cache-location=%s -s %s %s',
SACY_TRANSFORMER_SASS,
escapeshellarg(sys_get_temp_dir()),
$this->getType() == 'text/x-scss' ? '--scss' : '',
$path
);
}
}
class ProcessorScss extends ProcessorSass
{
protected function getType()
{
return 'text/x-scss';
}
}
class ProcessorLess extends ExternalProcessor
{
protected function getCommandLine($filename, $opts = [])
{
if (!is_executable(SACY_TRANSFORMER_LESS)) {
throw new \Exception('SACY_TRANSFORMER_LESS defined but not executable');
}
return sprintf(
'%s -I%s -',
SACY_TRANSFORMER_LESS,
escapeshellarg(dirname($filename))
);
}
}
class ProcessorJSX extends ExternalProcessor
{
protected function getCommandLine($filename, $opts = [])
{
if (!is_executable(SACY_TRANSFORMER_JSX)) {
throw new Exception('SACY_TRANSFORMER_JSX defined but not executable');
}
return SACY_TRANSFORMER_JSX;
}
}
class ProcessorFontIcons extends ExternalProcessor
{
protected function getCommandLine($filename, $opts = [])
{
return SACY_TRANSFORMER_FONTICONS." compile 'templates/icons/' -F -c {$filename}";
}
public function transform($in, $filename, $opts = [])
{
$css = 'data/tmp/cache/icons.css';
if (@filemtime($filename) > @filemtime($css)) {
parent::transform($in, $filename, $opts);
}
return str_replace('./icons', '/data/tmp/cache/icons', file_get_contents($css));
}
}
if (defined('SACY_COMPRESSOR_UGLIFY')) {
ExternalProcessorRegistry::registerCompressor('text/javascript', 'sacy\ProcessorUglify');
}
if (defined('SACY_TRANSFORMER_COFFEE')) {
ExternalProcessorRegistry::registerTransformer('text/coffeescript', 'sacy\ProcessorCoffee');
}
if (defined('SACY_TRANSFORMER_ECO')) {
ExternalProcessorRegistry::registerTransformer('text/x-eco', 'sacy\ProcessorEco');
}
if (defined('SACY_TRANSFORMER_SASS')) {
ExternalProcessorRegistry::registerTransformer('text/x-sass', 'sacy\ProcessorSass');
ExternalProcessorRegistry::registerTransformer('text/x-scss', 'sacy\ProcessorScss');
}
if (defined('SACY_TRANSFORMER_FONTICONS')) {
ExternalProcessorRegistry::registerTransformer('image/svg+xml', 'sacy\ProcessorFontIcons');
}
if (defined('SACY_TRANSFORMER_LESS')) {
ExternalProcessorRegistry::registerTransformer('text/x-less', 'sacy\ProcessorLess');
}
if (defined('SACY_TRANSFORMER_JSX')) {
ExternalProcessorRegistry::registerTransformer('text/x-jsx', 'sacy\ProcessorJSX');
}