Completed
Push — dev-4.1-unstable ( 190fa0...5aa386 )
by Felipe A.
01:02
created

HTMLCompress   A

Complexity

Total Complexity 4

Size/Duplication

Total Lines 8
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 8
rs 10
wmc 4

1 Method

Rating   Name   Duplication   Size   Complexity  
A filter_stream() 0 7 4
1
import re
2
3
import jinja2
4
import jinja2.ext
5
import jinja2.lexer
6
7
8
class HTMLCompressFeed(object):
9
    re_whitespace = re.compile('(\"[^\"\\n]*\"|\'[^\'\\n]*\')|([ \\t\\r\\n]+)')
10
    token_class = jinja2.lexer.Token
11
    block_tokens = {
12
        'variable_begin': 'variable_end',
13
        'block_begin': 'block_end'
14
        }
15
16
    def __init__(self):
17
        self.intag = False
18
        self.pending = ''
19
        self.lineno = 0
20
        self.skip_until = None
21
22
    def finalize(self, strip=False):
23
        if self.intag:
24
            data = self._collapse(self.pending)
25
        else:
26
            data = self.pending.rstrip() if strip else self.pending
27
        if data.strip():
28
            yield self.token_class(self.lineno, 'data', data)
29
        self.pending = ''
30
31
    def _collapse(self, data):
32
        return self.re_whitespace.sub(
33
            lambda m: ' ' if m.groups()[-1] else m.group(0),
34
            data
35
            )
36
37
    def feed(self, token):
38
        if self.skip_until:
39
            yield token
40
            if token.type == self.skip_until:
41
                self.skip_until = None
42
            return
43
44
        if token.type in self.block_tokens:
45
            print(token.type)
46
            for data in self.finalize(token.type == 'block_begin'):
47
                yield data
48
            yield token
49
            self.skip_until = self.block_tokens[token.type]
50
            return
51
52
        lineno = self.lineno
53
        size = len(token.value)
54
        value = self.pending + token.value
55
        while value:
56
            lineno = self.lineno if len(value) > size else token.lineno
57
            s, p, value = value.partition('>' if self.intag else '<')
58
            if self.intag:
59
                s = self._collapse(s)
60
                if p:
61
                    self.intag = False
62
                    s = s.rstrip() + p
63
                yield self.token_class(lineno, 'data', s)
64
            elif p:
65
                self.intag = True
66
                s = s + p if s.strip() else p
67
                yield self.token_class(lineno, 'data', s)
68
            else:
69
                value = s
70
                break
71
        self.lineno = lineno
72
        self.pending = value
73
74
75
class HTMLCompress(jinja2.ext.Extension):
76
    def filter_stream(self, stream):
77
        feed = HTMLCompressFeed()
78
        for token in stream:
79
            for data in feed.feed(token):
80
                yield data
81
        for data in feed.finalize():
82
            yield data
83
84
85
def test():
86
    from jinja2 import Environment
87
    env = Environment(extensions=[HTMLCompress])
88
    tmpl = env.from_string('''
89
        <html>
90
          <head>
91
            <title>{{ title }}</title>
92
          </head>
93
          <script type=text/javascript>
94
            if (foo < 42) {
95
              document.write('Foo < Bar');
96
            }
97
          </script>
98
          <body>
99
            <li><a href="{{ href }}" class="a b">{{ title }}</a><br>Test   Foo
100
            <li><a href="{{ href }}">{{ title }}</a><img src=test.png>
101
          </body>
102
        </html>
103
    ''')
104
    print(tmpl.render(title=42, href='index.html'))
105
106
107
if __name__ == '__main__':
108
    test()
109