44 *
55 * Tool for sorting CSS properties in specific order
66 *
7- * @version 2.13 (build bb516f2-1306162139 )
7+ * @version 2.14 (build 57f634a-1307080853 )
88 * @author Vyacheslav Oliyanchuk (miripiruni) <mail@csscomb.com>
99 * @license MIT
1010 * @web http://csscomb.com/
@@ -30,6 +30,10 @@ class csscomb{
3030 'datauri ' => null ,
3131 // если найдены интерполированные переменные, то эта переменная станет массивом
3232 'interpolations ' => null ,
33+ // Игнорируем комментарии
34+ 'comments ' => null ,
35+ 'inlinecomments ' => null ,
36+ 'magicComments ' => null ,
3337 // если найдены CSS-хаки мешающие парсить, то эта переменная станет массивом...
3438 'hacks ' => null ,
3539 // если найдены комментарии содержащие { или } мешающие парсить,
@@ -908,119 +912,56 @@ function preprocess() {
908912 }
909913
910914 // 4. Interpolated variables
911- preg_match_all ('@(\#|\@){.*?}@ismx ' , $ this ->code ['edited ' ], $ this ->code ['interpolations ' ]);
912- foreach ($ this ->code ['interpolations ' ][0 ] as $ key => $ value ) {
913- $ pos = strpos ($ this ->code ['edited ' ], $ value );
914- if ($ pos !== false ) {
915- $ this ->code ['edited ' ] = substr_replace ($ this ->code ['edited ' ],"interpolation " .$ key .'__ ' ,$ pos ,strlen ($ value ));
916- }
915+ preg_match_all ('@(\#|\@){.*?}@ismx ' , $ this ->code ['edited ' ], $ this ->code ['interpolations ' ], PREG_SET_ORDER );
916+ foreach ($ this ->code ['interpolations ' ] as $ key => $ value ) {
917+ $ this ->code ['edited ' ] = str_replace ($ value [0 ], 'interpolation ' .$ key .'__ ' , $ this ->code ['edited ' ]);
918+ }
919+
920+ // X. Temporally remove comments
921+ // Magic comment
922+ preg_match_all ('@
923+ (\s*\/\*\s*csscomb:\s*false\s*\*\/.*?\/\*\s*csscomb:\s*true\s*\*\/)
924+ |
925+ (\s*\/\/\s*csscomb:\s*false[\n\r].*?\/\/\s*csscomb:\s*true[^\n\S\r]*)
926+ @ismx ' , $ this ->code ['edited ' ],
927+ $ this ->code ['magicComments ' ], PREG_SET_ORDER );
928+ foreach ($ this ->code ['magicComments ' ] as $ key => $ value ) {
929+ $ this ->code ['edited ' ] = str_replace ($ value [0 ], "\nmagic: comment " .$ key .'__; ' , $ this ->code ['edited ' ]);
930+ }
931+ // Comments
932+ preg_match_all ('@
933+ ([\n\r]\s*/\*.*?\*/)+
934+ |
935+ (^\s*/\*.*?\*/)+
936+ |
937+ ([\n\r]\s*//[^\n\r]*)+
938+ |
939+ (^\s*//[^\n\r]*)+
940+ @ismx ' , $ this ->code ['edited ' ], $ this ->code ['comments ' ], PREG_SET_ORDER );
941+ foreach ($ this ->code ['comments ' ] as $ key => $ value ) {
942+ $ this ->code ['edited ' ] = str_replace ($ value [0 ], 'comment ' .$ key .'__ ' , $ this ->code ['edited ' ]);
943+ }
944+ // Inline comments
945+ preg_match_all ('@
946+ [^\S\n\r]*/\*.*?\*/([^\n\S\r]*/\*.*?\*/)*
947+ |
948+ (?<!:)[^\S\n\r]*//[^\n\r]*
949+ @ismx ' , $ this ->code ['edited ' ], $ this ->code ['inlinecomments ' ], PREG_SET_ORDER );
950+ foreach ($ this ->code ['inlinecomments ' ] as $ key => $ value ) {
951+ $ this ->code ['edited ' ] = str_replace ($ value [0 ], 'inlinecomment ' .$ key .'__ ' , $ this ->code ['edited ' ]);
917952 }
918953
919954 // 5. Закрываем сложности парсинга {}
920955 $ this ->code ['edited ' ] = str_replace ('{} ' , '{ } ' , $ this ->code ['edited ' ]);
921956
922957 // 6. Закрываем сложности с отсутствующей последней ; перед }
923- $ this ->code ['edited ' ] = preg_replace ('@(.*?[^\s;\{\}\/\*])(\s*?})@ ' , '$1;$2 ' , $ this ->code ['edited ' ]);
958+ $ this ->code ['edited ' ] = preg_replace ('@(.*?[^\s;\{\}\/\*_ ])(\s*?})@ ' , '$1;$2 ' , $ this ->code ['edited ' ]);
924959 // Убираем ; у последнего инлайнового комментария
925960 // Инлайновый комментарий может идти только после фигурной скобки или ;
926961 $ this ->code ['edited ' ] = preg_replace ('@([;\{\}]+\s*?//.*?);(\s*?})@ ' , '$1$2 ' , $ this ->code ['edited ' ]);
927962 // Убираем ; у интерполированных переменных
928963 $ this ->code ['edited ' ] = preg_replace ('/((#\{\$|\@\{).*?)[;](\s*?\})/ ' , '$1$3 ' , $ this ->code ['edited ' ]);
929964
930- // 7. Комментарии
931- if (preg_match_all ('@
932- (
933- \s*
934- /\*
935- .*?[^\*/]
936- \*/
937- (\s/\*\*/)?
938- )
939- @ismx ' , $ this ->code ['edited ' ], $ test )) {
940-
941- // 7.1. Закомментировано одно или несколько свойств: повторяющийся паттерн *:*; \s*?
942- if (preg_match_all ('@
943- (\s*)
944- /\*
945- (.*?[^\*/])
946- \*+/
947- (\ {0,1}/\*\*/)?
948- @ismx ' , $ this ->code ['edited ' ], $ comments )) {
949-
950- $ new_comments = Array ();
951- $ old_comments = $ comments [0 ];
952-
953- foreach ($ comments [2 ] as $ key => $ comment ) {
954- if ( // если комментарий содержит ; и :
955- strpos ($ comment , ': ' ) !== FALSE AND
956- strpos ($ comment , '; ' ) !== FALSE
957-
958- ) {
959- preg_match_all ('@
960- (\s*)
961- (
962- .+?[^;]
963- ;
964- )
965- @ismx ' , $ comment , $ properties );
966-
967- $ new_comment = '' ;
968- foreach ($ properties [2 ] as $ property ) {
969- $ new_comment .= $ comments [1 ][$ key ]."commented__ " .$ property ;
970- }
971- $ new_comments [] = $ new_comment ;
972- }
973- else {
974- // если нет : или ;, то считаем что это текстовый комментарий
975- // и копируем его в том виде, в каком он был.
976- $ new_comments [] = $ comments [0 ][$ key ];
977- }
978-
979-
980- }
981-
982- foreach ($ old_comments as $ key => $ old_comment ) {
983- $ this ->code ['edited ' ] = str_replace (
984- $ old_comments [$ key ],
985- $ new_comments [$ key ],
986- $ this ->code ['edited ' ]);
987- }
988- }
989-
990- // 7.2. Обрывки закомментированных деклараций: присутствует { или }
991- if (preg_match_all ('@
992- \s*?
993- /\*
994- (
995- .*?[^\*/]
996- )*?
997- \*+/
998- @ismx ' , $ this ->code ['edited ' ], $ comments )) {
999-
1000- $ new_comments = Array ();
1001- $ old_comments = $ comments [0 ];
1002-
1003- foreach ($ comments [0 ] as $ key => $ comment ) {
1004- if (strpos ($ comment , '} ' ) !== FALSE OR strpos ($ comment , '{ ' ) !== FALSE ) {
1005- $ new_comment = '' ;
1006- if (strpos ($ comment , '} ' ) !== FALSE ) { $ new_comment .= '} ' ; }
1007- $ new_comment .= "brace__ " .$ key ;
1008- if (strpos ($ comment , '{ ' ) !== FALSE ) { $ new_comment .= '{ ' ; }
1009- $ new_comments [$ key ] = $ new_comment ;
1010- $ this ->code ['braces ' ][$ key ] = $ comment ;
1011- }
1012- }
1013-
1014- foreach ($ new_comments as $ key => $ new_comment ) {
1015- if (strlen ($ new_comment ) > 0 ) {
1016- $ this ->code ['edited ' ] = str_replace (
1017- $ old_comments [$ key ],
1018- $ new_comment ,
1019- $ this ->code ['edited ' ]);
1020- }
1021- }
1022- }
1023- }
1024965
1025966 // 8. Entities
1026967 if (preg_match_all ('@
@@ -1181,9 +1122,9 @@ function parse_child($value = '') {
11811122
11821123 // 2. Выносим переменные в отдельный массив $vars
11831124 preg_match_all ('@
1184- (\s*/\*[^\*/]*?\*/)?
1185- (\s*//.*?)?
1125+ (comment\d*__)*
11861126 \s*(\$|\@)[^;\}]+?:[^;]+?;
1127+ (inlinecomment\d*__)*
11871128 @ismx ' , $ value , $ vars );
11881129 // Удаляем их из общей строки
11891130 foreach ($ vars [0 ] as $ var ) {
@@ -1195,29 +1136,32 @@ function parse_child($value = '') {
11951136
11961137 // Включения, следующие сразу за {
11971138 preg_match_all ('@
1198- (^\s*\@[^;]+?[;])|(^\s*\.[^;:]+?[;])
1139+ (^\s*(comment\d*__)*\s*\@[^;]+?[;](inlinecomment\d*__)*)
1140+ |
1141+ (^\s*(comment\d*__)*\s*\.[^;:]+?[;](inlinecomment\d*__)*)
11991142 @isx ' , $ value , $ first_imports );
12001143
12011144 // Все остальные
12021145 preg_match_all ('@
1203- (?<=[;}])(\s*\@[^;]+?[;])|(?<=[;}])(\s*\.[^;:]+?[;])
1146+ (?<=inlinecomment\d__|[;}])
1147+ ((comment\d*__)?\s*\@[^;]+?[;](inlinecomment\d*__)?)
1148+ |
1149+ (?<=inlinecomment\d__|[;}])
1150+ ((comment\d*__)?\s*\.[^;:]+?[;](inlinecomment\d*__)?)
12041151 @ismx ' , $ value , $ imports );
12051152 // Удаляем их из общей строки
12061153 foreach ($ first_imports [0 ] as &$ first_import ) {
12071154 $ value = str_replace ($ first_import , '' , $ value );
12081155 }
1209- foreach ($ imports [1 ] as &$ import ) {
1210- $ value = str_replace ($ import , '' , $ value );
1211- }
1212- foreach ($ imports [2 ] as &$ import ) {
1156+ foreach ($ imports [0 ] as &$ import ) {
12131157 $ value = str_replace ($ import , '' , $ value );
12141158 }
12151159
12161160 // 4. Выносим простые свойства в массив $properties
12171161 preg_match_all ('@
1162+ (comment\d*__)?
12181163 \s*[^;]+?:[^;]+?;
1219- (\s*/\*.*?[^\*/]\*/)?
1220- (\s{0,1}/\*\*/)?
1164+ (inlinecomment\d*__)?
12211165 @ismx ' , $ value , $ properties );
12221166 // Удаляем их из общей строки
12231167 foreach ($ properties [0 ] as &$ property ) {
@@ -1227,11 +1171,9 @@ function parse_child($value = '') {
12271171 $ props = $ properties [0 ];
12281172 $ props = $ this ->resort_properties ($ props );
12291173
1230- // 5. Если осталось ещё что-то, оставляем «как есть»
1231-
12321174 // 6. Склеиваем всё обратно в следующем порядке:
12331175 // переменные, включения, простые свойства, вложенные {}
1234- $ value = implode ('' , $ vars [0 ]).implode ('' , $ first_imports [0 ]).implode ('' , $ imports [1 ]). implode ( '' , $ imports [ 2 ]).implode ('' , $ block_imports ).implode ('' , $ props ).$ nested_string .$ value ;
1176+ $ value = implode ('' , $ vars [0 ]).implode ('' , $ first_imports [0 ]).implode ('' , $ imports [0 ]).implode ('' , $ block_imports ).implode ('' , $ props ).$ nested_string .$ value ;
12351177 return $ value ;
12361178 }
12371179
@@ -1252,7 +1194,6 @@ function parse_properties($css = '') {
12521194 ^
12531195 (.*?)
12541196 (
1255- #(\s*/\*.*\*/;)*?
12561197 \s*?
12571198 }
12581199 )
@@ -1303,17 +1244,15 @@ function parse_properties($css = '') {
13031244
13041245 ^
13051246 (.*?)
1306- (\s*?)
1307- (/\* .* \*/)
1247+ (inlinecomment\d*__)
13081248 (.*)
13091249 $
13101250
13111251 @ismx ' , $ properties , $ matches );
13121252
13131253 if (
13141254 count ($ matches ) === 5 and // все распарсилось как надо
1315- strlen ($ matches [1 ]) === 0 and // комментарий действительно идет первым
1316- strpos ($ matches [2 ], "\n" ) !== 0 // перед комментарием нет переноса строки, следовательно предпологаем, что он относится к скобке с селектором
1255+ strlen ($ matches [1 ]) === 0 // комментарий действительно идет первым
13171256 ) {
13181257 $ first_spaces = $ matches [2 ];
13191258 $ first_comment = $ matches [3 ];
@@ -1330,10 +1269,7 @@ function parse_properties($css = '') {
13301269 .[^;]*
13311270 ;
13321271 ( # На этой же строке (после ;) может быть комментарий. Он тоже пригодится.
1333- \s*
1334- /\*
1335- .*?[^\*/]
1336- \*/
1272+ inlinecomment\d*__
13371273 )
13381274 ?
13391275 (\s{0,1}/\*\*/)?
@@ -1361,8 +1297,7 @@ function parse_properties($css = '') {
13611297 .[^;]* # все что угодно, но не ;
13621298 ;
13631299 ( # На этой же строке (после ;) может быть комментарий. Он тоже пригодится.
1364- \s*
1365- /\* .* \*/
1300+ inlinecomment\d*__
13661301 )
13671302 *?
13681303 )
@@ -1406,9 +1341,7 @@ function resort_properties($prop) {
14061341 * Пробел в начале добавляется специально, чтобы избежать совпадений по вхождению
14071342 * одной строки в другую. Например: top не должно совпадать с border-top
14081343 */
1409- strpos (' ' .trim ($ property ), ' ' .$ k .': ' ) !== FALSE OR
1410- strpos (' ' .trim ($ property ), ' commented__ ' .$ k .': ' ) !== FALSE
1411-
1344+ strpos (' ' .trim ($ property ), ' ' .$ k .': ' ) !== FALSE
14121345 ) {
14131346 $ through_number = $ this ->get_through_number ($ k ); // определяем "сквозной" порядковый номер
14141347 if ($ through_number !== false ) $ index = $ through_number ;
@@ -1421,8 +1354,7 @@ function resort_properties($prop) {
14211354 foreach ($ this ->sort_order as $ pos => $ key ) {
14221355 if (
14231356 // пробел в начале добавляется специально.
1424- strpos (' ' .trim ($ property ), ' ' .$ key .': ' ) !== FALSE OR
1425- strpos (' ' .trim ($ property ), ' commented__ ' .$ key .': ' ) !== FALSE
1357+ strpos (' ' .trim ($ property ), ' ' .$ key .': ' ) !== FALSE
14261358 ) {
14271359 $ index = $ pos ;
14281360 }
@@ -1506,26 +1438,34 @@ function postprocess() {
15061438 }
15071439
15081440 // 4. Interpolated variables
1509- preg_match_all ('#interpolation(\d)__#ismx ' , $ this ->code ['resorted ' ], $ new_vars );
1510- foreach ($ new_vars [1 ] as $ key => $ value ) {
1511- $ this ->code ['resorted ' ] = str_replace ($ new_vars [0 ][$ key ], $ this ->code ['interpolations ' ][0 ][$ key ], $ this ->code ['resorted ' ]);
1441+ if (is_array ($ this ->code ['interpolations ' ])) { // если были обнаружены и вырезаны data uri
1442+ foreach ($ this ->code ['interpolations ' ] as $ key => $ val ) {
1443+ $ this ->code ['resorted ' ] = str_replace ('interpolation ' .$ key .'__ ' , $ val [0 ], $ this ->code ['resorted ' ]); // заменяем значение expression обратно
1444+ }
1445+ }
1446+ // Magic comments
1447+ if (is_array ($ this ->code ['magicComments ' ])) {
1448+ foreach ($ this ->code ['magicComments ' ] as $ key => $ val ) {
1449+ $ this ->code ['resorted ' ] = str_replace ("\nmagic: comment " .$ key .'__; ' , $ val [0 ], $ this ->code ['resorted ' ]);
1450+ }
15121451 }
15131452
1514- // 5. Удаляем искусственно созданные 'commented__'
1515- while ( strpos ( $ this -> code [ ' resorted ' ], ' commented__ ' ) !== FALSE ) {
1516- $ this ->code ['resorted ' ] = preg_replace (
1517- ' #
1518- commented__
1519- (.*?[^:]
1520- :
1521- .*?[^;]
1522- ;)
1523- #ismx ' ,
1524- ' /*$1*/ ' ,
1525- $ this -> code [ ' resorted ' ]
1526- );
1453+
1454+ // Comments
1455+ if ( is_array ( $ this ->code ['inlinecomments ' ])) { // если были обнаружены и вырезаны data uri
1456+ foreach ( $ this -> code [ ' inlinecomments ' ] as $ key => $ val ) {
1457+ $ this -> code [ ' resorted ' ] = str_replace ( ' inlinecomment ' . $ key . ' __ ' , $ val [ 0 ], $ this -> code [ ' resorted ' ]); // заменяем значение expression обратно
1458+ }
1459+ }
1460+ if ( is_array ( $ this -> code [ ' comments ' ])) { // если были обнаружены и вырезаны data uri
1461+ foreach ( $ this -> code [ ' comments ' ] as $ key => $ val ) {
1462+ if ( strpos ( $ this -> code [ ' resorted ' ], ' comment ' . $ key . ' __ ' ) > - 1 ) {
1463+ $ this -> code [ ' resorted ' ] = str_replace ( ' comment ' . $ key . ' __ ' , $ val [ 0 ], $ this -> code [ ' resorted ' ]); // заменяем значение expression обратно
1464+ }
1465+ }
15271466 }
15281467
1468+
15291469 // 6. Удаляем искусственно созданные 'brace__'
15301470 if (is_array ($ this ->code ['braces ' ])) { // если были обнаружены и вырезаны хаки
15311471 foreach ($ this ->code ['braces ' ] as $ key => $ val ) {
0 commit comments