1# The MIT License (MIT) 2# 3# Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. 4# 5# Permission is hereby granted, free of charge, to any person 6# obtaining a copy of this software and associated documentation files 7# (the "Software"), to deal in the Software without restriction, 8# including without limitation the rights to use, copy, modify, merge, 9# publish, distribute, sublicense, and/or sell copies of the Software, 10# and to permit persons to whom the Software is furnished to do so, 11# subject to the following conditions: 12# 13# The above copyright notice and this permission notice shall be 14# included in all copies or substantial portions of the Software. 15# 16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 20# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 21# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23# SOFTWARE. 24 25import copy 26from ..core.pattern import Pattern 27 28__all__ = ["TemplatablePattern"] 29 30class TemplateNames: 31 def __init__(self): 32 self.django = False 33 self.erb = False 34 self.handlebars = False 35 self.php = False 36 37class TemplatePatterns: 38 def __init__(self, input_scanner): 39 pattern = Pattern(input_scanner) 40 self.handlebars_comment = pattern.starting_with(r'{{!--').until_after(r'--}}') 41 self.handlebars_unescaped = pattern.starting_with(r'{{{').until_after(r'}}}') 42 self.handlebars = pattern.starting_with(r'{{').until_after(r'}}') 43 self.php = pattern.starting_with(r'<\?(?:[=]|php)').until_after(r'\?>') 44 self.erb = pattern.starting_with(r'<%[^%]').until_after(r'[^%]%>') 45 # django coflicts with handlebars a bit. 46 self.django = pattern.starting_with(r'{%').until_after(r'%}') 47 self.django_value = pattern.starting_with(r'{{').until_after(r'}}') 48 self.django_comment = pattern.starting_with(r'{#').until_after(r'#}') 49 50class TemplatablePattern(Pattern): 51 52 def __init__(self, input_scanner, parent=None): 53 Pattern.__init__(self, input_scanner, parent) 54 self.__template_pattern = None 55 self._disabled = TemplateNames() 56 self._excluded = TemplateNames() 57 58 if parent is not None: 59 self.__template_pattern = \ 60 self._input.get_regexp(parent.__template_pattern) 61 self._disabled = copy.copy(parent._disabled) 62 self._excluded = copy.copy(parent._excluded) 63 64 self.__patterns = TemplatePatterns(input_scanner) 65 66 def _create(self): 67 return TemplatablePattern(self._input, self) 68 69 def _update(self): 70 self.__set_templated_pattern() 71 72 def read_options(self, options): 73 result = self._create() 74 for language in ['django', 'erb', 'handlebars', 'php']: 75 setattr(result._disabled, language, 76 not (language in options.templating)) 77 result._update() 78 return result 79 80 def disable(self, language): 81 result = self._create() 82 setattr(result._disabled, language, True) 83 result._update() 84 return result 85 86 def exclude(self, language): 87 result = self._create() 88 setattr(result._excluded, language, True) 89 result._update() 90 return result 91 92 def read(self): 93 result = '' 94 if bool(self._match_pattern): 95 result = self._input.read(self._starting_pattern) 96 else: 97 result = self._input.read(self._starting_pattern, 98 self.__template_pattern) 99 100 next = self._read_template() 101 102 while (bool(next)): 103 if self._match_pattern is not None: 104 next += self._input.read(self._match_pattern) 105 else: 106 next += self._input.readUntil(self.__template_pattern) 107 108 result += next 109 next = self._read_template() 110 111 if self._until_after: 112 result += self._input.readUntilAfter(self._until_after) 113 114 return result 115 116 def __set_templated_pattern(self): 117 items = list() 118 119 if not self._disabled.php: 120 items.append(self.__patterns.php._starting_pattern.pattern) 121 122 if not self._disabled.handlebars: 123 items.append(self.__patterns.handlebars._starting_pattern.pattern) 124 125 if not self._disabled.erb: 126 items.append(self.__patterns.erb._starting_pattern.pattern) 127 128 if not self._disabled.django: 129 items.append(self.__patterns.django._starting_pattern.pattern) 130 items.append(self.__patterns.django_value._starting_pattern.pattern) 131 items.append(self.__patterns.django_comment._starting_pattern.pattern) 132 133 if self._until_pattern: 134 items.append(self._until_pattern.pattern) 135 136 self.__template_pattern = self._input.get_regexp( 137 r'(?:' + '|'.join(items) + ')') 138 139 def _read_template(self): 140 resulting_string = '' 141 c = self._input.peek() 142 if c == '<': 143 peek1 = self._input.peek(1) 144 if not self._disabled.php and \ 145 not self._excluded.php and \ 146 peek1 == '?': 147 resulting_string = resulting_string or \ 148 self.__patterns.php.read() 149 150 if not self._disabled.erb and \ 151 not self._excluded.erb and \ 152 peek1 == '%': 153 resulting_string = resulting_string or \ 154 self.__patterns.erb.read() 155 elif c == '{': 156 if not self._disabled.handlebars and \ 157 not self._excluded.handlebars: 158 resulting_string = resulting_string or \ 159 self.__patterns.handlebars_comment.read() 160 resulting_string = resulting_string or \ 161 self.__patterns.handlebars_unescaped.read() 162 resulting_string = resulting_string or \ 163 self.__patterns.handlebars.read() 164 if not self._disabled.django: 165 # django coflicts with handlebars a bit. 166 if not self._excluded.django and \ 167 not self._excluded.handlebars: 168 resulting_string = resulting_string or \ 169 self.__patterns.django_value.read() 170 if not self._excluded.django: 171 172 resulting_string = resulting_string or \ 173 self.__patterns.django_comment.read() 174 resulting_string = resulting_string or \ 175 self.__patterns.django.read() 176 177 return resulting_string 178