Skip to content

Commit

Permalink
Version update: 2.14
Browse files Browse the repository at this point in the history
  • Loading branch information
tonyganch committed Jul 8, 2013
1 parent 6af2c0b commit 1b1116f
Showing 1 changed file with 87 additions and 147 deletions.
234 changes: 87 additions & 147 deletions csscomb.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*
* Tool for sorting CSS properties in specific order
*
* @version 2.13 (build bb516f2-1306162139)
* @version 2.14 (build 57f634a-1307080853)
* @author Vyacheslav Oliyanchuk (miripiruni) <[email protected]>
* @license MIT
* @web http://csscomb.com/
Expand All @@ -30,6 +30,10 @@ class csscomb{
'datauri' => null,
// если найдены интерполированные переменные, то эта переменная станет массивом
'interpolations' => null,
// Игнорируем комментарии
'comments' => null,
'inlinecomments' => null,
'magicComments' => null,
// если найдены CSS-хаки мешающие парсить, то эта переменная станет массивом...
'hacks' => null,
// если найдены комментарии содержащие { или } мешающие парсить,
Expand Down Expand Up @@ -908,119 +912,56 @@ function preprocess() {
}

// 4. Interpolated variables
preg_match_all('@(\#|\@){.*?}@ismx', $this->code['edited'], $this->code['interpolations']);
foreach ($this->code['interpolations'][0] as $key => $value) {
$pos = strpos($this->code['edited'], $value);
if ($pos !== false) {
$this->code['edited'] = substr_replace($this->code['edited'],"interpolation".$key.'__',$pos,strlen($value));
}
preg_match_all('@(\#|\@){.*?}@ismx', $this->code['edited'], $this->code['interpolations'], PREG_SET_ORDER);
foreach ($this->code['interpolations'] as $key => $value) {
$this->code['edited'] = str_replace($value[0], 'interpolation'.$key.'__', $this->code['edited']);
}

// X. Temporally remove comments
// Magic comment
preg_match_all('@
(\s*\/\*\s*csscomb:\s*false\s*\*\/.*?\/\*\s*csscomb:\s*true\s*\*\/)
|
(\s*\/\/\s*csscomb:\s*false[\n\r].*?\/\/\s*csscomb:\s*true[^\n\S\r]*)
@ismx', $this->code['edited'],
$this->code['magicComments'], PREG_SET_ORDER);
foreach ($this->code['magicComments'] as $key => $value) {
$this->code['edited'] = str_replace($value[0], "\nmagic: comment".$key.'__;', $this->code['edited']);
}
// Comments
preg_match_all('@
([\n\r]\s*/\*.*?\*/)+
|
(^\s*/\*.*?\*/)+
|
([\n\r]\s*//[^\n\r]*)+
|
(^\s*//[^\n\r]*)+
@ismx', $this->code['edited'], $this->code['comments'], PREG_SET_ORDER);
foreach ($this->code['comments'] as $key => $value) {
$this->code['edited'] = str_replace($value[0], 'comment'.$key.'__', $this->code['edited']);
}
// Inline comments
preg_match_all('@
[^\S\n\r]*/\*.*?\*/([^\n\S\r]*/\*.*?\*/)*
|
(?<!:)[^\S\n\r]*//[^\n\r]*
@ismx', $this->code['edited'], $this->code['inlinecomments'], PREG_SET_ORDER);
foreach ($this->code['inlinecomments'] as $key => $value) {
$this->code['edited'] = str_replace($value[0], 'inlinecomment'.$key.'__', $this->code['edited']);
}

// 5. Закрываем сложности парсинга {}
$this->code['edited'] = str_replace('{}', '{ }', $this->code['edited']);

// 6. Закрываем сложности с отсутствующей последней ; перед }
$this->code['edited'] = preg_replace('@(.*?[^\s;\{\}\/\*])(\s*?})@', '$1;$2', $this->code['edited']);
$this->code['edited'] = preg_replace('@(.*?[^\s;\{\}\/\*_])(\s*?})@', '$1;$2', $this->code['edited']);
// Убираем ; у последнего инлайнового комментария
// Инлайновый комментарий может идти только после фигурной скобки или ;
$this->code['edited'] = preg_replace('@([;\{\}]+\s*?//.*?);(\s*?})@', '$1$2', $this->code['edited']);
// Убираем ; у интерполированных переменных
$this->code['edited'] = preg_replace('/((#\{\$|\@\{).*?)[;](\s*?\})/', '$1$3', $this->code['edited']);

// 7. Комментарии
if (preg_match_all('@
(
\s*
/\*
.*?[^\*/]
\*/
(\s/\*\*/)?
)
@ismx', $this->code['edited'], $test)) {

// 7.1. Закомментировано одно или несколько свойств: повторяющийся паттерн *:*; \s*?
if (preg_match_all('@
(\s*)
/\*
(.*?[^\*/])
\*+/
(\ {0,1}/\*\*/)?
@ismx', $this->code['edited'], $comments)) {

$new_comments = Array();
$old_comments = $comments[0];

foreach ($comments[2] as $key => $comment) {
if ( // если комментарий содержит ; и :
strpos($comment, ':') !== FALSE AND
strpos($comment, ';') !== FALSE

) {
preg_match_all('@
(\s*)
(
.+?[^;]
;
)
@ismx', $comment, $properties);

$new_comment = '';
foreach ($properties[2] as $property) {
$new_comment .= $comments[1][$key]."commented__".$property;
}
$new_comments[] = $new_comment;
}
else {
// если нет : или ;, то считаем что это текстовый комментарий
// и копируем его в том виде, в каком он был.
$new_comments[] = $comments[0][$key];
}


}

foreach ($old_comments as $key => $old_comment) {
$this->code['edited'] = str_replace(
$old_comments[$key],
$new_comments[$key],
$this->code['edited']);
}
}

// 7.2. Обрывки закомментированных деклараций: присутствует { или }
if (preg_match_all('@
\s*?
/\*
(
.*?[^\*/]
)*?
\*+/
@ismx', $this->code['edited'], $comments)) {

$new_comments = Array();
$old_comments = $comments[0];

foreach ($comments[0] as $key => $comment) {
if (strpos($comment, '}') !== FALSE OR strpos($comment, '{') !== FALSE) {
$new_comment = '';
if (strpos($comment, '}') !== FALSE) { $new_comment .= '}'; }
$new_comment .= "brace__".$key;
if (strpos($comment, '{') !== FALSE) { $new_comment .= '{'; }
$new_comments[$key] = $new_comment;
$this->code['braces'][$key] = $comment;
}
}

foreach ($new_comments as $key => $new_comment) {
if (strlen($new_comment) > 0) {
$this->code['edited'] = str_replace(
$old_comments[$key],
$new_comment,
$this->code['edited']);
}
}
}
}

// 8. Entities
if (preg_match_all('@
Expand Down Expand Up @@ -1181,9 +1122,9 @@ function parse_child($value = '') {

// 2. Выносим переменные в отдельный массив $vars
preg_match_all('@
(\s*/\*[^\*/]*?\*/)?
(\s*//.*?)?
(comment\d*__)*
\s*(\$|\@)[^;\}]+?:[^;]+?;
(inlinecomment\d*__)*
@ismx', $value, $vars);
// Удаляем их из общей строки
foreach ($vars[0] as $var) {
Expand All @@ -1195,29 +1136,32 @@ function parse_child($value = '') {

// Включения, следующие сразу за {
preg_match_all('@
(^\s*\@[^;]+?[;])|(^\s*\.[^;:]+?[;])
(^\s*(comment\d*__)*\s*\@[^;]+?[;](inlinecomment\d*__)*)
|
(^\s*(comment\d*__)*\s*\.[^;:]+?[;](inlinecomment\d*__)*)
@isx', $value, $first_imports);

// Все остальные
preg_match_all('@
(?<=[;}])(\s*\@[^;]+?[;])|(?<=[;}])(\s*\.[^;:]+?[;])
(?<=inlinecomment\d__|[;}])
((comment\d*__)?\s*\@[^;]+?[;](inlinecomment\d*__)?)
|
(?<=inlinecomment\d__|[;}])
((comment\d*__)?\s*\.[^;:]+?[;](inlinecomment\d*__)?)
@ismx', $value, $imports);
// Удаляем их из общей строки
foreach ($first_imports[0] as &$first_import) {
$value = str_replace($first_import, '', $value);
}
foreach ($imports[1] as &$import) {
$value = str_replace($import, '', $value);
}
foreach ($imports[2] as &$import) {
foreach ($imports[0] as &$import) {
$value = str_replace($import, '', $value);
}

// 4. Выносим простые свойства в массив $properties
preg_match_all('@
(comment\d*__)?
\s*[^;]+?:[^;]+?;
(\s*/\*.*?[^\*/]\*/)?
(\s{0,1}/\*\*/)?
(inlinecomment\d*__)?
@ismx', $value, $properties);
// Удаляем их из общей строки
foreach ($properties[0] as &$property) {
Expand All @@ -1227,11 +1171,9 @@ function parse_child($value = '') {
$props = $properties[0];
$props = $this->resort_properties($props);

// 5. Если осталось ещё что-то, оставляем «как есть»

// 6. Склеиваем всё обратно в следующем порядке:
// переменные, включения, простые свойства, вложенные {}
$value = implode('', $vars[0]).implode('', $first_imports[0]).implode('', $imports[1]).implode('', $imports[2]).implode('', $block_imports).implode('', $props).$nested_string.$value;
$value = implode('', $vars[0]).implode('', $first_imports[0]).implode('', $imports[0]).implode('', $block_imports).implode('', $props).$nested_string.$value;
return $value;
}

Expand All @@ -1252,7 +1194,6 @@ function parse_properties($css = '') {
^
(.*?)
(
#(\s*/\*.*\*/;)*?
\s*?
}
)
Expand Down Expand Up @@ -1303,17 +1244,15 @@ function parse_properties($css = '') {
^
(.*?)
(\s*?)
(/\* .* \*/)
(inlinecomment\d*__)
(.*)
$
@ismx', $properties, $matches);

if (
count($matches) === 5 and // все распарсилось как надо
strlen($matches[1]) === 0 and // комментарий действительно идет первым
strpos($matches[2], "\n") !== 0 // перед комментарием нет переноса строки, следовательно предпологаем, что он относится к скобке с селектором
strlen($matches[1]) === 0 // комментарий действительно идет первым
) {
$first_spaces = $matches[2];
$first_comment = $matches[3];
Expand All @@ -1330,10 +1269,7 @@ function parse_properties($css = '') {
.[^;]*
;
( # На этой же строке (после ;) может быть комментарий. Он тоже пригодится.
\s*
/\*
.*?[^\*/]
\*/
inlinecomment\d*__
)
?
(\s{0,1}/\*\*/)?
Expand Down Expand Up @@ -1361,8 +1297,7 @@ function parse_properties($css = '') {
.[^;]* # все что угодно, но не ;
;
( # На этой же строке (после ;) может быть комментарий. Он тоже пригодится.
\s*
/\* .* \*/
inlinecomment\d*__
)
*?
)
Expand Down Expand Up @@ -1406,9 +1341,7 @@ function resort_properties($prop) {
* Пробел в начале добавляется специально, чтобы избежать совпадений по вхождению
* одной строки в другую. Например: top не должно совпадать с border-top
*/
strpos(' '.trim($property), ' '.$k.':') !== FALSE OR
strpos(' '.trim($property), ' commented__'.$k.':') !== FALSE

strpos(' '.trim($property), ' '.$k.':') !== FALSE
) {
$through_number = $this->get_through_number($k); // определяем "сквозной" порядковый номер
if ($through_number !== false) $index = $through_number;
Expand All @@ -1421,8 +1354,7 @@ function resort_properties($prop) {
foreach ($this->sort_order as $pos => $key) {
if (
// пробел в начале добавляется специально.
strpos(' '.trim($property), ' '.$key.':') !== FALSE OR
strpos(' '.trim($property), ' commented__'.$key.':') !== FALSE
strpos(' '.trim($property), ' '.$key.':') !== FALSE
) {
$index = $pos;
}
Expand Down Expand Up @@ -1506,26 +1438,34 @@ function postprocess() {
}

// 4. Interpolated variables
preg_match_all('#interpolation(\d)__#ismx', $this->code['resorted'], $new_vars);
foreach ($new_vars[1] as $key => $value) {
$this->code['resorted'] = str_replace($new_vars[0][$key], $this->code['interpolations'][0][$key], $this->code['resorted']);
if (is_array($this->code['interpolations'])) { // если были обнаружены и вырезаны data uri
foreach ($this->code['interpolations'] as $key => $val) {
$this->code['resorted'] = str_replace('interpolation'.$key.'__', $val[0], $this->code['resorted']); // заменяем значение expression обратно
}
}
// Magic comments
if (is_array($this->code['magicComments'])) {
foreach ($this->code['magicComments'] as $key => $val) {
$this->code['resorted'] = str_replace("\nmagic: comment".$key.'__;', $val[0], $this->code['resorted']);
}
}

// 5. Удаляем искусственно созданные 'commented__'
while(strpos($this->code['resorted'], 'commented__') !== FALSE) {
$this->code['resorted'] = preg_replace(
'#
commented__
(.*?[^:]
:
.*?[^;]
;)
#ismx',
'/*$1*/',
$this->code['resorted']
);

// Comments
if (is_array($this->code['inlinecomments'])) { // если были обнаружены и вырезаны data uri
foreach ($this->code['inlinecomments'] as $key => $val) {
$this->code['resorted'] = str_replace('inlinecomment'.$key.'__', $val[0], $this->code['resorted']); // заменяем значение expression обратно
}
}
if (is_array($this->code['comments'])) { // если были обнаружены и вырезаны data uri
foreach ($this->code['comments'] as $key => $val) {
if (strpos($this->code['resorted'], 'comment'.$key.'__') > -1) {
$this->code['resorted'] = str_replace('comment'.$key.'__', $val[0], $this->code['resorted']); // заменяем значение expression обратно
}
}
}


// 6. Удаляем искусственно созданные 'brace__'
if (is_array($this->code['braces'])) { // если были обнаружены и вырезаны хаки
foreach ($this->code['braces'] as $key => $val) {
Expand Down

2 comments on commit 1b1116f

@drudge
Copy link
Member

@drudge drudge commented on 1b1116f Jul 9, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the Chocolat Mixin registry.

@tonyganch
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@drudge, thank you!

Please sign in to comment.