1var shortenHex = require('./shorten-hex'); 2var shortenHsl = require('./shorten-hsl'); 3var shortenRgb = require('./shorten-rgb'); 4var sortSelectors = require('./sort-selectors'); 5var tidyRules = require('./tidy-rules'); 6var tidyBlock = require('./tidy-block'); 7var tidyAtRule = require('./tidy-at-rule'); 8 9var Hack = require('../hack'); 10var removeUnused = require('../remove-unused'); 11var restoreFromOptimizing = require('../restore-from-optimizing'); 12var wrapForOptimizing = require('../wrap-for-optimizing').all; 13 14var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel; 15 16var Token = require('../../tokenizer/token'); 17var Marker = require('../../tokenizer/marker'); 18 19var formatPosition = require('../../utils/format-position'); 20var split = require('../../utils/split'); 21 22var serializeRules = require('../../writer/one-time').rules; 23 24var IgnoreProperty = 'ignore-property'; 25 26var CHARSET_TOKEN = '@charset'; 27var CHARSET_REGEXP = new RegExp('^' + CHARSET_TOKEN, 'i'); 28 29var DEFAULT_ROUNDING_PRECISION = require('../../options/rounding-precision').DEFAULT; 30 31var WHOLE_PIXEL_VALUE = /(?:^|\s|\()(-?\d+)px/; 32var TIME_VALUE = /^(\-?[\d\.]+)(m?s)$/; 33 34var HEX_VALUE_PATTERN = /[0-9a-f]/i; 35var PROPERTY_NAME_PATTERN = /^(?:\-chrome\-|\-[\w\-]+\w|\w[\w\-]+\w|\-\-\S+)$/; 36var IMPORT_PREFIX_PATTERN = /^@import/i; 37var QUOTED_PATTERN = /^('.*'|".*")$/; 38var QUOTED_BUT_SAFE_PATTERN = /^['"][a-zA-Z][a-zA-Z\d\-_]+['"]$/; 39var URL_PREFIX_PATTERN = /^url\(/i; 40var LOCAL_PREFIX_PATTERN = /^local\(/i; 41var VARIABLE_NAME_PATTERN = /^--\S+$/; 42 43function isLocal(value){ 44 return LOCAL_PREFIX_PATTERN.test(value); 45} 46 47function isNegative(value) { 48 return value && value[1][0] == '-' && parseFloat(value[1]) < 0; 49} 50 51function isQuoted(value) { 52 return QUOTED_PATTERN.test(value); 53} 54 55function isUrl(value) { 56 return URL_PREFIX_PATTERN.test(value); 57} 58 59function normalizeUrl(value) { 60 return value 61 .replace(URL_PREFIX_PATTERN, 'url(') 62 .replace(/\\?\n|\\?\r\n/g, ''); 63} 64 65function optimizeBackground(property) { 66 var values = property.value; 67 68 if (values.length == 1 && values[0][1] == 'none') { 69 values[0][1] = '0 0'; 70 } 71 72 if (values.length == 1 && values[0][1] == 'transparent') { 73 values[0][1] = '0 0'; 74 } 75} 76 77function optimizeBorderRadius(property) { 78 var values = property.value; 79 var spliceAt; 80 81 if (values.length == 3 && values[1][1] == '/' && values[0][1] == values[2][1]) { 82 spliceAt = 1; 83 } else if (values.length == 5 && values[2][1] == '/' && values[0][1] == values[3][1] && values[1][1] == values[4][1]) { 84 spliceAt = 2; 85 } else if (values.length == 7 && values[3][1] == '/' && values[0][1] == values[4][1] && values[1][1] == values[5][1] && values[2][1] == values[6][1]) { 86 spliceAt = 3; 87 } else if (values.length == 9 && values[4][1] == '/' && values[0][1] == values[5][1] && values[1][1] == values[6][1] && values[2][1] == values[7][1] && values[3][1] == values[8][1]) { 88 spliceAt = 4; 89 } 90 91 if (spliceAt) { 92 property.value.splice(spliceAt); 93 property.dirty = true; 94 } 95} 96 97/** 98 * @param {string} name 99 * @param {string} value 100 * @param {Object} compatibility 101 * @return {string} 102 */ 103function optimizeColors(name, value, compatibility) { 104 if (!value.match(/#|rgb|hsl/gi)) { 105 return shortenHex(value); 106 } 107 108 value = value 109 .replace(/(rgb|hsl)a?\((\-?\d+),(\-?\d+\%?),(\-?\d+\%?),(0*[1-9]+[0-9]*(\.?\d*)?)\)/gi, function (match, colorFn, p1, p2, p3, alpha) { 110 return (parseInt(alpha, 10) >= 1 ? colorFn + '(' + [p1,p2,p3].join(',') + ')' : match); 111 }) 112 .replace(/rgb\((\-?\d+),(\-?\d+),(\-?\d+)\)/gi, function (match, red, green, blue) { 113 return shortenRgb(red, green, blue); 114 }) 115 .replace(/hsl\((-?\d+),(-?\d+)%?,(-?\d+)%?\)/gi, function (match, hue, saturation, lightness) { 116 return shortenHsl(hue, saturation, lightness); 117 }) 118 .replace(/(^|[^='"])#([0-9a-f]{6})/gi, function (match, prefix, color, at, inputValue) { 119 var suffix = inputValue[at + match.length]; 120 121 if (suffix && HEX_VALUE_PATTERN.test(suffix)) { 122 return match; 123 } else if (color[0] == color[1] && color[2] == color[3] && color[4] == color[5]) { 124 return (prefix + '#' + color[0] + color[2] + color[4]).toLowerCase(); 125 } else { 126 return (prefix + '#' + color).toLowerCase(); 127 } 128 }) 129 .replace(/(^|[^='"])#([0-9a-f]{3})/gi, function (match, prefix, color) { 130 return prefix + '#' + color.toLowerCase(); 131 }) 132 .replace(/(rgb|rgba|hsl|hsla)\(([^\)]+)\)/gi, function (match, colorFunction, colorDef) { 133 var tokens = colorDef.split(','); 134 var colorFnLowercase = colorFunction && colorFunction.toLowerCase(); 135 var applies = (colorFnLowercase == 'hsl' && tokens.length == 3) || 136 (colorFnLowercase == 'hsla' && tokens.length == 4) || 137 (colorFnLowercase == 'rgb' && tokens.length === 3 && colorDef.indexOf('%') > 0) || 138 (colorFnLowercase == 'rgba' && tokens.length == 4 && colorDef.indexOf('%') > 0); 139 140 if (!applies) { 141 return match; 142 } 143 144 if (tokens[1].indexOf('%') == -1) { 145 tokens[1] += '%'; 146 } 147 148 if (tokens[2].indexOf('%') == -1) { 149 tokens[2] += '%'; 150 } 151 152 return colorFunction + '(' + tokens.join(',') + ')'; 153 }); 154 155 if (compatibility.colors.opacity && name.indexOf('background') == -1) { 156 value = value.replace(/(?:rgba|hsla)\(0,0%?,0%?,0\)/g, function (match) { 157 if (split(value, ',').pop().indexOf('gradient(') > -1) { 158 return match; 159 } 160 161 return 'transparent'; 162 }); 163 } 164 165 return shortenHex(value); 166} 167 168function optimizeFilter(property) { 169 if (property.value.length == 1) { 170 property.value[0][1] = property.value[0][1].replace(/progid:DXImageTransform\.Microsoft\.(Alpha|Chroma)(\W)/, function (match, filter, suffix) { 171 return filter.toLowerCase() + suffix; 172 }); 173 } 174 175 property.value[0][1] = property.value[0][1] 176 .replace(/,(\S)/g, ', $1') 177 .replace(/ ?= ?/g, '='); 178} 179 180function optimizeFontWeight(property, atIndex) { 181 var value = property.value[atIndex][1]; 182 183 if (value == 'normal') { 184 value = '400'; 185 } else if (value == 'bold') { 186 value = '700'; 187 } 188 189 property.value[atIndex][1] = value; 190} 191 192function optimizeMultipleZeros(property) { 193 var values = property.value; 194 var spliceAt; 195 196 if (values.length == 4 && values[0][1] === '0' && values[1][1] === '0' && values[2][1] === '0' && values[3][1] === '0') { 197 if (property.name.indexOf('box-shadow') > -1) { 198 spliceAt = 2; 199 } else { 200 spliceAt = 1; 201 } 202 } 203 204 if (spliceAt) { 205 property.value.splice(spliceAt); 206 property.dirty = true; 207 } 208} 209 210function optimizeOutline(property) { 211 var values = property.value; 212 213 if (values.length == 1 && values[0][1] == 'none') { 214 values[0][1] = '0'; 215 } 216} 217 218function optimizePixelLengths(_, value, compatibility) { 219 if (!WHOLE_PIXEL_VALUE.test(value)) { 220 return value; 221 } 222 223 return value.replace(WHOLE_PIXEL_VALUE, function (match, val) { 224 var newValue; 225 var intVal = parseInt(val); 226 227 if (intVal === 0) { 228 return match; 229 } 230 231 if (compatibility.properties.shorterLengthUnits && compatibility.units.pt && intVal * 3 % 4 === 0) { 232 newValue = intVal * 3 / 4 + 'pt'; 233 } 234 235 if (compatibility.properties.shorterLengthUnits && compatibility.units.pc && intVal % 16 === 0) { 236 newValue = intVal / 16 + 'pc'; 237 } 238 239 if (compatibility.properties.shorterLengthUnits && compatibility.units.in && intVal % 96 === 0) { 240 newValue = intVal / 96 + 'in'; 241 } 242 243 if (newValue) { 244 newValue = match.substring(0, match.indexOf(val)) + newValue; 245 } 246 247 return newValue && newValue.length < match.length ? newValue : match; 248 }); 249} 250 251function optimizePrecision(_, value, precisionOptions) { 252 if (!precisionOptions.enabled || value.indexOf('.') === -1) { 253 return value; 254 } 255 256 return value 257 .replace(precisionOptions.decimalPointMatcher, '$1$2$3') 258 .replace(precisionOptions.zeroMatcher, function (match, integerPart, fractionPart, unit) { 259 var multiplier = precisionOptions.units[unit].multiplier; 260 var parsedInteger = parseInt(integerPart); 261 var integer = isNaN(parsedInteger) ? 0 : parsedInteger; 262 var fraction = parseFloat(fractionPart); 263 264 return Math.round((integer + fraction) * multiplier) / multiplier + unit; 265 }); 266} 267 268function optimizeTimeUnits(_, value) { 269 if (!TIME_VALUE.test(value)) 270 return value; 271 272 return value.replace(TIME_VALUE, function (match, val, unit) { 273 var newValue; 274 275 if (unit == 'ms') { 276 newValue = parseInt(val) / 1000 + 's'; 277 } else if (unit == 's') { 278 newValue = parseFloat(val) * 1000 + 'ms'; 279 } 280 281 return newValue.length < match.length ? newValue : match; 282 }); 283} 284 285function optimizeUnits(name, value, unitsRegexp) { 286 if (/^(?:\-moz\-calc|\-webkit\-calc|calc|rgb|hsl|rgba|hsla)\(/.test(value)) { 287 return value; 288 } 289 290 if (name == 'flex' || name == '-ms-flex' || name == '-webkit-flex' || name == 'flex-basis' || name == '-webkit-flex-basis') { 291 return value; 292 } 293 294 if (value.indexOf('%') > 0 && (name == 'height' || name == 'max-height' || name == 'width' || name == 'max-width')) { 295 return value; 296 } 297 298 return value 299 .replace(unitsRegexp, '$1' + '0' + '$2') 300 .replace(unitsRegexp, '$1' + '0' + '$2'); 301} 302 303function optimizeWhitespace(name, value) { 304 if (name.indexOf('filter') > -1 || value.indexOf(' ') == -1 || value.indexOf('expression') === 0) { 305 return value; 306 } 307 308 if (value.indexOf(Marker.SINGLE_QUOTE) > -1 || value.indexOf(Marker.DOUBLE_QUOTE) > -1) { 309 return value; 310 } 311 312 value = value.replace(/\s+/g, ' '); 313 314 if (value.indexOf('calc') > -1) { 315 value = value.replace(/\) ?\/ ?/g, ')/ '); 316 } 317 318 return value 319 .replace(/(\(;?)\s+/g, '$1') 320 .replace(/\s+(;?\))/g, '$1') 321 .replace(/, /g, ','); 322} 323 324function optimizeZeroDegUnit(_, value) { 325 if (value.indexOf('0deg') == -1) { 326 return value; 327 } 328 329 return value.replace(/\(0deg\)/g, '(0)'); 330} 331 332function optimizeZeroUnits(name, value) { 333 if (value.indexOf('0') == -1) { 334 return value; 335 } 336 337 if (value.indexOf('-') > -1) { 338 value = value 339 .replace(/([^\w\d\-]|^)\-0([^\.]|$)/g, '$10$2') 340 .replace(/([^\w\d\-]|^)\-0([^\.]|$)/g, '$10$2'); 341 } 342 343 return value 344 .replace(/(^|\s)0+([1-9])/g, '$1$2') 345 .replace(/(^|\D)\.0+(\D|$)/g, '$10$2') 346 .replace(/(^|\D)\.0+(\D|$)/g, '$10$2') 347 .replace(/\.([1-9]*)0+(\D|$)/g, function (match, nonZeroPart, suffix) { 348 return (nonZeroPart.length > 0 ? '.' : '') + nonZeroPart + suffix; 349 }) 350 .replace(/(^|\D)0\.(\d)/g, '$1.$2'); 351} 352 353function removeQuotes(name, value) { 354 if (name == 'content' || name.indexOf('font-variation-settings') > -1 || name.indexOf('font-feature-settings') > -1 || name == 'grid' || name.indexOf('grid-') > -1) { 355 return value; 356 } 357 358 return QUOTED_BUT_SAFE_PATTERN.test(value) ? 359 value.substring(1, value.length - 1) : 360 value; 361} 362 363function removeUrlQuotes(value) { 364 return /^url\(['"].+['"]\)$/.test(value) && !/^url\(['"].*[\*\s\(\)'"].*['"]\)$/.test(value) && !/^url\(['"]data:[^;]+;charset/.test(value) ? 365 value.replace(/["']/g, '') : 366 value; 367} 368 369function transformValue(propertyName, propertyValue, rule, transformCallback) { 370 var selector = serializeRules(rule); 371 var transformedValue = transformCallback(propertyName, propertyValue, selector); 372 373 if (transformedValue === undefined) { 374 return propertyValue; 375 } else if (transformedValue === false) { 376 return IgnoreProperty; 377 } else { 378 return transformedValue; 379 } 380} 381 382// 383 384function optimizeBody(rule, properties, context) { 385 var options = context.options; 386 var levelOptions = options.level[OptimizationLevel.One]; 387 var property, name, type, value; 388 var valueIsUrl; 389 var propertyToken; 390 var _properties = wrapForOptimizing(properties, true); 391 392 propertyLoop: 393 for (var i = 0, l = _properties.length; i < l; i++) { 394 property = _properties[i]; 395 name = property.name; 396 397 if (!PROPERTY_NAME_PATTERN.test(name)) { 398 propertyToken = property.all[property.position]; 399 context.warnings.push('Invalid property name \'' + name + '\' at ' + formatPosition(propertyToken[1][2][0]) + '. Ignoring.'); 400 property.unused = true; 401 } 402 403 if (property.value.length === 0) { 404 propertyToken = property.all[property.position]; 405 context.warnings.push('Empty property \'' + name + '\' at ' + formatPosition(propertyToken[1][2][0]) + '. Ignoring.'); 406 property.unused = true; 407 } 408 409 if (property.hack && ( 410 (property.hack[0] == Hack.ASTERISK || property.hack[0] == Hack.UNDERSCORE) && !options.compatibility.properties.iePrefixHack || 411 property.hack[0] == Hack.BACKSLASH && !options.compatibility.properties.ieSuffixHack || 412 property.hack[0] == Hack.BANG && !options.compatibility.properties.ieBangHack)) { 413 property.unused = true; 414 } 415 416 if (levelOptions.removeNegativePaddings && name.indexOf('padding') === 0 && (isNegative(property.value[0]) || isNegative(property.value[1]) || isNegative(property.value[2]) || isNegative(property.value[3]))) { 417 property.unused = true; 418 } 419 420 if (!options.compatibility.properties.ieFilters && isLegacyFilter(property)) { 421 property.unused = true; 422 } 423 424 if (property.unused) { 425 continue; 426 } 427 428 if (property.block) { 429 optimizeBody(rule, property.value[0][1], context); 430 continue; 431 } 432 433 if (VARIABLE_NAME_PATTERN.test(name)) { 434 continue; 435 } 436 437 for (var j = 0, m = property.value.length; j < m; j++) { 438 type = property.value[j][0]; 439 value = property.value[j][1]; 440 valueIsUrl = isUrl(value); 441 442 if (type == Token.PROPERTY_BLOCK) { 443 property.unused = true; 444 context.warnings.push('Invalid value token at ' + formatPosition(value[0][1][2][0]) + '. Ignoring.'); 445 break; 446 } 447 448 if (valueIsUrl && !context.validator.isUrl(value)) { 449 property.unused = true; 450 context.warnings.push('Broken URL \'' + value + '\' at ' + formatPosition(property.value[j][2][0]) + '. Ignoring.'); 451 break; 452 } 453 454 if (valueIsUrl) { 455 value = levelOptions.normalizeUrls ? 456 normalizeUrl(value) : 457 value; 458 value = !options.compatibility.properties.urlQuotes ? 459 removeUrlQuotes(value) : 460 value; 461 } else if (isQuoted(value) || isLocal(value)) { 462 value = levelOptions.removeQuotes ? 463 removeQuotes(name, value) : 464 value; 465 } else { 466 value = levelOptions.removeWhitespace ? 467 optimizeWhitespace(name, value) : 468 value; 469 value = optimizePrecision(name, value, options.precision); 470 value = optimizePixelLengths(name, value, options.compatibility); 471 value = levelOptions.replaceTimeUnits ? 472 optimizeTimeUnits(name, value) : 473 value; 474 value = levelOptions.replaceZeroUnits ? 475 optimizeZeroUnits(name, value) : 476 value; 477 478 if (options.compatibility.properties.zeroUnits) { 479 value = optimizeZeroDegUnit(name, value); 480 value = optimizeUnits(name, value, options.unitsRegexp); 481 } 482 483 if (options.compatibility.properties.colors) { 484 value = optimizeColors(name, value, options.compatibility); 485 } 486 } 487 488 value = transformValue(name, value, rule, levelOptions.transform); 489 490 if (value === IgnoreProperty) { 491 property.unused = true; 492 continue propertyLoop; 493 } 494 495 property.value[j][1] = value; 496 } 497 498 if (levelOptions.replaceMultipleZeros) { 499 optimizeMultipleZeros(property); 500 } 501 502 if (name == 'background' && levelOptions.optimizeBackground) { 503 optimizeBackground(property); 504 } else if (name.indexOf('border') === 0 && name.indexOf('radius') > 0 && levelOptions.optimizeBorderRadius) { 505 optimizeBorderRadius(property); 506 } else if (name == 'filter'&& levelOptions.optimizeFilter && options.compatibility.properties.ieFilters) { 507 optimizeFilter(property); 508 } else if (name == 'font-weight' && levelOptions.optimizeFontWeight) { 509 optimizeFontWeight(property, 0); 510 } else if (name == 'outline' && levelOptions.optimizeOutline) { 511 optimizeOutline(property); 512 } 513 } 514 515 restoreFromOptimizing(_properties); 516 removeUnused(_properties); 517 removeComments(properties, options); 518} 519 520function removeComments(tokens, options) { 521 var token; 522 var i; 523 524 for (i = 0; i < tokens.length; i++) { 525 token = tokens[i]; 526 527 if (token[0] != Token.COMMENT) { 528 continue; 529 } 530 531 optimizeComment(token, options); 532 533 if (token[1].length === 0) { 534 tokens.splice(i, 1); 535 i--; 536 } 537 } 538} 539 540function optimizeComment(token, options) { 541 if (token[1][2] == Marker.EXCLAMATION && (options.level[OptimizationLevel.One].specialComments == 'all' || options.commentsKept < options.level[OptimizationLevel.One].specialComments)) { 542 options.commentsKept++; 543 return; 544 } 545 546 token[1] = []; 547} 548 549function cleanupCharsets(tokens) { 550 var hasCharset = false; 551 552 for (var i = 0, l = tokens.length; i < l; i++) { 553 var token = tokens[i]; 554 555 if (token[0] != Token.AT_RULE) 556 continue; 557 558 if (!CHARSET_REGEXP.test(token[1])) 559 continue; 560 561 if (hasCharset || token[1].indexOf(CHARSET_TOKEN) == -1) { 562 tokens.splice(i, 1); 563 i--; 564 l--; 565 } else { 566 hasCharset = true; 567 tokens.splice(i, 1); 568 tokens.unshift([Token.AT_RULE, token[1].replace(CHARSET_REGEXP, CHARSET_TOKEN)]); 569 } 570 } 571} 572 573function buildUnitRegexp(options) { 574 var units = ['px', 'em', 'ex', 'cm', 'mm', 'in', 'pt', 'pc', '%']; 575 var otherUnits = ['ch', 'rem', 'vh', 'vm', 'vmax', 'vmin', 'vw']; 576 577 otherUnits.forEach(function (unit) { 578 if (options.compatibility.units[unit]) { 579 units.push(unit); 580 } 581 }); 582 583 return new RegExp('(^|\\s|\\(|,)0(?:' + units.join('|') + ')(\\W|$)', 'g'); 584} 585 586function buildPrecisionOptions(roundingPrecision) { 587 var precisionOptions = { 588 matcher: null, 589 units: {}, 590 }; 591 var optimizable = []; 592 var unit; 593 var value; 594 595 for (unit in roundingPrecision) { 596 value = roundingPrecision[unit]; 597 598 if (value != DEFAULT_ROUNDING_PRECISION) { 599 precisionOptions.units[unit] = {}; 600 precisionOptions.units[unit].value = value; 601 precisionOptions.units[unit].multiplier = Math.pow(10, value); 602 603 optimizable.push(unit); 604 } 605 } 606 607 if (optimizable.length > 0) { 608 precisionOptions.enabled = true; 609 precisionOptions.decimalPointMatcher = new RegExp('(\\d)\\.($|' + optimizable.join('|') + ')($|\\W)', 'g'); 610 precisionOptions.zeroMatcher = new RegExp('(\\d*)(\\.\\d+)(' + optimizable.join('|') + ')', 'g'); 611 } 612 613 return precisionOptions; 614} 615 616function isImport(token) { 617 return IMPORT_PREFIX_PATTERN.test(token[1]); 618} 619 620function isLegacyFilter(property) { 621 var value; 622 623 if (property.name == 'filter' || property.name == '-ms-filter') { 624 value = property.value[0][1]; 625 626 return value.indexOf('progid') > -1 || 627 value.indexOf('alpha') === 0 || 628 value.indexOf('chroma') === 0; 629 } else { 630 return false; 631 } 632} 633 634function level1Optimize(tokens, context) { 635 var options = context.options; 636 var levelOptions = options.level[OptimizationLevel.One]; 637 var ie7Hack = options.compatibility.selectors.ie7Hack; 638 var adjacentSpace = options.compatibility.selectors.adjacentSpace; 639 var spaceAfterClosingBrace = options.compatibility.properties.spaceAfterClosingBrace; 640 var format = options.format; 641 var mayHaveCharset = false; 642 var afterRules = false; 643 644 options.unitsRegexp = options.unitsRegexp || buildUnitRegexp(options); 645 options.precision = options.precision || buildPrecisionOptions(levelOptions.roundingPrecision); 646 options.commentsKept = options.commentsKept || 0; 647 648 for (var i = 0, l = tokens.length; i < l; i++) { 649 var token = tokens[i]; 650 651 switch (token[0]) { 652 case Token.AT_RULE: 653 token[1] = isImport(token) && afterRules ? '' : token[1]; 654 token[1] = levelOptions.tidyAtRules ? tidyAtRule(token[1]) : token[1]; 655 mayHaveCharset = true; 656 break; 657 case Token.AT_RULE_BLOCK: 658 optimizeBody(token[1], token[2], context); 659 afterRules = true; 660 break; 661 case Token.NESTED_BLOCK: 662 token[1] = levelOptions.tidyBlockScopes ? tidyBlock(token[1], spaceAfterClosingBrace) : token[1]; 663 level1Optimize(token[2], context); 664 afterRules = true; 665 break; 666 case Token.COMMENT: 667 optimizeComment(token, options); 668 break; 669 case Token.RULE: 670 token[1] = levelOptions.tidySelectors ? tidyRules(token[1], !ie7Hack, adjacentSpace, format, context.warnings) : token[1]; 671 token[1] = token[1].length > 1 ? sortSelectors(token[1], levelOptions.selectorsSortingMethod) : token[1]; 672 optimizeBody(token[1], token[2], context); 673 afterRules = true; 674 break; 675 } 676 677 if (token[0] == Token.COMMENT && token[1].length === 0 || levelOptions.removeEmpty && (token[1].length === 0 || (token[2] && token[2].length === 0))) { 678 tokens.splice(i, 1); 679 i--; 680 l--; 681 } 682 } 683 684 if (levelOptions.cleanupCharsets && mayHaveCharset) { 685 cleanupCharsets(tokens); 686 } 687 688 return tokens; 689} 690 691module.exports = level1Optimize; 692