corrade-nucleus-nucleons – Blame information for rev 6

Subversion Repositories:
Rev:
Rev Author Line No. Line
2 office 1 from __future__ import print_function
2 import sys
3 import re
4 import copy
5 from cssbeautifier.__version__ import __version__
6  
7 #
8 # The MIT License (MIT)
9  
10 # Copyright (c) 2007-2017 Einar Lielmanis, Liam Newman, and contributors.
11  
12 # Permission is hereby granted, free of charge, to any person
13 # obtaining a copy of this software and associated documentation files
14 # (the "Software"), to deal in the Software without restriction,
15 # including without limitation the rights to use, copy, modify, merge,
16 # publish, distribute, sublicense, and/or sell copies of the Software,
17 # and to permit persons to whom the Software is furnished to do so,
18 # subject to the following conditions:
19  
20 # The above copyright notice and this permission notice shall be
21 # included in all copies or substantial portions of the Software.
22  
23 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 # SOFTWARE.
31  
32  
33 class BeautifierOptions:
34 def __init__(self):
35 self.indent_size = 4
36 self.indent_char = ' '
37 self.indent_with_tabs = False
38 self.preserve_newlines = False
39 self.selector_separator_newline = True
40 self.end_with_newline = False
41 self.newline_between_rules = True
42 self.space_around_combinator = False
43 self.eol = 'auto'
44  
45 self.css = None
46 self.js = None
47 self.html = None
48  
49 # deprecated
50 self.space_around_selector_separator = False
51  
52 def mergeOpts(self, targetType):
53 finalOpts = copy.copy(self)
54  
55 local = getattr(finalOpts, targetType)
56 if (local):
57 delattr(finalOpts, targetType)
58 for key in local:
59 setattr(finalOpts, key, local[key])
60  
61 return finalOpts
62  
63  
64 def __repr__(self):
65 return \
66 """indent_size = %d
67 indent_char = [%s]
68 indent_with_tabs = [%s]
69 preserve_newlines = [%s]
70 separate_selectors_newline = [%s]
71 end_with_newline = [%s]
72 newline_between_rules = [%s]
73 space_around_combinator = [%s]
74 """ % (self.indent_size, self.indent_char, self.indent_with_tabs, self.preserve_newlines,
75 self.selector_separator_newline, self.end_with_newline, self.newline_between_rules,
76 self.space_around_combinator)
77  
78  
79 def default_options():
80 return BeautifierOptions()
81  
82  
83 def beautify(string, opts=default_options()):
84 b = Beautifier(string, opts)
85 return b.beautify()
86  
87  
88 def beautify_file(file_name, opts=default_options()):
89 if file_name == '-': # stdin
90 stream = sys.stdin
91 else:
92 stream = open(file_name)
93 content = ''.join(stream.readlines())
94 b = Beautifier(content, opts)
95 return b.beautify()
96  
97  
98 def usage(stream=sys.stdout):
99  
100 print("cssbeautifier.py@" + __version__ + """
101  
102 CSS beautifier (http://jsbeautifier.org/)
103  
104 """, file=stream)
105 if stream == sys.stderr:
106 return 1
107 else:
108 return 0
109  
110 WHITE_RE = re.compile("^\s+$")
111 WORD_RE = re.compile("[\w$\-_]")
112  
113  
114 class Printer:
115  
116 def __init__(self, beautifier, indent_char, indent_size, default_indent=""):
117 self.beautifier = beautifier
118 self.newlines_from_last_ws_eat = 0
119 self.indentSize = indent_size
120 self.singleIndent = (indent_size) * indent_char
121 self.indentLevel = 0
122 self.nestedLevel = 0
123  
124 self.baseIndentString = default_indent
125 self.output = []
126  
127 def __lastCharWhitespace(self):
128 return len(self.output) > 0 and WHITE_RE.search(self.output[-1]) is not None
129  
130 def indent(self):
131 self.indentLevel += 1
132 self.baseIndentString += self.singleIndent
133  
134 def outdent(self):
135 if self.indentLevel:
136 self.indentLevel -= 1
137 self.baseIndentString = self.baseIndentString[:-(len(self.singleIndent))]
138  
139 def push(self, string):
140 self.output.append(string)
141  
142 def openBracket(self):
143 self.singleSpace()
144 self.output.append("{")
145 if self.beautifier.eatWhitespace(True) == 0:
146 self.newLine()
147  
148 def closeBracket(self,newLine):
149 if newLine:
150 self.newLine()
151 self.output.append("}")
152 self.beautifier.eatWhitespace(True)
153 if self.beautifier.newlines_from_last_ws_eat == 0:
154 self.newLine()
155  
156 def semicolon(self):
157 self.output.append(";")
158  
159 def comment(self, comment):
160 self.output.append(comment)
161  
162 def newLine(self, keepWhitespace=False):
163 if len(self.output) > 0 :
164 if not keepWhitespace and self.output[-1] != '\n':
165 self.trim()
166 elif self.output[-1] == self.baseIndentString:
167 self.output.pop()
168  
169 self.output.append("\n")
170  
171 if len(self.baseIndentString) > 0:
172 self.output.append(self.baseIndentString)
173  
174 def trim(self):
175 while self.__lastCharWhitespace():
176 self.output.pop()
177  
178 def singleSpace(self):
179 if len(self.output) > 0 and not self.__lastCharWhitespace():
180 self.output.append(" ")
181  
182 def preserveSingleSpace(self,isAfterSpace):
183 if isAfterSpace:
184 self.singleSpace()
185  
186 def result(self):
187 if self.baseIndentString:
188 return self.baseIndentString + "".join(self.output);
189 else:
190 return "".join(self.output)
191  
192  
193 class Beautifier:
194  
195 def __init__(self, source_text, opts=default_options()):
196 # This is not pretty, but given how we did the version import
197 # it is the only way to do this without having setup.py fail on a missing six dependency.
198 self.six = __import__("six")
199  
200 # in javascript, these two differ
201 # in python they are the same, different methods are called on them
202 self.lineBreak = re.compile(self.six.u("\r\n|[\n\r\u2028\u2029]"))
203 self.allLineBreaks = self.lineBreak
204  
205 if not source_text:
206 source_text = ''
207  
208 opts = opts.mergeOpts('css')
209  
210 # Continue to accept deprecated option
211 opts.space_around_combinator = opts.space_around_combinator or opts.space_around_selector_separator
212  
213 self.opts = opts
214 self.indentSize = opts.indent_size
215 self.indentChar = opts.indent_char
216 self.pos = -1
217 self.ch = None
218  
219 if self.opts.indent_with_tabs:
220 self.indentChar = "\t"
221 self.indentSize = 1
222  
223 if self.opts.eol == 'auto':
224 self.opts.eol = '\n'
225 if self.lineBreak.search(source_text or ''):
226 self.opts.eol = self.lineBreak.search(source_text).group()
227  
228 self.opts.eol = self.opts.eol.replace('\\r', '\r').replace('\\n', '\n')
229  
230 # HACK: newline parsing inconsistent. This brute force normalizes the input newlines.
231 self.source_text = re.sub(self.allLineBreaks, '\n', source_text)
232  
233 # https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
234 # also in CONDITIONAL_GROUP_RULE below
235 self.NESTED_AT_RULE = [ \
236 "@page", \
237 "@font-face", \
238 "@keyframes", \
239 "@media", \
240 "@supports", \
241 "@document"]
242 self.CONDITIONAL_GROUP_RULE = [ \
243 "@media", \
244 "@supports", \
245 "@document"]
246  
247 m = re.search("^[\t ]*", self.source_text)
248 baseIndentString = m.group(0)
249 self.printer = Printer(self, self.indentChar, self.indentSize, baseIndentString)
250  
251 def next(self):
252 self.pos = self.pos + 1
253 if self.pos < len(self.source_text):
254 self.ch = self.source_text[self.pos]
255 else:
256 self.ch = ''
257 return self.ch
258  
259 def peek(self,skipWhitespace=False):
260 start = self.pos
261 if skipWhitespace:
262 self.eatWhitespace()
263 result = ""
264 if self.pos + 1 < len(self.source_text):
265 result = self.source_text[self.pos + 1]
266 if skipWhitespace:
267 self.pos = start - 1
268 self.next()
269  
270 return result
271  
272 def eatString(self, endChars):
273 start = self.pos
274 while self.next():
275 if self.ch == "\\":
276 self.next()
277 elif self.ch in endChars:
278 break
279 elif self.ch == "\n":
280 break
281 return self.source_text[start:self.pos] + self.ch
282  
283 def peekString(self, endChar):
284 start = self.pos
285 st = self.eatString(endChar)
286 self.pos = start - 1
287 self.next()
288 return st
289  
290 def eatWhitespace(self, pn=False):
291 result = 0
292 while WHITE_RE.search(self.peek()) is not None:
293 self.next()
294 if self.ch == "\n" and pn and self.opts.preserve_newlines:
295 self.printer.newLine(True)
296 result += 1
297 self.newlines_from_last_ws_eat = result
298 return result
299  
300 def skipWhitespace(self):
301 result = ''
302 if self.ch and WHITE_RE.search(self.ch):
303 result = self.ch
304  
305 while WHITE_RE.search(self.next()) is not None:
306 result += self.ch
307 return result
308  
309 def eatComment(self):
310 start = self.pos
311 singleLine = self.peek() == "/"
312 self.next()
313 while self.next():
314 if not singleLine and self.ch == "*" and self.peek() == "/":
315 self.next()
316 break
317 elif singleLine and self.ch == "\n":
318 return self.source_text[start:self.pos]
319 return self.source_text[start:self.pos] + self.ch
320  
321 def lookBack(self, string):
322 past = self.source_text[self.pos - len(string):self.pos]
323 return past.lower() == string
324  
325 # Nested pseudo-class if we are insideRule
326 # and the next special character found opens
327 # a new block
328 def foundNestedPseudoClass(self):
329 i = self.pos + 1
330 openParen = 0
331 while i < len(self.source_text):
332 ch = self.source_text[i]
333 if ch == "{":
334 return True
335 elif ch == "(":
336 # pseudoclasses can contain ()
337 openParen += 1
338 elif ch == ")":
339 if openParen == 0:
340 return False
341 openParen -= 1
342 elif ch == ";" or ch == "}":
343 return False
344 i += 1;
345  
346 return False
347  
348 def beautify(self):
349 printer = self.printer
350 insideRule = False
351 insidePropertyValue = False
352 enteringConditionalGroup = False
353 top_ch = ''
354 last_top_ch = ''
355 parenLevel = 0
356  
357 while True:
358 whitespace = self.skipWhitespace()
359 isAfterSpace = whitespace != ''
360 isAfterNewline = '\n' in whitespace
361 last_top_ch = top_ch
362 top_ch = self.ch
363  
364 if not self.ch:
365 break
366 elif self.ch == '/' and self.peek() == '*':
367 header = printer.indentLevel == 0
368  
369 if not isAfterNewline or header:
370 printer.newLine()
371  
372  
373 comment = self.eatComment()
374 printer.comment(comment)
375 printer.newLine()
376 if header:
377 printer.newLine(True)
378 elif self.ch == '/' and self.peek() == '/':
379 if not isAfterNewline and last_top_ch != '{':
380 printer.trim()
381  
382 printer.singleSpace()
383 printer.comment(self.eatComment())
384 printer.newLine()
385 elif self.ch == '@':
386 printer.preserveSingleSpace(isAfterSpace)
387  
388 # deal with less propery mixins @{...}
389 if self.peek(True) == '{':
390 printer.push(self.eatString('}'));
391 else:
392 printer.push(self.ch)
393 # strip trailing space, if present, for hash property check
394 variableOrRule = self.peekString(": ,;{}()[]/='\"")
395  
396 if variableOrRule[-1] in ": ":
397 # wwe have a variable or pseudo-class, add it and insert one space before continuing
398 self.next()
399 variableOrRule = self.eatString(": ")
400 if variableOrRule[-1].isspace():
401 variableOrRule = variableOrRule[:-1]
402 printer.push(variableOrRule)
403 printer.singleSpace();
404  
405 if variableOrRule[-1].isspace():
406 variableOrRule = variableOrRule[:-1]
407  
408 # might be a nesting at-rule
409 if variableOrRule in self.NESTED_AT_RULE:
410 printer.nestedLevel += 1
411 if variableOrRule in self.CONDITIONAL_GROUP_RULE:
412 enteringConditionalGroup = True
413 elif self.ch == '#' and self.peek() == '{':
414 printer.preserveSingleSpace(isAfterSpace)
415 printer.push(self.eatString('}'));
416 elif self.ch == '{':
417 if self.peek(True) == '}':
418 self.eatWhitespace()
419 self.next()
420 printer.singleSpace()
421 printer.push("{")
422 printer.closeBracket(False)
423 if self.newlines_from_last_ws_eat < 2 and self.opts.newline_between_rules and printer.indentLevel == 0:
424 printer.newLine(True)
425 else:
426 printer.indent()
427 printer.openBracket()
428 # when entering conditional groups, only rulesets are allowed
429 if enteringConditionalGroup:
430 enteringConditionalGroup = False
431 insideRule = printer.indentLevel > printer.nestedLevel
432 else:
433 # otherwise, declarations are also allowed
434 insideRule = printer.indentLevel >= printer.nestedLevel
435 elif self.ch == '}':
436 printer.outdent()
437 printer.closeBracket(True)
438 insideRule = False
439 insidePropertyValue = False
440 if printer.nestedLevel:
441 printer.nestedLevel -= 1
442 if self.newlines_from_last_ws_eat < 2 and self.opts.newline_between_rules and printer.indentLevel == 0:
443 printer.newLine(True)
444 elif self.ch == ":":
445 self.eatWhitespace()
446 if (insideRule or enteringConditionalGroup) and \
447 not (self.lookBack('&') or self.foundNestedPseudoClass()) and \
448 not self.lookBack('('):
449 # 'property: value' delimiter
450 # which could be in a conditional group query
451 printer.push(":")
452 if not insidePropertyValue:
453 insidePropertyValue = True
454 printer.singleSpace()
455 else:
456 # sass/less parent reference don't use a space
457 # sass nested pseudo-class don't use a space
458  
459 # preserve space before pseudoclasses/pseudoelements, as it means "in any child"
460 if (self.lookBack(' ')) and (printer.output[-1] != ' '):
461 printer.push(" ")
462 if self.peek() == ":":
463 # pseudo-element
464 self.next()
465 printer.push("::")
466 else:
467 # pseudo-element
468 printer.push(":")
469 elif self.ch == '"' or self.ch == '\'':
470 printer.preserveSingleSpace(isAfterSpace)
471 printer.push(self.eatString(self.ch))
472 elif self.ch == ';':
473 insidePropertyValue = False
474 printer.semicolon()
475 if self.eatWhitespace(True) == 0:
476 printer.newLine()
477 elif self.ch == '(':
478 # may be a url
479 if self.lookBack("url"):
480 printer.push(self.ch)
481 self.eatWhitespace()
482 if self.next():
483 if self.ch is not ')' and self.ch is not '"' \
484 and self.ch is not '\'':
485 printer.push(self.eatString(')'))
486 else:
487 self.pos = self.pos - 1
488 else:
489 parenLevel += 1
490 printer.preserveSingleSpace(isAfterSpace)
491 printer.push(self.ch)
492 self.eatWhitespace()
493 elif self.ch == ')':
494 printer.push(self.ch)
495 parenLevel -= 1
496 elif self.ch == ',':
497 printer.push(self.ch)
498 if self.eatWhitespace(True) == 0 and not insidePropertyValue and self.opts.selector_separator_newline and parenLevel < 1:
499 printer.newLine()
500 else:
501 printer.singleSpace()
502 elif (self.ch == '>' or self.ch == '+' or self.ch == '~') and \
503 not insidePropertyValue and parenLevel < 1:
504 # handle combinator spacing
505 if self.opts.space_around_combinator:
506 printer.singleSpace()
507 printer.push(self.ch)
508 printer.singleSpace()
509 else:
510 printer.push(self.ch)
511 self.eatWhitespace()
512 # squash extra whitespace
513 if self.ch and WHITE_RE.search(self.ch):
514 self.ch = ''
515 elif self.ch == ']':
516 printer.push(self.ch)
517 elif self.ch == '[':
518 printer.preserveSingleSpace(isAfterSpace)
519 printer.push(self.ch)
520 elif self.ch == '=':
521 # no whitespace before or after
522 self.eatWhitespace()
523 printer.push('=')
524 if WHITE_RE.search(self.ch):
525 self.ch = ''
526 else:
527 printer.preserveSingleSpace(isAfterSpace)
528 printer.push(self.ch)
529  
530 sweet_code = re.sub('[\r\n\t ]+$', '', printer.result())
531  
532 # establish end_with_newline
533 if self.opts.end_with_newline:
534 sweet_code += '\n'
535  
536 if not self.opts.eol == '\n':
537 sweet_code = sweet_code.replace('\n', self.opts.eol)
538  
539 return sweet_code