first commit
This commit is contained in:
commit
1218dd1517
12716 files changed
+989233
No files matched your search
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the package bk2k/bootstrap-package.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace BK2K\BootstrapPackage\Parser;
|
||||
|
||||
use TYPO3\CMS\Core\Cache\CacheManager;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* AbstractParser
|
||||
*/
|
||||
abstract class AbstractParser implements ParserInterface
|
||||
{
|
||||
/**
|
||||
* @param string $extension
|
||||
* @return bool
|
||||
*/
|
||||
public function supports($extension)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param array $settings
|
||||
* @return string
|
||||
*/
|
||||
public function compile($file, $settings)
|
||||
{
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param array $settings
|
||||
* @return bool
|
||||
*/
|
||||
protected function isCached($file, $settings)
|
||||
{
|
||||
$cacheIdentifier = $this->getCacheIdentifier($file, $settings);
|
||||
$cacheFile = $this->getCacheFile($cacheIdentifier, $settings['cache']['tempDirectory']);
|
||||
$cacheFileMeta = $this->getCacheFileMeta($cacheFile);
|
||||
|
||||
return file_exists($cacheFile) && file_exists($cacheFileMeta);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $cacheFile
|
||||
* @param string $cacheFileMeta
|
||||
* @param array $settings
|
||||
* @return bool
|
||||
*/
|
||||
protected function needsCompile($cacheFile, $cacheFileMeta, $settings)
|
||||
{
|
||||
$needCompilation = false;
|
||||
$fileModificationTime = filemtime($cacheFile);
|
||||
$metadata = unserialize(file_get_contents($cacheFileMeta), ['allowed_classes' => false]);
|
||||
|
||||
foreach ($metadata['files'] as $file => $cacheTime) {
|
||||
$currentTime = filemtime($file);
|
||||
if ($currentTime !== $cacheTime || $currentTime > $fileModificationTime) {
|
||||
$needCompilation = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$needCompilation && $settings['variables'] !== $metadata['variables']) {
|
||||
$needCompilation = true;
|
||||
}
|
||||
|
||||
if (!$needCompilation && $settings['options']['sourceMap'] !== $metadata['sourceMap']) {
|
||||
$needCompilation = true;
|
||||
}
|
||||
|
||||
return $needCompilation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $cacheIdentifier
|
||||
* @param string $tempDirectory
|
||||
* @return string
|
||||
*/
|
||||
protected function getCacheFile($cacheIdentifier, $tempDirectory)
|
||||
{
|
||||
return $tempDirectory . $cacheIdentifier . '.css';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
protected function getCacheFileMeta($filename)
|
||||
{
|
||||
return $filename . '.meta';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param array $settings
|
||||
* @return string
|
||||
*/
|
||||
protected function getCacheIdentifier($file, $settings)
|
||||
{
|
||||
$filehash = md5($file);
|
||||
$hash = hash('sha256', $filehash . serialize($settings));
|
||||
$extension = pathinfo($file, PATHINFO_EXTENSION);
|
||||
|
||||
return basename($file, '.' . $extension) . '-' . $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getPathSite()
|
||||
{
|
||||
return Environment::getPublicPath() . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all page caches
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheGroupException
|
||||
*/
|
||||
protected function clearPageCaches()
|
||||
{
|
||||
GeneralUtility::makeInstance(CacheManager::class)->flushCachesInGroup('pages');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the package bk2k/bootstrap-package.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace BK2K\BootstrapPackage\Parser;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* LessParser
|
||||
*/
|
||||
class LessParser extends AbstractParser
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (!class_exists('Less_Cache')) {
|
||||
require_once ExtensionManagementUtility::extPath('bootstrap_package') . '/Contrib/less.php/Less.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $extension
|
||||
* @return bool
|
||||
*/
|
||||
public function supports($extension)
|
||||
{
|
||||
return $extension === 'less';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param array $settings
|
||||
* @return string
|
||||
*/
|
||||
public function compile($file, $settings)
|
||||
{
|
||||
$cacheIdentifier = $this->getCacheIdentifier($file, $settings);
|
||||
$cacheFile = $this->getCacheFile($cacheIdentifier, $settings['cache']['tempDirectory']);
|
||||
$cacheFileMeta = $this->getCacheFileMeta($cacheFile);
|
||||
$compile = false;
|
||||
|
||||
if (!$this->isCached($file, $settings)
|
||||
|| $this->needsCompile($cacheFile, $cacheFileMeta, $settings)) {
|
||||
$compile = true;
|
||||
}
|
||||
|
||||
if ($compile) {
|
||||
$result = $this->parseFile($file, $settings);
|
||||
GeneralUtility::writeFile(GeneralUtility::getFileAbsFileName($cacheFile), $result['css']);
|
||||
GeneralUtility::writeFile(GeneralUtility::getFileAbsFileName($cacheFileMeta), serialize($result['cache']));
|
||||
$this->clearPageCaches();
|
||||
}
|
||||
|
||||
return $cacheFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param array $settings
|
||||
* @return array
|
||||
*/
|
||||
protected function parseFile($file, $settings)
|
||||
{
|
||||
$options = [];
|
||||
$options['compress'] = true;
|
||||
if ($settings['options']['sourceMap']) {
|
||||
$options['compress'] = false;
|
||||
$options['sourceMap'] = true;
|
||||
$options['sourceMapBasepath'] = realpath($this->getPathSite());
|
||||
$options['sourceMapRootpath'] = $settings['cache']['tempDirectoryRelativeToRoot'];
|
||||
}
|
||||
|
||||
$parser = new \Less_Parser($options);
|
||||
$parser->parseFile(GeneralUtility::getFileAbsFileName($file));
|
||||
$parser->ModifyVars($settings['variables']);
|
||||
$css = $parser->getCss();
|
||||
|
||||
// Correct relative urls
|
||||
$absoluteFilename = GeneralUtility::getFileAbsFileName($file);
|
||||
$relativePath = $settings['cache']['tempDirectoryRelativeToRoot'] . dirname(substr($absoluteFilename, strlen($this->getPathSite()))) . '/';
|
||||
$search = '%url\s*\(\s*[\\\'"]?(?!(((?:https?:)?\/\/)|(?:data:?:)))([^\\\'")]+)[\\\'"]?\s*\)%';
|
||||
$replace = 'url("' . $relativePath . '$3")';
|
||||
$css = preg_replace($search, $replace, $css);
|
||||
|
||||
$parsedFiles = [];
|
||||
foreach ($parser::AllParsedFiles() as $parsedfile) {
|
||||
$parsedFiles[$parsedfile] = filemtime($parsedfile);
|
||||
}
|
||||
|
||||
return [
|
||||
'css' => $css,
|
||||
'cache' => [
|
||||
'version' => \Less_Version::version,
|
||||
'date' => date('r'),
|
||||
'css' => $css,
|
||||
'etag' => md5($css),
|
||||
'files' => $parsedFiles,
|
||||
'variables' => $settings['variables'],
|
||||
'sourceMap' => $settings['options']['sourceMap']
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the package bk2k/bootstrap-package.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace BK2K\BootstrapPackage\Parser;
|
||||
|
||||
/**
|
||||
* ParserInterface
|
||||
*/
|
||||
interface ParserInterface
|
||||
{
|
||||
/**
|
||||
* @param string $extension
|
||||
* @return bool
|
||||
*/
|
||||
public function supports($extension);
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param array $settings
|
||||
* @return string
|
||||
*/
|
||||
public function compile($file, $settings);
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the package bk2k/bootstrap-package.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace BK2K\BootstrapPackage\Parser;
|
||||
|
||||
use ScssPhp\ScssPhp\Compiler;
|
||||
use ScssPhp\ScssPhp\Formatter\Compressed;
|
||||
use ScssPhp\ScssPhp\Version;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
|
||||
/**
|
||||
* ScssParser
|
||||
*/
|
||||
class ScssParser extends AbstractParser
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (!class_exists('ScssPhp\ScssPhp\Version')) {
|
||||
require_once ExtensionManagementUtility::extPath('bootstrap_package') . '/Contrib/scssphp/scss.inc.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $extension
|
||||
* @return bool
|
||||
*/
|
||||
public function supports($extension)
|
||||
{
|
||||
return $extension === 'scss';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param array $settings
|
||||
* @return string
|
||||
*/
|
||||
public function compile($file, $settings)
|
||||
{
|
||||
$cacheIdentifier = $this->getCacheIdentifier($file, $settings);
|
||||
$cacheFile = $this->getCacheFile($cacheIdentifier, $settings['cache']['tempDirectory']);
|
||||
$cacheFileMeta = $this->getCacheFileMeta($cacheFile);
|
||||
$compile = false;
|
||||
|
||||
if (!$this->isCached($file, $settings)
|
||||
|| $this->needsCompile($cacheFile, $cacheFileMeta, $settings)) {
|
||||
$compile = true;
|
||||
}
|
||||
|
||||
if ($compile) {
|
||||
$result = $this->parseFile($file, $settings);
|
||||
GeneralUtility::writeFile(GeneralUtility::getFileAbsFileName($cacheFile), $result['css']);
|
||||
GeneralUtility::writeFile(GeneralUtility::getFileAbsFileName($cacheFileMeta), serialize($result['cache']));
|
||||
$this->clearPageCaches();
|
||||
}
|
||||
|
||||
return $cacheFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param array $settings
|
||||
* @return array
|
||||
*/
|
||||
protected function parseFile($file, $settings)
|
||||
{
|
||||
$scss = new Compiler();
|
||||
$scss->setFormatter(Compressed::class);
|
||||
$scss->setVariables($settings['variables']);
|
||||
if ($settings['options']['sourceMap']) {
|
||||
$scss->setSourceMap(Compiler::SOURCE_MAP_INLINE);
|
||||
$scss->setSourceMapOptions([
|
||||
'sourceMapRootpath' => $settings['cache']['tempDirectoryRelativeToRoot'],
|
||||
'sourceMapBasepath' => '<PATH DOES NOT EXIST BUT SUPRESSES WARNINGS>'
|
||||
]);
|
||||
}
|
||||
$absoluteFilename = $settings['file']['absolute'];
|
||||
// Adds visual directory path of the initial file as import path
|
||||
// This scenarios happens, when e.g. developing packages using the `path`
|
||||
// repository feature of Composer - having one package in `public/typo3conf/ext/`
|
||||
// and the other one symlinked in e.g. `packages/`.
|
||||
// Since the PHP SCSS parser works on resolved real paths, the symlinked context is lost.
|
||||
$visualImportPath = dirname($absoluteFilename);
|
||||
$scss->addImportPath(function ($url) use ($visualImportPath) {
|
||||
// Resolve potential back paths manually using PathUtility::getCanonicalPath,
|
||||
// but make sure we do not break out of TYPO3 application path using GeneralUtility::getFileAbsFileName
|
||||
// Also resolve EXT: paths if given
|
||||
$isTypo3Absolute = (strpos($url, 'EXT:') === 0) || PathUtility::isAbsolutePath($url);
|
||||
$fileName = $isTypo3Absolute ? $url : $visualImportPath . '/' . $url;
|
||||
$full = GeneralUtility::getFileAbsFileName(PathUtility::getCanonicalPath($fileName));
|
||||
// The API forces us to check the existence of files paths, with or without url.
|
||||
// We must only return a string if the file to be imported actually exists.
|
||||
$hasExtension = preg_match('/[.]s?css$/', $url);
|
||||
if (
|
||||
is_file($file = $full . '.scss') ||
|
||||
($hasExtension && is_file($file = $full))
|
||||
) {
|
||||
// We could trigger a deprecation message here at some point
|
||||
return $file;
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
// Add extensions path to import paths, so that we can use paths relative to this directory to resolve imports
|
||||
$scss->addImportPath(Environment::getExtensionsPath());
|
||||
|
||||
// Make paths in url() statements relative to site root
|
||||
$absoluteFilePath = dirname($absoluteFilename);
|
||||
$relativeFilePath = PathUtility::getAbsoluteWebPath($absoluteFilePath);
|
||||
$absoluteBootstrapPackageThemePath =
|
||||
ExtensionManagementUtility::extPath('bootstrap_package') . 'Resources/Public/Scss/Theme';
|
||||
$relativeBootstrapPackageThemePath = PathUtility::getAbsoluteWebPath($absoluteBootstrapPackageThemePath);
|
||||
$scss->registerFunction(
|
||||
'url',
|
||||
function ($args) use (
|
||||
$scss,
|
||||
$absoluteFilePath,
|
||||
$relativeFilePath,
|
||||
$absoluteBootstrapPackageThemePath,
|
||||
$relativeBootstrapPackageThemePath
|
||||
) {
|
||||
$marker = $args[0][1];
|
||||
$args[0][1] = '';
|
||||
$result = $scss->compileValue($args[0]);
|
||||
if (substr_compare($result, 'data:', 0, 5, true) !== 0) {
|
||||
if (is_file(PathUtility::getCanonicalPath($absoluteFilePath . '/' . $result))) {
|
||||
$result = PathUtility::getCanonicalPath($relativeFilePath . '/' . $result);
|
||||
} elseif (is_file(PathUtility::getCanonicalPath($absoluteBootstrapPackageThemePath . '/' . $result))) {
|
||||
$result = PathUtility::getCanonicalPath($relativeBootstrapPackageThemePath . '/' . $result);
|
||||
}
|
||||
$result = substr($result, 0, 1) === '/' ? substr($result, 1) : $result;
|
||||
}
|
||||
return 'url(' . $marker . $result . $marker . ')';
|
||||
}
|
||||
);
|
||||
|
||||
// Compile file
|
||||
$css = $scss->compile('@import "' . $absoluteFilename . '"');
|
||||
|
||||
// Fix paths in url() statements to be relative to temp directory
|
||||
$relativeTempPath = $settings['cache']['tempDirectoryRelativeToRoot'];
|
||||
$search = '%url\s*\(\s*[\\\'"]?(?!(((?:https?:)?\/\/)|(?:data:?:)))([^\\\'")]+)[\\\'"]?\s*\)%';
|
||||
$replace = 'url("' . $relativeTempPath . '$3")';
|
||||
$css = preg_replace($search, $replace, $css);
|
||||
|
||||
return [
|
||||
'css' => $css,
|
||||
'cache' => [
|
||||
'version' => Version::VERSION,
|
||||
'date' => date('r'),
|
||||
'css' => $css,
|
||||
'etag' => md5($css),
|
||||
'files' => $scss->getParsedFiles(),
|
||||
'variables' => $settings['variables'],
|
||||
'sourceMap' => $settings['options']['sourceMap']
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user