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_SINGLE_QUOTE_ESCAPE = 5 | |
| 21 INSIDE_DOUBLE_QUOTE = 6 | |
| 22 INSIDE_DOUBLE_QUOTE_ESCAPE = 7 | |
| 23 | |
| 24 WHITESPACE_PATTERN = re.compile(r"\s+", re.MULTILINE) | |
|
Timothy Loh
2016/08/10 05:37:39
re.MULTILINE doesn't affect either of these regexe
kouhei (in TOK)
2016/11/01 10:49:16
Done.
| |
| 25 OP_PADDING_PATTERN = re.compile(r";?\s*(?P<op>[\{\};])\s*", re.MULTILINE) | |
|
Timothy Loh
2016/08/10 05:37:39
I don't think you want the backslashes in [\{\};]
kouhei (in TOK)
2016/11/01 10:49:16
Done.
| |
| 26 | |
| 27 def __init__(self): | |
| 28 self._output = '' | |
| 29 self._codeblock = '' | |
| 30 | |
| 31 def flush_codeblock(self): | |
| 32 stripped = re.sub(self.WHITESPACE_PATTERN, ' ', self._codeblock) | |
| 33 stripped = re.sub(self.OP_PADDING_PATTERN, r'\g<op>', stripped) | |
| 34 self._output += stripped | |
| 35 self._codeblock = '' | |
| 36 | |
| 37 def parse(self, content): | |
| 38 state = self.INITIAL | |
| 39 for c in content: | |
| 40 if state == self.INITIAL: | |
| 41 if c == '/': | |
| 42 state = self.MAYBE_COMMENT_START | |
|
Timothy Loh
2016/08/10 05:37:38
"'"
kouhei (in TOK)
2016/11/01 10:49:16
Done.
| |
| 43 elif c == '\'': | |
| 44 self.flush_codeblock() | |
| 45 self._output += c | |
| 46 state = self.INSIDE_SINGLE_QUOTE | |
| 47 elif c == '\"': | |
|
Timothy Loh
2016/08/10 05:37:38
'"'
kouhei (in TOK)
2016/11/01 10:49:16
Done.
| |
| 48 self.flush_codeblock() | |
| 49 self._output += c | |
| 50 state = self.INSIDE_DOUBLE_QUOTE | |
| 51 else: | |
| 52 self._codeblock += c | |
| 53 elif state == self.MAYBE_COMMENT_START: | |
| 54 if c == '*': | |
| 55 self.flush_codeblock() | |
| 56 state = self.INSIDE_COMMENT | |
| 57 else: | |
| 58 self._codeblock += '/' + c | |
| 59 state = self.INITIAL | |
| 60 elif state == self.INSIDE_COMMENT: | |
| 61 if c == '*': | |
| 62 state = self.MAYBE_COMMENT_END | |
| 63 else: | |
| 64 pass | |
| 65 elif state == self.MAYBE_COMMENT_END: | |
| 66 if c == '/': | |
| 67 state = self.INITIAL | |
| 68 else: | |
| 69 state = self.INSIDE_COMMENT | |
| 70 elif state == self.INSIDE_SINGLE_QUOTE: | |
| 71 if c == '\\': | |
| 72 self._output += c | |
| 73 state = self.INSIDE_SINGLE_QUOTE_ESCAPE | |
| 74 elif c == '\'': | |
|
Timothy Loh
2016/08/10 05:37:38
"'"
kouhei (in TOK)
2016/11/01 10:49:16
Done.
| |
| 75 self._output += c | |
| 76 state = self.INITIAL | |
| 77 else: | |
| 78 self._output += c | |
| 79 elif state == self.INSIDE_SINGLE_QUOTE_ESCAPE: | |
| 80 self._output += c | |
| 81 state = self.INSIDE_SINGLE_QUOTE | |
| 82 elif state == self.INSIDE_DOUBLE_QUOTE: | |
| 83 if c == '\\': | |
| 84 self._output += c | |
| 85 state = self.INSIDE_DOUBLE_QUOTE_ESCAPE | |
| 86 elif c == '"': | |
| 87 self._output += c | |
| 88 state = self.INITIAL | |
| 89 else: | |
| 90 self._output += c | |
| 91 elif state == self.INSIDE_DOUBLE_QUOTE_ESCAPE: | |
| 92 self._output += c | |
| 93 state = self.INSIDE_DOUBLE_QUOTE | |
| 94 | |
| 95 self.flush_codeblock() | |
| 96 self._output = self._output.strip() | |
| 97 return self._output | |
| 98 | |
| 99 @property | |
| 100 def output(self): | |
| 101 return self._output | |
| 102 | |
| 103 @classmethod | |
| 104 def minimize_css(cls, content): | |
| 105 minimizer = CSSMinimizer() | |
| 106 minimizer.parse(content) | |
| 107 return minimizer.output | |
| 108 | |
| 109 | |
| 110 class CSSMinimizerWriter(in_generator.GenericWriter): | |
| 111 | |
| 112 def __init__(self, in_file_paths): | |
| 113 super(CSSMinimizerWriter, self).__init__(in_file_paths) | |
| 114 | |
| 115 self._outputs = {} | |
| 116 for in_file_path in in_file_paths: | |
| 117 out_path = os.path.basename(in_file_path) | |
| 118 self._outputs[out_path] = lambda fp=in_file_path: self.generate_impl ementation(fp) | |
|
Timothy Loh
2016/08/10 05:37:39
This line is a bit hard for me to read, I'd use pa
kouhei (in TOK)
2016/11/01 10:49:15
Done.
| |
| 119 | |
| 120 def generate_implementation(self, in_file_path): | |
| 121 content = '' | |
| 122 with open(os.path.abspath(in_file_path)) as in_file: | |
| 123 content = in_file.read() | |
| 124 return CSSMinimizer.minimize_css(content) | |
| 125 | |
| 126 | |
| 127 if __name__ == '__main__': | |
| 128 in_generator.Maker(CSSMinimizerWriter).main(sys.argv) | |
| OLD | NEW |