diff --git a/_config/config.yml b/_config/config.yml index f568b01..34e44ed 100755 --- a/_config/config.yml +++ b/_config/config.yml @@ -10,3 +10,7 @@ SilverStripe\Core\Injector\Injector: spaceless: ['\Moo\Template\Parser\Spaceless', 'spaceless'] openBlocks: content: ['\Moo\Template\Parser\TemplateBlock', 'content'] + +SilverStripe\ORM\FieldType\DBString: + extensions: + - Moo\Template\Extension\SpacelessCast diff --git a/src/Template/Extension/SpacelessCast.php b/src/Template/Extension/SpacelessCast.php new file mode 100644 index 0000000..70ec940 --- /dev/null +++ b/src/Template/Extension/SpacelessCast.php @@ -0,0 +1,29 @@ + 'HTMLText', + ]; + + /** + * Get string without extra spaces. + */ + public function Spaceless(): DBField + { + return DBField::create_field( + 'HTMLText', + Spaceless::spaceless([ + 'Template' => [ + 'php' => $this->getOwner()->RAW(), + ], + ]) + ); + } +} diff --git a/src/Template/Parser/Spaceless.php b/src/Template/Parser/Spaceless.php index 383d9a1..62fcd51 100755 --- a/src/Template/Parser/Spaceless.php +++ b/src/Template/Parser/Spaceless.php @@ -7,28 +7,124 @@ */ class Spaceless { + /** + * Remove space from the start of the statement. + */ + protected static array $patternStart = [ + '/\'(\s+)([^\s\'])/m', + "'$2", + ]; + + /** + * Remove space from between HTML tags. + */ + protected static array $patternBetweenTag = [ + '/>\s+<', + ]; + + /** + * Remove space from the end of the statement. + */ + protected static array $patternEnd = [ + '/([^\s\'])(\s+)\';/m', + "$1';", + ]; + + /** + * Convert multiple spaces into one space. + */ + protected static array $patternOneSpace = [ + '!\s+!', + ' ', + ]; + + /** + * Remove space from empty statement `$val .= ' ';`. + */ + protected static array $patternEmpty = [ + '/\'(\s+)\';/m', + "'';", + ]; + /** * Remove white spaces from around template code. * - * @param $res - * @return null|string|string[] + * @param array $res + * + * @return ?string */ public static function spaceless($res) { - // Pattern to find whitespaces + // Template string code to remove whitespaces from + $php = $res['Template']['php']; + + // Convert into an array + $code = static::toStatementPerLine($php); + + // Clean up each i tem in the array + $index = 0; + foreach ($code as $key => $line) { + $code[$key] = static::cleanCode((string) $line, $index); + ++$index; + } + + return implode("\n", $code); + } + + /** + * Clean up a line of code based on its position `$index`. + */ + protected static function cleanCode(string $value, int $index): string + { + // Default replacements $pattern = [ - '/\'(\s+)([^\s\'])/m', - '/\'(\s+)\'/m', - '/([^\s\'])(\s+)\';/m', - '/>\s+<'], $php); + $replacement = [ + static::$patternStart[1], + static::$patternEnd[1], + static::$patternOneSpace[1], + static::$patternEmpty[1], + static::$patternBetweenTag[1], + ]; + } + + return preg_replace($pattern, $replacement, $value); + } + + /** + * Convert the PHP string into an array of items. One statement per line. + */ + protected static function toStatementPerLine(string $value): array + { + // Convert string into single line string + $value = str_replace(["\r\n", "\n", "\r", "\t"], '', $value); + // Add break-line before every start of a statement `$val .=` + $value = str_replace('$val .=', "\n\$val .=", $value); - return $php; + // Convert the string into an array item per line + return array_filter(explode("\n", $value)); } }