1#!/usr/bin/env python 2# Copyright 2016 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import re 7import sys 8 9class CSSMinimizer(object): 10 11 INITIAL = 0 12 MAYBE_COMMENT_START = 1 13 INSIDE_COMMENT = 2 14 MAYBE_COMMENT_END = 3 15 INSIDE_SINGLE_QUOTE = 4 16 INSIDE_SINGLE_QUOTE_ESCAPE = 5 17 INSIDE_DOUBLE_QUOTE = 6 18 INSIDE_DOUBLE_QUOTE_ESCAPE = 7 19 20 def __init__(self): 21 self._output = '' 22 self._codeblock = '' 23 24 def flush_codeblock(self): 25 stripped = re.sub(r"\s+", ' ', self._codeblock) 26 stripped = re.sub(r";?\s*(?P<op>[{};])\s*", r'\g<op>', stripped) 27 self._output += stripped 28 self._codeblock = '' 29 30 def parse(self, content): 31 state = self.INITIAL 32 for char in content: 33 if state == self.INITIAL: 34 if char == '/': 35 state = self.MAYBE_COMMENT_START 36 elif char == "'": 37 self.flush_codeblock() 38 self._output += char 39 state = self.INSIDE_SINGLE_QUOTE 40 elif char == '"': 41 self.flush_codeblock() 42 self._output += char 43 state = self.INSIDE_DOUBLE_QUOTE 44 else: 45 self._codeblock += char 46 elif state == self.MAYBE_COMMENT_START: 47 if char == '*': 48 self.flush_codeblock() 49 state = self.INSIDE_COMMENT 50 else: 51 self._codeblock += '/' + char 52 state = self.INITIAL 53 elif state == self.INSIDE_COMMENT: 54 if char == '*': 55 state = self.MAYBE_COMMENT_END 56 else: 57 pass 58 elif state == self.MAYBE_COMMENT_END: 59 if char == '/': 60 state = self.INITIAL 61 else: 62 state = self.INSIDE_COMMENT 63 elif state == self.INSIDE_SINGLE_QUOTE: 64 if char == '\\': 65 self._output += char 66 state = self.INSIDE_SINGLE_QUOTE_ESCAPE 67 elif char == "'": 68 self._output += char 69 state = self.INITIAL 70 else: 71 self._output += char 72 elif state == self.INSIDE_SINGLE_QUOTE_ESCAPE: 73 self._output += char 74 state = self.INSIDE_SINGLE_QUOTE 75 elif state == self.INSIDE_DOUBLE_QUOTE: 76 if char == '\\': 77 self._output += char 78 state = self.INSIDE_DOUBLE_QUOTE_ESCAPE 79 elif char == '"': 80 self._output += char 81 state = self.INITIAL 82 else: 83 self._output += char 84 elif state == self.INSIDE_DOUBLE_QUOTE_ESCAPE: 85 self._output += char 86 state = self.INSIDE_DOUBLE_QUOTE 87 88 self.flush_codeblock() 89 self._output = self._output.strip() 90 return self._output 91 92 @classmethod 93 def minimize_css(cls, content): 94 minimizer = CSSMinimizer() 95 return minimizer.parse(content) 96 97def main(): 98 result = '' 99 try: 100 result = CSSMinimizer.minimize_css(sys.stdin.read()) 101 finally: 102 print(result) 103 104if __name__ == '__main__': 105 main() 106