Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 6 import os.path | |
| 7 import re | |
| 8 import sys | |
| 9 | |
| 10 import in_generator | |
| 11 | |
| 12 | |
| 13 class CSSMinimizer(object): | |
| 14 | |
| 15 INITIAL = 0 | |
| 16 MAYBE_COMMENT_START = 1 | |
| 17 INSIDE_COMMENT = 2 | |
| 18 MAYBE_COMMENT_END = 3 | |
| 19 INSIDE_SINGLE_QUOTE = 4 | |
| 20 INSIDE_DOUBLE_QUOTE = 5 | |
| 21 | |
| 22 WHITESPACE_PATTERN = re.compile(r"\s+", re.MULTILINE) | |
| 23 WHITESPACE_PATTERN = re.compile(r"\s+", re.MULTILINE) | |
|
esprehn
2016/06/27 05:17:31
You have this twice
kouhei (in TOK)
2016/06/27 05:39:22
Done.
| |
| 24 OP_PADDING_PATTERN = re.compile(r";?\s*(?P<op>[\{\};])\s*", re.MULTILINE) | |
| 25 | |
| 26 def __init__(self): | |
| 27 self._output = '' | |
| 28 self._codeblock = '' | |
| 29 | |
| 30 def flush_codeblock(self): | |
| 31 stripped = re.sub(self.WHITESPACE_PATTERN, ' ', self._codeblock) | |
| 32 stripped = re.sub(self.OP_PADDING_PATTERN, r'\g<op>', stripped) | |
| 33 self._output += stripped | |
| 34 self._codeblock = '' | |
| 35 | |
| 36 def parse(self, content): | |
| 37 state = self.INITIAL | |
| 38 for c in content: | |
| 39 if state == self.INITIAL: | |
| 40 if c == '/': | |
| 41 state = self.MAYBE_COMMENT_START | |
| 42 elif c == '\'': | |
| 43 self.flush_codeblock() | |
| 44 self._output += c | |
| 45 state = self.INSIDE_SINGLE_QUOTE | |
| 46 elif c == '\"': | |
| 47 self.flush_codeblock() | |
| 48 self._output += c | |
| 49 state = self.INSIDE_DOUBLE_QUOTE | |
| 50 else: | |
| 51 self._codeblock += c | |
| 52 elif state == self.MAYBE_COMMENT_START: | |
| 53 if c == '*': | |
| 54 self.flush_codeblock() | |
| 55 state = self.INSIDE_COMMENT | |
| 56 else: | |
| 57 self._codeblock += '/' + c | |
| 58 state = self.INITIAL | |
| 59 elif state == self.INSIDE_COMMENT: | |
| 60 if c == '*': | |
| 61 state = self.MAYBE_COMMENT_END | |
| 62 else: | |
| 63 pass | |
| 64 elif state == self.MAYBE_COMMENT_END: | |
| 65 if c == '/': | |
| 66 state = self.INITIAL | |
| 67 else: | |
| 68 state = self.INSIDE_COMMENT | |
| 69 elif state == self.INSIDE_SINGLE_QUOTE: | |
| 70 if c == '\'': | |
| 71 self._output += c | |
| 72 state = self.INITIAL | |
| 73 else: | |
|
esprehn
2016/06/27 05:17:31
This is a lot of code to not have any tests...
kouhei (in TOK)
2016/06/27 05:39:22
Ack. I'll add test before commit.
kouhei (in TOK)
2016/07/05 05:11:09
Done.
| |
| 74 self._output += c | |
| 75 elif state == self.INSIDE_DOUBLE_QUOTE: | |
| 76 if c == '"': | |
| 77 self._output += c | |
| 78 state = self.INITIAL | |
| 79 else: | |
| 80 self._output += c | |
| 81 | |
| 82 return self._output | |
| 83 | |
| 84 @property | |
| 85 def output(self): | |
| 86 return self._output | |
| 87 | |
| 88 @classmethod | |
| 89 def minimize_css(cls, content): | |
| 90 minimizer = CSSMinimizer() | |
| 91 minimizer.parse(content) | |
| 92 return minimizer.output | |
| 93 | |
| 94 | |
| 95 class CSSMinimizerWriter(in_generator.GenericWriter): | |
| 96 | |
| 97 def __init__(self, in_file_paths): | |
| 98 super(CSSMinimizerWriter, self).__init__(in_file_paths) | |
| 99 | |
| 100 self._outputs = {} | |
| 101 for in_file_path in in_file_paths: | |
| 102 out_path = os.path.basename(in_file_path) | |
| 103 self._outputs[out_path] = lambda fp=in_file_path: self.generate_impl ementation(fp) | |
| 104 | |
| 105 def generate_implementation(self, in_file_path): | |
| 106 content = '' | |
| 107 with open(os.path.abspath(in_file_path)) as in_file: | |
| 108 content = in_file.read() | |
| 109 return CSSMinimizer.minimize_css(content) | |
| 110 | |
| 111 | |
| 112 if __name__ == '__main__': | |
| 113 in_generator.Maker(CSSMinimizerWriter).main(sys.argv) | |
| OLD | NEW |