/script-kiddie/002_script_kiddie/script-kiddie/bower_components/js-beautify/python/cssbeautifier/__init__.py |
@@ -0,0 +1,539 @@ |
from __future__ import print_function |
import sys |
import re |
import copy |
from cssbeautifier.__version__ import __version__ |
|
# |
# The MIT License (MIT) |
|
# Copyright (c) 2007-2017 Einar Lielmanis, Liam Newman, and contributors. |
|
# Permission is hereby granted, free of charge, to any person |
# obtaining a copy of this software and associated documentation files |
# (the "Software"), to deal in the Software without restriction, |
# including without limitation the rights to use, copy, modify, merge, |
# publish, distribute, sublicense, and/or sell copies of the Software, |
# and to permit persons to whom the Software is furnished to do so, |
# subject to the following conditions: |
|
# The above copyright notice and this permission notice shall be |
# included in all copies or substantial portions of the Software. |
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
# SOFTWARE. |
|
|
class BeautifierOptions: |
def __init__(self): |
self.indent_size = 4 |
self.indent_char = ' ' |
self.indent_with_tabs = False |
self.preserve_newlines = False |
self.selector_separator_newline = True |
self.end_with_newline = False |
self.newline_between_rules = True |
self.space_around_combinator = False |
self.eol = 'auto' |
|
self.css = None |
self.js = None |
self.html = None |
|
# deprecated |
self.space_around_selector_separator = False |
|
def mergeOpts(self, targetType): |
finalOpts = copy.copy(self) |
|
local = getattr(finalOpts, targetType) |
if (local): |
delattr(finalOpts, targetType) |
for key in local: |
setattr(finalOpts, key, local[key]) |
|
return finalOpts |
|
|
def __repr__(self): |
return \ |
"""indent_size = %d |
indent_char = [%s] |
indent_with_tabs = [%s] |
preserve_newlines = [%s] |
separate_selectors_newline = [%s] |
end_with_newline = [%s] |
newline_between_rules = [%s] |
space_around_combinator = [%s] |
""" % (self.indent_size, self.indent_char, self.indent_with_tabs, self.preserve_newlines, |
self.selector_separator_newline, self.end_with_newline, self.newline_between_rules, |
self.space_around_combinator) |
|
|
def default_options(): |
return BeautifierOptions() |
|
|
def beautify(string, opts=default_options()): |
b = Beautifier(string, opts) |
return b.beautify() |
|
|
def beautify_file(file_name, opts=default_options()): |
if file_name == '-': # stdin |
stream = sys.stdin |
else: |
stream = open(file_name) |
content = ''.join(stream.readlines()) |
b = Beautifier(content, opts) |
return b.beautify() |
|
|
def usage(stream=sys.stdout): |
|
print("cssbeautifier.py@" + __version__ + """ |
|
CSS beautifier (http://jsbeautifier.org/) |
|
""", file=stream) |
if stream == sys.stderr: |
return 1 |
else: |
return 0 |
|
WHITE_RE = re.compile("^\s+$") |
WORD_RE = re.compile("[\w$\-_]") |
|
|
class Printer: |
|
def __init__(self, beautifier, indent_char, indent_size, default_indent=""): |
self.beautifier = beautifier |
self.newlines_from_last_ws_eat = 0 |
self.indentSize = indent_size |
self.singleIndent = (indent_size) * indent_char |
self.indentLevel = 0 |
self.nestedLevel = 0 |
|
self.baseIndentString = default_indent |
self.output = [] |
|
def __lastCharWhitespace(self): |
return len(self.output) > 0 and WHITE_RE.search(self.output[-1]) is not None |
|
def indent(self): |
self.indentLevel += 1 |
self.baseIndentString += self.singleIndent |
|
def outdent(self): |
if self.indentLevel: |
self.indentLevel -= 1 |
self.baseIndentString = self.baseIndentString[:-(len(self.singleIndent))] |
|
def push(self, string): |
self.output.append(string) |
|
def openBracket(self): |
self.singleSpace() |
self.output.append("{") |
if self.beautifier.eatWhitespace(True) == 0: |
self.newLine() |
|
def closeBracket(self,newLine): |
if newLine: |
self.newLine() |
self.output.append("}") |
self.beautifier.eatWhitespace(True) |
if self.beautifier.newlines_from_last_ws_eat == 0: |
self.newLine() |
|
def semicolon(self): |
self.output.append(";") |
|
def comment(self, comment): |
self.output.append(comment) |
|
def newLine(self, keepWhitespace=False): |
if len(self.output) > 0 : |
if not keepWhitespace and self.output[-1] != '\n': |
self.trim() |
elif self.output[-1] == self.baseIndentString: |
self.output.pop() |
|
self.output.append("\n") |
|
if len(self.baseIndentString) > 0: |
self.output.append(self.baseIndentString) |
|
def trim(self): |
while self.__lastCharWhitespace(): |
self.output.pop() |
|
def singleSpace(self): |
if len(self.output) > 0 and not self.__lastCharWhitespace(): |
self.output.append(" ") |
|
def preserveSingleSpace(self,isAfterSpace): |
if isAfterSpace: |
self.singleSpace() |
|
def result(self): |
if self.baseIndentString: |
return self.baseIndentString + "".join(self.output); |
else: |
return "".join(self.output) |
|
|
class Beautifier: |
|
def __init__(self, source_text, opts=default_options()): |
# This is not pretty, but given how we did the version import |
# it is the only way to do this without having setup.py fail on a missing six dependency. |
self.six = __import__("six") |
|
# in javascript, these two differ |
# in python they are the same, different methods are called on them |
self.lineBreak = re.compile(self.six.u("\r\n|[\n\r\u2028\u2029]")) |
self.allLineBreaks = self.lineBreak |
|
if not source_text: |
source_text = '' |
|
opts = opts.mergeOpts('css') |
|
# Continue to accept deprecated option |
opts.space_around_combinator = opts.space_around_combinator or opts.space_around_selector_separator |
|
self.opts = opts |
self.indentSize = opts.indent_size |
self.indentChar = opts.indent_char |
self.pos = -1 |
self.ch = None |
|
if self.opts.indent_with_tabs: |
self.indentChar = "\t" |
self.indentSize = 1 |
|
if self.opts.eol == 'auto': |
self.opts.eol = '\n' |
if self.lineBreak.search(source_text or ''): |
self.opts.eol = self.lineBreak.search(source_text).group() |
|
self.opts.eol = self.opts.eol.replace('\\r', '\r').replace('\\n', '\n') |
|
# HACK: newline parsing inconsistent. This brute force normalizes the input newlines. |
self.source_text = re.sub(self.allLineBreaks, '\n', source_text) |
|
# https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule |
# also in CONDITIONAL_GROUP_RULE below |
self.NESTED_AT_RULE = [ \ |
"@page", \ |
"@font-face", \ |
"@keyframes", \ |
"@media", \ |
"@supports", \ |
"@document"] |
self.CONDITIONAL_GROUP_RULE = [ \ |
"@media", \ |
"@supports", \ |
"@document"] |
|
m = re.search("^[\t ]*", self.source_text) |
baseIndentString = m.group(0) |
self.printer = Printer(self, self.indentChar, self.indentSize, baseIndentString) |
|
def next(self): |
self.pos = self.pos + 1 |
if self.pos < len(self.source_text): |
self.ch = self.source_text[self.pos] |
else: |
self.ch = '' |
return self.ch |
|
def peek(self,skipWhitespace=False): |
start = self.pos |
if skipWhitespace: |
self.eatWhitespace() |
result = "" |
if self.pos + 1 < len(self.source_text): |
result = self.source_text[self.pos + 1] |
if skipWhitespace: |
self.pos = start - 1 |
self.next() |
|
return result |
|
def eatString(self, endChars): |
start = self.pos |
while self.next(): |
if self.ch == "\\": |
self.next() |
elif self.ch in endChars: |
break |
elif self.ch == "\n": |
break |
return self.source_text[start:self.pos] + self.ch |
|
def peekString(self, endChar): |
start = self.pos |
st = self.eatString(endChar) |
self.pos = start - 1 |
self.next() |
return st |
|
def eatWhitespace(self, pn=False): |
result = 0 |
while WHITE_RE.search(self.peek()) is not None: |
self.next() |
if self.ch == "\n" and pn and self.opts.preserve_newlines: |
self.printer.newLine(True) |
result += 1 |
self.newlines_from_last_ws_eat = result |
return result |
|
def skipWhitespace(self): |
result = '' |
if self.ch and WHITE_RE.search(self.ch): |
result = self.ch |
|
while WHITE_RE.search(self.next()) is not None: |
result += self.ch |
return result |
|
def eatComment(self): |
start = self.pos |
singleLine = self.peek() == "/" |
self.next() |
while self.next(): |
if not singleLine and self.ch == "*" and self.peek() == "/": |
self.next() |
break |
elif singleLine and self.ch == "\n": |
return self.source_text[start:self.pos] |
return self.source_text[start:self.pos] + self.ch |
|
def lookBack(self, string): |
past = self.source_text[self.pos - len(string):self.pos] |
return past.lower() == string |
|
# Nested pseudo-class if we are insideRule |
# and the next special character found opens |
# a new block |
def foundNestedPseudoClass(self): |
i = self.pos + 1 |
openParen = 0 |
while i < len(self.source_text): |
ch = self.source_text[i] |
if ch == "{": |
return True |
elif ch == "(": |
# pseudoclasses can contain () |
openParen += 1 |
elif ch == ")": |
if openParen == 0: |
return False |
openParen -= 1 |
elif ch == ";" or ch == "}": |
return False |
i += 1; |
|
return False |
|
def beautify(self): |
printer = self.printer |
insideRule = False |
insidePropertyValue = False |
enteringConditionalGroup = False |
top_ch = '' |
last_top_ch = '' |
parenLevel = 0 |
|
while True: |
whitespace = self.skipWhitespace() |
isAfterSpace = whitespace != '' |
isAfterNewline = '\n' in whitespace |
last_top_ch = top_ch |
top_ch = self.ch |
|
if not self.ch: |
break |
elif self.ch == '/' and self.peek() == '*': |
header = printer.indentLevel == 0 |
|
if not isAfterNewline or header: |
printer.newLine() |
|
|
comment = self.eatComment() |
printer.comment(comment) |
printer.newLine() |
if header: |
printer.newLine(True) |
elif self.ch == '/' and self.peek() == '/': |
if not isAfterNewline and last_top_ch != '{': |
printer.trim() |
|
printer.singleSpace() |
printer.comment(self.eatComment()) |
printer.newLine() |
elif self.ch == '@': |
printer.preserveSingleSpace(isAfterSpace) |
|
# deal with less propery mixins @{...} |
if self.peek(True) == '{': |
printer.push(self.eatString('}')); |
else: |
printer.push(self.ch) |
# strip trailing space, if present, for hash property check |
variableOrRule = self.peekString(": ,;{}()[]/='\"") |
|
if variableOrRule[-1] in ": ": |
# wwe have a variable or pseudo-class, add it and insert one space before continuing |
self.next() |
variableOrRule = self.eatString(": ") |
if variableOrRule[-1].isspace(): |
variableOrRule = variableOrRule[:-1] |
printer.push(variableOrRule) |
printer.singleSpace(); |
|
if variableOrRule[-1].isspace(): |
variableOrRule = variableOrRule[:-1] |
|
# might be a nesting at-rule |
if variableOrRule in self.NESTED_AT_RULE: |
printer.nestedLevel += 1 |
if variableOrRule in self.CONDITIONAL_GROUP_RULE: |
enteringConditionalGroup = True |
elif self.ch == '#' and self.peek() == '{': |
printer.preserveSingleSpace(isAfterSpace) |
printer.push(self.eatString('}')); |
elif self.ch == '{': |
if self.peek(True) == '}': |
self.eatWhitespace() |
self.next() |
printer.singleSpace() |
printer.push("{") |
printer.closeBracket(False) |
if self.newlines_from_last_ws_eat < 2 and self.opts.newline_between_rules and printer.indentLevel == 0: |
printer.newLine(True) |
else: |
printer.indent() |
printer.openBracket() |
# when entering conditional groups, only rulesets are allowed |
if enteringConditionalGroup: |
enteringConditionalGroup = False |
insideRule = printer.indentLevel > printer.nestedLevel |
else: |
# otherwise, declarations are also allowed |
insideRule = printer.indentLevel >= printer.nestedLevel |
elif self.ch == '}': |
printer.outdent() |
printer.closeBracket(True) |
insideRule = False |
insidePropertyValue = False |
if printer.nestedLevel: |
printer.nestedLevel -= 1 |
if self.newlines_from_last_ws_eat < 2 and self.opts.newline_between_rules and printer.indentLevel == 0: |
printer.newLine(True) |
elif self.ch == ":": |
self.eatWhitespace() |
if (insideRule or enteringConditionalGroup) and \ |
not (self.lookBack('&') or self.foundNestedPseudoClass()) and \ |
not self.lookBack('('): |
# 'property: value' delimiter |
# which could be in a conditional group query |
printer.push(":") |
if not insidePropertyValue: |
insidePropertyValue = True |
printer.singleSpace() |
else: |
# sass/less parent reference don't use a space |
# sass nested pseudo-class don't use a space |
|
# preserve space before pseudoclasses/pseudoelements, as it means "in any child" |
if (self.lookBack(' ')) and (printer.output[-1] != ' '): |
printer.push(" ") |
if self.peek() == ":": |
# pseudo-element |
self.next() |
printer.push("::") |
else: |
# pseudo-element |
printer.push(":") |
elif self.ch == '"' or self.ch == '\'': |
printer.preserveSingleSpace(isAfterSpace) |
printer.push(self.eatString(self.ch)) |
elif self.ch == ';': |
insidePropertyValue = False |
printer.semicolon() |
if self.eatWhitespace(True) == 0: |
printer.newLine() |
elif self.ch == '(': |
# may be a url |
if self.lookBack("url"): |
printer.push(self.ch) |
self.eatWhitespace() |
if self.next(): |
if self.ch is not ')' and self.ch is not '"' \ |
and self.ch is not '\'': |
printer.push(self.eatString(')')) |
else: |
self.pos = self.pos - 1 |
else: |
parenLevel += 1 |
printer.preserveSingleSpace(isAfterSpace) |
printer.push(self.ch) |
self.eatWhitespace() |
elif self.ch == ')': |
printer.push(self.ch) |
parenLevel -= 1 |
elif self.ch == ',': |
printer.push(self.ch) |
if self.eatWhitespace(True) == 0 and not insidePropertyValue and self.opts.selector_separator_newline and parenLevel < 1: |
printer.newLine() |
else: |
printer.singleSpace() |
elif (self.ch == '>' or self.ch == '+' or self.ch == '~') and \ |
not insidePropertyValue and parenLevel < 1: |
# handle combinator spacing |
if self.opts.space_around_combinator: |
printer.singleSpace() |
printer.push(self.ch) |
printer.singleSpace() |
else: |
printer.push(self.ch) |
self.eatWhitespace() |
# squash extra whitespace |
if self.ch and WHITE_RE.search(self.ch): |
self.ch = '' |
elif self.ch == ']': |
printer.push(self.ch) |
elif self.ch == '[': |
printer.preserveSingleSpace(isAfterSpace) |
printer.push(self.ch) |
elif self.ch == '=': |
# no whitespace before or after |
self.eatWhitespace() |
printer.push('=') |
if WHITE_RE.search(self.ch): |
self.ch = '' |
else: |
printer.preserveSingleSpace(isAfterSpace) |
printer.push(self.ch) |
|
sweet_code = re.sub('[\r\n\t ]+$', '', printer.result()) |
|
# establish end_with_newline |
if self.opts.end_with_newline: |
sweet_code += '\n' |
|
if not self.opts.eol == '\n': |
sweet_code = sweet_code.replace('\n', self.opts.eol) |
|
return sweet_code |
/script-kiddie/002_script_kiddie/script-kiddie/bower_components/js-beautify/python/cssbeautifier/tests/generated/tests.py |
@@ -0,0 +1,1394 @@ |
#!/usr/bin/env python |
# -*- coding: utf-8 -*- |
|
''' |
AUTO-GENERATED. DO NOT MODIFY. |
Script: test/generate-tests.js |
Template: test/data/css/python.mustache |
Data: test/data/css/tests.js |
|
The MIT License (MIT) |
|
Copyright (c) 2007-2017 Einar Lielmanis, Liam Newman, and contributors. |
|
Permission is hereby granted, free of charge, to any person |
obtaining a copy of this software and associated documentation files |
(the "Software"), to deal in the Software without restriction, |
including without limitation the rights to use, copy, modify, merge, |
publish, distribute, sublicense, and/or sell copies of the Software, |
and to permit persons to whom the Software is furnished to do so, |
subject to the following conditions: |
|
The above copyright notice and this permission notice shall be |
included in all copies or substantial portions of the Software. |
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
SOFTWARE. |
''' |
|
import unittest |
import cssbeautifier |
import copy |
|
class CSSBeautifierTest(unittest.TestCase): |
|
options = None |
|
@classmethod |
def setUpClass(cls): |
false = False |
true = True |
|
default_options = cssbeautifier.default_options() |
default_options.indent_size = 1 |
default_options.indent_char = '\t' |
default_options.selector_separator_newline = true |
default_options.end_with_newline = false |
default_options.newline_between_rules = false |
|
default_options.indent_size = 1 |
default_options.indent_char = '\t' |
default_options.selector_separator_newline = true |
default_options.end_with_newline = false |
default_options.newline_between_rules = false |
default_options.space_around_combinator = false |
default_options.preserve_newlines = false |
default_options.space_around_selector_separator = false |
|
cls.default_options = default_options |
|
def reset_options(self): |
self.options = copy.copy(self.default_options) |
|
def testGenerated(self): |
self.reset_options() |
test_fragment = self.decodesto |
t = self.decodesto |
|
false = False |
true = True |
|
|
#============================================================ |
# End With Newline - (eof = "\n") |
self.reset_options(); |
self.options.end_with_newline = true |
test_fragment('', '\n') |
test_fragment(' .tabs{}', ' .tabs {}\n') |
test_fragment( |
' \n' + |
'\n' + |
'.tabs{}\n' + |
'\n' + |
'\n' + |
'\n', |
# -- output -- |
' .tabs {}\n') |
test_fragment('\n') |
|
# End With Newline - (eof = "") |
self.reset_options(); |
self.options.end_with_newline = false |
test_fragment('') |
test_fragment(' .tabs{}', ' .tabs {}') |
test_fragment( |
' \n' + |
'\n' + |
'.tabs{}\n' + |
'\n' + |
'\n' + |
'\n', |
# -- output -- |
' .tabs {}') |
test_fragment('\n', '') |
|
|
#============================================================ |
# Empty braces |
self.reset_options(); |
t('.tabs{}', '.tabs {}') |
t('.tabs { }', '.tabs {}') |
t('.tabs { }', '.tabs {}') |
t( |
'.tabs \n' + |
'{\n' + |
' \n' + |
' }', |
# -- output -- |
'.tabs {}') |
|
|
#============================================================ |
# |
self.reset_options(); |
t( |
'#cboxOverlay {\n' + |
'\tbackground: url(images/overlay.png) repeat 0 0;\n' + |
'\topacity: 0.9;\n' + |
'\tfilter: alpha(opacity = 90);\n' + |
'}', |
# -- output -- |
'#cboxOverlay {\n' + |
'\tbackground: url(images/overlay.png) repeat 0 0;\n' + |
'\topacity: 0.9;\n' + |
'\tfilter: alpha(opacity=90);\n' + |
'}') |
|
|
#============================================================ |
# Support simple language specific option inheritance/overriding - (c = " ") |
self.reset_options(); |
self.options.indent_char = ' ' |
self.options.indent_size = 4 |
self.options.js = { 'indent_size': 3 } |
self.options.css = { 'indent_size': 5 } |
t( |
'.selector {\n' + |
' font-size: 12px;\n' + |
'}') |
|
# Support simple language specific option inheritance/overriding - (c = " ") |
self.reset_options(); |
self.options.indent_char = ' ' |
self.options.indent_size = 4 |
self.options.html = { 'js': { 'indent_size': 3 }, 'css': { 'indent_size': 5 } } |
t( |
'.selector {\n' + |
' font-size: 12px;\n' + |
'}') |
|
# Support simple language specific option inheritance/overriding - (c = " ") |
self.reset_options(); |
self.options.indent_char = ' ' |
self.options.indent_size = 9 |
self.options.html = { 'js': { 'indent_size': 3 }, 'css': { 'indent_size': 8 }, 'indent_size': 2} |
self.options.js = { 'indent_size': 5 } |
self.options.css = { 'indent_size': 3 } |
t( |
'.selector {\n' + |
' font-size: 12px;\n' + |
'}') |
|
|
#============================================================ |
# Space Around Combinator - (space = " ") |
self.reset_options(); |
self.options.space_around_combinator = true |
t('a>b{}', 'a > b {}') |
t('a~b{}', 'a ~ b {}') |
t('a+b{}', 'a + b {}') |
t('a+b>c{}', 'a + b > c {}') |
t('a > b{}', 'a > b {}') |
t('a ~ b{}', 'a ~ b {}') |
t('a + b{}', 'a + b {}') |
t('a + b > c{}', 'a + b > c {}') |
t( |
'a > b{width: calc(100% + 45px);}', |
# -- output -- |
'a > b {\n' + |
'\twidth: calc(100% + 45px);\n' + |
'}') |
t( |
'a ~ b{width: calc(100% + 45px);}', |
# -- output -- |
'a ~ b {\n' + |
'\twidth: calc(100% + 45px);\n' + |
'}') |
t( |
'a + b{width: calc(100% + 45px);}', |
# -- output -- |
'a + b {\n' + |
'\twidth: calc(100% + 45px);\n' + |
'}') |
t( |
'a + b > c{width: calc(100% + 45px);}', |
# -- output -- |
'a + b > c {\n' + |
'\twidth: calc(100% + 45px);\n' + |
'}') |
|
# Space Around Combinator - (space = "") |
self.reset_options(); |
self.options.space_around_combinator = false |
t('a>b{}', 'a>b {}') |
t('a~b{}', 'a~b {}') |
t('a+b{}', 'a+b {}') |
t('a+b>c{}', 'a+b>c {}') |
t('a > b{}', 'a>b {}') |
t('a ~ b{}', 'a~b {}') |
t('a + b{}', 'a+b {}') |
t('a + b > c{}', 'a+b>c {}') |
t( |
'a > b{width: calc(100% + 45px);}', |
# -- output -- |
'a>b {\n' + |
'\twidth: calc(100% + 45px);\n' + |
'}') |
t( |
'a ~ b{width: calc(100% + 45px);}', |
# -- output -- |
'a~b {\n' + |
'\twidth: calc(100% + 45px);\n' + |
'}') |
t( |
'a + b{width: calc(100% + 45px);}', |
# -- output -- |
'a+b {\n' + |
'\twidth: calc(100% + 45px);\n' + |
'}') |
t( |
'a + b > c{width: calc(100% + 45px);}', |
# -- output -- |
'a+b>c {\n' + |
'\twidth: calc(100% + 45px);\n' + |
'}') |
|
# Space Around Combinator - (space = " ") |
self.reset_options(); |
self.options.space_around_selector_separator = true |
t('a>b{}', 'a > b {}') |
t('a~b{}', 'a ~ b {}') |
t('a+b{}', 'a + b {}') |
t('a+b>c{}', 'a + b > c {}') |
t('a > b{}', 'a > b {}') |
t('a ~ b{}', 'a ~ b {}') |
t('a + b{}', 'a + b {}') |
t('a + b > c{}', 'a + b > c {}') |
t( |
'a > b{width: calc(100% + 45px);}', |
# -- output -- |
'a > b {\n' + |
'\twidth: calc(100% + 45px);\n' + |
'}') |
t( |
'a ~ b{width: calc(100% + 45px);}', |
# -- output -- |
'a ~ b {\n' + |
'\twidth: calc(100% + 45px);\n' + |
'}') |
t( |
'a + b{width: calc(100% + 45px);}', |
# -- output -- |
'a + b {\n' + |
'\twidth: calc(100% + 45px);\n' + |
'}') |
t( |
'a + b > c{width: calc(100% + 45px);}', |
# -- output -- |
'a + b > c {\n' + |
'\twidth: calc(100% + 45px);\n' + |
'}') |
|
|
#============================================================ |
# Selector Separator - (separator = " ", separator1 = " ") |
self.reset_options(); |
self.options.selector_separator_newline = false |
self.options.selector_separator = " " |
t( |
'#bla, #foo{color:green}', |
# -- output -- |
'#bla, #foo {\n' + |
'\tcolor: green\n' + |
'}') |
t( |
'@media print {.tab{}}', |
# -- output -- |
'@media print {\n' + |
'\t.tab {}\n' + |
'}') |
t( |
'@media print {.tab,.bat{}}', |
# -- output -- |
'@media print {\n' + |
'\t.tab, .bat {}\n' + |
'}') |
t( |
'#bla, #foo{color:black}', |
# -- output -- |
'#bla, #foo {\n' + |
'\tcolor: black\n' + |
'}') |
t( |
'a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}', |
# -- output -- |
'a:first-child, a:first-child {\n' + |
'\tcolor: red;\n' + |
'\tdiv:first-child, div:hover {\n' + |
'\t\tcolor: black;\n' + |
'\t}\n' + |
'}') |
|
# Selector Separator - (separator = " ", separator1 = " ") |
self.reset_options(); |
self.options.selector_separator_newline = false |
self.options.selector_separator = " " |
t( |
'#bla, #foo{color:green}', |
# -- output -- |
'#bla, #foo {\n' + |
'\tcolor: green\n' + |
'}') |
t( |
'@media print {.tab{}}', |
# -- output -- |
'@media print {\n' + |
'\t.tab {}\n' + |
'}') |
t( |
'@media print {.tab,.bat{}}', |
# -- output -- |
'@media print {\n' + |
'\t.tab, .bat {}\n' + |
'}') |
t( |
'#bla, #foo{color:black}', |
# -- output -- |
'#bla, #foo {\n' + |
'\tcolor: black\n' + |
'}') |
t( |
'a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}', |
# -- output -- |
'a:first-child, a:first-child {\n' + |
'\tcolor: red;\n' + |
'\tdiv:first-child, div:hover {\n' + |
'\t\tcolor: black;\n' + |
'\t}\n' + |
'}') |
|
# Selector Separator - (separator = "\n", separator1 = "\n\t") |
self.reset_options(); |
self.options.selector_separator_newline = true |
self.options.selector_separator = " " |
t( |
'#bla, #foo{color:green}', |
# -- output -- |
'#bla,\n#foo {\n' + |
'\tcolor: green\n' + |
'}') |
t( |
'@media print {.tab{}}', |
# -- output -- |
'@media print {\n' + |
'\t.tab {}\n' + |
'}') |
t( |
'@media print {.tab,.bat{}}', |
# -- output -- |
'@media print {\n' + |
'\t.tab,\n\t.bat {}\n' + |
'}') |
t( |
'#bla, #foo{color:black}', |
# -- output -- |
'#bla,\n#foo {\n' + |
'\tcolor: black\n' + |
'}') |
t( |
'a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}', |
# -- output -- |
'a:first-child,\na:first-child {\n' + |
'\tcolor: red;\n' + |
'\tdiv:first-child,\n\tdiv:hover {\n' + |
'\t\tcolor: black;\n' + |
'\t}\n' + |
'}') |
|
# Selector Separator - (separator = "\n", separator1 = "\n\t") |
self.reset_options(); |
self.options.selector_separator_newline = true |
self.options.selector_separator = " " |
t( |
'#bla, #foo{color:green}', |
# -- output -- |
'#bla,\n#foo {\n' + |
'\tcolor: green\n' + |
'}') |
t( |
'@media print {.tab{}}', |
# -- output -- |
'@media print {\n' + |
'\t.tab {}\n' + |
'}') |
t( |
'@media print {.tab,.bat{}}', |
# -- output -- |
'@media print {\n' + |
'\t.tab,\n\t.bat {}\n' + |
'}') |
t( |
'#bla, #foo{color:black}', |
# -- output -- |
'#bla,\n#foo {\n' + |
'\tcolor: black\n' + |
'}') |
t( |
'a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}', |
# -- output -- |
'a:first-child,\na:first-child {\n' + |
'\tcolor: red;\n' + |
'\tdiv:first-child,\n\tdiv:hover {\n' + |
'\t\tcolor: black;\n' + |
'\t}\n' + |
'}') |
|
|
#============================================================ |
# Preserve Newlines - (separator_input = "\n\n", separator_output = "\n\n") |
self.reset_options(); |
self.options.preserve_newlines = true |
t('.div {}\n\n.span {}') |
t( |
'#bla, #foo{\n' + |
'\tcolor:black;\n\n\tfont-size: 12px;\n' + |
'}', |
# -- output -- |
'#bla,\n' + |
'#foo {\n' + |
'\tcolor: black;\n\n\tfont-size: 12px;\n' + |
'}') |
|
# Preserve Newlines - (separator_input = "\n\n", separator_output = "\n") |
self.reset_options(); |
self.options.preserve_newlines = false |
t('.div {}\n\n.span {}', '.div {}\n.span {}') |
t( |
'#bla, #foo{\n' + |
'\tcolor:black;\n\n\tfont-size: 12px;\n' + |
'}', |
# -- output -- |
'#bla,\n' + |
'#foo {\n' + |
'\tcolor: black;\n\tfont-size: 12px;\n' + |
'}') |
|
|
#============================================================ |
# Preserve Newlines and newline_between_rules |
self.reset_options(); |
self.options.preserve_newlines = true |
self.options.newline_between_rules = true |
t( |
'.div {}.span {}', |
# -- output -- |
'.div {}\n' + |
'\n' + |
'.span {}') |
t( |
'#bla, #foo{\n' + |
'\tcolor:black;\n' + |
'\tfont-size: 12px;\n' + |
'}', |
# -- output -- |
'#bla,\n' + |
'#foo {\n' + |
'\tcolor: black;\n' + |
'\tfont-size: 12px;\n' + |
'}') |
t( |
'#bla, #foo{\n' + |
'\tcolor:black;\n' + |
'\n' + |
'\n' + |
'\tfont-size: 12px;\n' + |
'}', |
# -- output -- |
'#bla,\n' + |
'#foo {\n' + |
'\tcolor: black;\n' + |
'\n' + |
'\n' + |
'\tfont-size: 12px;\n' + |
'}') |
t( |
'#bla,\n' + |
'\n' + |
'#foo {\n' + |
'\tcolor: black;\n' + |
'\tfont-size: 12px;\n' + |
'}') |
t( |
'a {\n' + |
'\tb: c;\n' + |
'\n' + |
'\n' + |
'\td: {\n' + |
'\t\te: f;\n' + |
'\t}\n' + |
'}') |
t( |
'.div {}\n' + |
'\n' + |
'.span {}') |
t( |
'.div {\n' + |
'\ta: 1;\n' + |
'\n' + |
'\n' + |
'\tb: 2;\n' + |
'}\n' + |
'\n' + |
'\n' + |
'\n' + |
'.span {\n' + |
'\ta: 1;\n' + |
'}') |
t( |
'.div {\n' + |
'\n' + |
'\n' + |
'\ta: 1;\n' + |
'\n' + |
'\n' + |
'\tb: 2;\n' + |
'}\n' + |
'\n' + |
'\n' + |
'\n' + |
'.span {\n' + |
'\ta: 1;\n' + |
'}') |
t( |
'@media screen {\n' + |
'\t.div {\n' + |
'\t\ta: 1;\n' + |
'\n' + |
'\n' + |
'\t\tb: 2;\n' + |
'\t}\n' + |
'\n' + |
'\n' + |
'\n' + |
'\t.span {\n' + |
'\t\ta: 1;\n' + |
'\t}\n' + |
'}\n' + |
'\n' + |
'.div {}\n' + |
'\n' + |
'.span {}') |
|
|
#============================================================ |
# Preserve Newlines and add tabs |
self.reset_options(); |
self.options.preserve_newlines = true |
t( |
'.tool-tip {\n' + |
'\tposition: relative;\n' + |
'\n' + |
'\t\t\n' + |
'\t.tool-tip-content {\n' + |
'\t\t&>* {\n' + |
'\t\t\tmargin-top: 0;\n' + |
'\t\t}\n' + |
'\t\t\n' + |
'\n' + |
'\t\t.mixin-box-shadow(.2rem .2rem .5rem rgba(0, 0, 0, .15));\n' + |
'\t\tpadding: 1rem;\n' + |
'\t\tposition: absolute;\n' + |
'\t\tz-index: 10;\n' + |
'\t}\n' + |
'}', |
# -- output -- |
'.tool-tip {\n' + |
'\tposition: relative;\n' + |
'\n' + |
'\n' + |
'\t.tool-tip-content {\n' + |
'\t\t&>* {\n' + |
'\t\t\tmargin-top: 0;\n' + |
'\t\t}\n' + |
'\n\n\t\t.mixin-box-shadow(.2rem .2rem .5rem rgba(0, 0, 0, .15));\n' + |
'\t\tpadding: 1rem;\n' + |
'\t\tposition: absolute;\n' + |
'\t\tz-index: 10;\n' + |
'\t}\n' + |
'}') |
|
|
#============================================================ |
# Newline Between Rules - (separator = "\n") |
self.reset_options(); |
self.options.newline_between_rules = true |
t( |
'.div {}\n' + |
'.span {}', |
# -- output -- |
'.div {}\n' + |
'\n.span {}') |
t( |
'.div{}\n' + |
' \n' + |
'.span{}', |
# -- output -- |
'.div {}\n' + |
'\n.span {}') |
t( |
'.div {} \n' + |
' \n' + |
'.span { } \n', |
# -- output -- |
'.div {}\n' + |
'\n.span {}') |
t( |
'.div {\n' + |
' \n' + |
'} \n' + |
' .span {\n' + |
' } ', |
# -- output -- |
'.div {}\n' + |
'\n.span {}') |
t( |
'.selector1 {\n' + |
'\tmargin: 0; /* This is a comment including an url http://domain.com/path/to/file.ext */\n' + |
'}\n' + |
'.div{height:15px;}', |
# -- output -- |
'.selector1 {\n' + |
'\tmargin: 0;\n' + |
'\t/* This is a comment including an url http://domain.com/path/to/file.ext */\n' + |
'}\n' + |
'\n.div {\n' + |
'\theight: 15px;\n' + |
'}') |
t( |
'.tabs{width:10px;//end of line comment\n' + |
'height:10px;//another\n' + |
'}\n' + |
'.div{height:15px;}', |
# -- output -- |
'.tabs {\n' + |
'\twidth: 10px; //end of line comment\n' + |
'\theight: 10px; //another\n' + |
'}\n' + |
'\n.div {\n' + |
'\theight: 15px;\n' + |
'}') |
t( |
'#foo {\n' + |
'\tbackground-image: url(foo@2x.png);\n' + |
'\t@font-face {\n' + |
'\t\tfont-family: "Bitstream Vera Serif Bold";\n' + |
'\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n' + |
'\t}\n' + |
'}\n' + |
'.div{height:15px;}', |
# -- output -- |
'#foo {\n' + |
'\tbackground-image: url(foo@2x.png);\n' + |
'\t@font-face {\n' + |
'\t\tfont-family: "Bitstream Vera Serif Bold";\n' + |
'\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n' + |
'\t}\n' + |
'}\n' + |
'\n.div {\n' + |
'\theight: 15px;\n' + |
'}') |
t( |
'@media screen {\n' + |
'\t#foo:hover {\n' + |
'\t\tbackground-image: url(foo@2x.png);\n' + |
'\t}\n' + |
'\t@font-face {\n' + |
'\t\tfont-family: "Bitstream Vera Serif Bold";\n' + |
'\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n' + |
'\t}\n' + |
'}\n' + |
'.div{height:15px;}', |
# -- output -- |
'@media screen {\n' + |
'\t#foo:hover {\n' + |
'\t\tbackground-image: url(foo@2x.png);\n' + |
'\t}\n' + |
'\t@font-face {\n' + |
'\t\tfont-family: "Bitstream Vera Serif Bold";\n' + |
'\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n' + |
'\t}\n' + |
'}\n' + |
'\n.div {\n' + |
'\theight: 15px;\n' + |
'}') |
t( |
'@font-face {\n' + |
'\tfont-family: "Bitstream Vera Serif Bold";\n' + |
'\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n' + |
'}\n' + |
'@media screen {\n' + |
'\t#foo:hover {\n' + |
'\t\tbackground-image: url(foo.png);\n' + |
'\t}\n' + |
'\t@media screen and (min-device-pixel-ratio: 2) {\n' + |
'\t\t@font-face {\n' + |
'\t\t\tfont-family: "Helvetica Neue"\n' + |
'\t\t}\n' + |
'\t\t#foo:hover {\n' + |
'\t\t\tbackground-image: url(foo@2x.png);\n' + |
'\t\t}\n' + |
'\t}\n' + |
'}', |
# -- output -- |
'@font-face {\n' + |
'\tfont-family: "Bitstream Vera Serif Bold";\n' + |
'\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n' + |
'}\n' + |
'\n@media screen {\n' + |
'\t#foo:hover {\n' + |
'\t\tbackground-image: url(foo.png);\n' + |
'\t}\n' + |
'\t@media screen and (min-device-pixel-ratio: 2) {\n' + |
'\t\t@font-face {\n' + |
'\t\t\tfont-family: "Helvetica Neue"\n' + |
'\t\t}\n' + |
'\t\t#foo:hover {\n' + |
'\t\t\tbackground-image: url(foo@2x.png);\n' + |
'\t\t}\n' + |
'\t}\n' + |
'}') |
t( |
'a:first-child{color:red;div:first-child{color:black;}}\n' + |
'.div{height:15px;}', |
# -- output -- |
'a:first-child {\n' + |
'\tcolor: red;\n' + |
'\tdiv:first-child {\n' + |
'\t\tcolor: black;\n' + |
'\t}\n' + |
'}\n' + |
'\n.div {\n' + |
'\theight: 15px;\n' + |
'}') |
t( |
'a:first-child{color:red;div:not(.peq){color:black;}}\n' + |
'.div{height:15px;}', |
# -- output -- |
'a:first-child {\n' + |
'\tcolor: red;\n' + |
'\tdiv:not(.peq) {\n' + |
'\t\tcolor: black;\n' + |
'\t}\n' + |
'}\n' + |
'\n.div {\n' + |
'\theight: 15px;\n' + |
'}') |
|
# Newline Between Rules - (separator = "") |
self.reset_options(); |
self.options.newline_between_rules = false |
t( |
'.div {}\n' + |
'.span {}') |
t( |
'.div{}\n' + |
' \n' + |
'.span{}', |
# -- output -- |
'.div {}\n' + |
'.span {}') |
t( |
'.div {} \n' + |
' \n' + |
'.span { } \n', |
# -- output -- |
'.div {}\n' + |
'.span {}') |
t( |
'.div {\n' + |
' \n' + |
'} \n' + |
' .span {\n' + |
' } ', |
# -- output -- |
'.div {}\n' + |
'.span {}') |
t( |
'.selector1 {\n' + |
'\tmargin: 0; /* This is a comment including an url http://domain.com/path/to/file.ext */\n' + |
'}\n' + |
'.div{height:15px;}', |
# -- output -- |
'.selector1 {\n' + |
'\tmargin: 0;\n' + |
'\t/* This is a comment including an url http://domain.com/path/to/file.ext */\n' + |
'}\n' + |
'.div {\n' + |
'\theight: 15px;\n' + |
'}') |
t( |
'.tabs{width:10px;//end of line comment\n' + |
'height:10px;//another\n' + |
'}\n' + |
'.div{height:15px;}', |
# -- output -- |
'.tabs {\n' + |
'\twidth: 10px; //end of line comment\n' + |
'\theight: 10px; //another\n' + |
'}\n' + |
'.div {\n' + |
'\theight: 15px;\n' + |
'}') |
t( |
'#foo {\n' + |
'\tbackground-image: url(foo@2x.png);\n' + |
'\t@font-face {\n' + |
'\t\tfont-family: "Bitstream Vera Serif Bold";\n' + |
'\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n' + |
'\t}\n' + |
'}\n' + |
'.div{height:15px;}', |
# -- output -- |
'#foo {\n' + |
'\tbackground-image: url(foo@2x.png);\n' + |
'\t@font-face {\n' + |
'\t\tfont-family: "Bitstream Vera Serif Bold";\n' + |
'\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n' + |
'\t}\n' + |
'}\n' + |
'.div {\n' + |
'\theight: 15px;\n' + |
'}') |
t( |
'@media screen {\n' + |
'\t#foo:hover {\n' + |
'\t\tbackground-image: url(foo@2x.png);\n' + |
'\t}\n' + |
'\t@font-face {\n' + |
'\t\tfont-family: "Bitstream Vera Serif Bold";\n' + |
'\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n' + |
'\t}\n' + |
'}\n' + |
'.div{height:15px;}', |
# -- output -- |
'@media screen {\n' + |
'\t#foo:hover {\n' + |
'\t\tbackground-image: url(foo@2x.png);\n' + |
'\t}\n' + |
'\t@font-face {\n' + |
'\t\tfont-family: "Bitstream Vera Serif Bold";\n' + |
'\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n' + |
'\t}\n' + |
'}\n' + |
'.div {\n' + |
'\theight: 15px;\n' + |
'}') |
t( |
'@font-face {\n' + |
'\tfont-family: "Bitstream Vera Serif Bold";\n' + |
'\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n' + |
'}\n' + |
'@media screen {\n' + |
'\t#foo:hover {\n' + |
'\t\tbackground-image: url(foo.png);\n' + |
'\t}\n' + |
'\t@media screen and (min-device-pixel-ratio: 2) {\n' + |
'\t\t@font-face {\n' + |
'\t\t\tfont-family: "Helvetica Neue"\n' + |
'\t\t}\n' + |
'\t\t#foo:hover {\n' + |
'\t\t\tbackground-image: url(foo@2x.png);\n' + |
'\t\t}\n' + |
'\t}\n' + |
'}') |
t( |
'a:first-child{color:red;div:first-child{color:black;}}\n' + |
'.div{height:15px;}', |
# -- output -- |
'a:first-child {\n' + |
'\tcolor: red;\n' + |
'\tdiv:first-child {\n' + |
'\t\tcolor: black;\n' + |
'\t}\n' + |
'}\n' + |
'.div {\n' + |
'\theight: 15px;\n' + |
'}') |
t( |
'a:first-child{color:red;div:not(.peq){color:black;}}\n' + |
'.div{height:15px;}', |
# -- output -- |
'a:first-child {\n' + |
'\tcolor: red;\n' + |
'\tdiv:not(.peq) {\n' + |
'\t\tcolor: black;\n' + |
'\t}\n' + |
'}\n' + |
'.div {\n' + |
'\theight: 15px;\n' + |
'}') |
|
|
#============================================================ |
# Functions braces |
self.reset_options(); |
t('.tabs(){}', '.tabs() {}') |
t('.tabs (){}', '.tabs () {}') |
t( |
'.tabs (pa, pa(1,2)), .cols { }', |
# -- output -- |
'.tabs (pa, pa(1, 2)),\n' + |
'.cols {}') |
t( |
'.tabs(pa, pa(1,2)), .cols { }', |
# -- output -- |
'.tabs(pa, pa(1, 2)),\n' + |
'.cols {}') |
t('.tabs ( ) { }', '.tabs () {}') |
t('.tabs( ) { }', '.tabs() {}') |
t( |
'.tabs (t, t2) \n' + |
'{\n' + |
' key: val(p1 ,p2); \n' + |
' }', |
# -- output -- |
'.tabs (t, t2) {\n' + |
'\tkey: val(p1, p2);\n' + |
'}') |
t( |
'.box-shadow(@shadow: 0 1px 3px rgba(0, 0, 0, .25)) {\n' + |
'\t-webkit-box-shadow: @shadow;\n' + |
'\t-moz-box-shadow: @shadow;\n' + |
'\tbox-shadow: @shadow;\n' + |
'}') |
|
|
#============================================================ |
# Comments |
self.reset_options(); |
t('/* test */') |
t( |
'.tabs{/* test */}', |
# -- output -- |
'.tabs {\n' + |
'\t/* test */\n' + |
'}') |
t( |
'.tabs{/* test */}', |
# -- output -- |
'.tabs {\n' + |
'\t/* test */\n' + |
'}') |
t( |
'/* header */.tabs {}', |
# -- output -- |
'/* header */\n' + |
'\n' + |
'.tabs {}') |
t( |
'.tabs {\n' + |
'/* non-header */\n' + |
'width:10px;}', |
# -- output -- |
'.tabs {\n' + |
'\t/* non-header */\n' + |
'\twidth: 10px;\n' + |
'}') |
t('/* header') |
t('// comment') |
t( |
'.selector1 {\n' + |
'\tmargin: 0; /* This is a comment including an url http://domain.com/path/to/file.ext */\n' + |
'}', |
# -- output -- |
'.selector1 {\n' + |
'\tmargin: 0;\n' + |
'\t/* This is a comment including an url http://domain.com/path/to/file.ext */\n' + |
'}') |
|
# single line comment support (less/sass) |
t( |
'.tabs{\n' + |
'// comment\n' + |
'width:10px;\n' + |
'}', |
# -- output -- |
'.tabs {\n' + |
'\t// comment\n' + |
'\twidth: 10px;\n' + |
'}') |
t( |
'.tabs{// comment\n' + |
'width:10px;\n' + |
'}', |
# -- output -- |
'.tabs {\n' + |
'\t// comment\n' + |
'\twidth: 10px;\n' + |
'}') |
t( |
'//comment\n' + |
'.tabs{width:10px;}', |
# -- output -- |
'//comment\n' + |
'.tabs {\n' + |
'\twidth: 10px;\n' + |
'}') |
t( |
'.tabs{//comment\n' + |
'//2nd single line comment\n' + |
'width:10px;}', |
# -- output -- |
'.tabs {\n' + |
'\t//comment\n' + |
'\t//2nd single line comment\n' + |
'\twidth: 10px;\n' + |
'}') |
t( |
'.tabs{width:10px;//end of line comment\n' + |
'}', |
# -- output -- |
'.tabs {\n' + |
'\twidth: 10px; //end of line comment\n' + |
'}') |
t( |
'.tabs{width:10px;//end of line comment\n' + |
'height:10px;}', |
# -- output -- |
'.tabs {\n' + |
'\twidth: 10px; //end of line comment\n' + |
'\theight: 10px;\n' + |
'}') |
t( |
'.tabs{width:10px;//end of line comment\n' + |
'height:10px;//another\n' + |
'}', |
# -- output -- |
'.tabs {\n' + |
'\twidth: 10px; //end of line comment\n' + |
'\theight: 10px; //another\n' + |
'}') |
|
|
#============================================================ |
# Handle LESS property name interpolation |
self.reset_options(); |
t( |
'tag {\n' + |
'\t@{prop}: none;\n' + |
'}') |
t( |
'tag{@{prop}:none;}', |
# -- output -- |
'tag {\n' + |
'\t@{prop}: none;\n' + |
'}') |
t( |
'tag{ @{prop}: none;}', |
# -- output -- |
'tag {\n' + |
'\t@{prop}: none;\n' + |
'}') |
|
# can also be part of property name |
t( |
'tag {\n' + |
'\tdynamic-@{prop}: none;\n' + |
'}') |
t( |
'tag{dynamic-@{prop}:none;}', |
# -- output -- |
'tag {\n' + |
'\tdynamic-@{prop}: none;\n' + |
'}') |
t( |
'tag{ dynamic-@{prop}: none;}', |
# -- output -- |
'tag {\n' + |
'\tdynamic-@{prop}: none;\n' + |
'}') |
|
|
#============================================================ |
# Handle LESS property name interpolation, test #631 |
self.reset_options(); |
t( |
'.generate-columns(@n, @i: 1) when (@i =< @n) {\n' + |
'\t.column-@{i} {\n' + |
'\t\twidth: (@i * 100% / @n);\n' + |
'\t}\n' + |
'\t.generate-columns(@n, (@i + 1));\n' + |
'}') |
t( |
'.generate-columns(@n,@i:1) when (@i =< @n){.column-@{i}{width:(@i * 100% / @n);}.generate-columns(@n,(@i + 1));}', |
# -- output -- |
'.generate-columns(@n, @i: 1) when (@i =< @n) {\n' + |
'\t.column-@{i} {\n' + |
'\t\twidth: (@i * 100% / @n);\n' + |
'\t}\n' + |
'\t.generate-columns(@n, (@i + 1));\n' + |
'}') |
|
|
#============================================================ |
# Psuedo-classes vs Variables |
self.reset_options(); |
t('@page :first {}') |
|
# Assume the colon goes with the @name. If we're in LESS, this is required regardless of the at-string. |
t('@page:first {}', '@page: first {}') |
t('@page: first {}') |
|
|
#============================================================ |
# SASS/SCSS |
self.reset_options(); |
|
# Basic Interpolation |
t( |
'p {\n' + |
'\t$font-size: 12px;\n' + |
'\t$line-height: 30px;\n' + |
'\tfont: #{$font-size}/#{$line-height};\n' + |
'}') |
t('p.#{$name} {}') |
t( |
'@mixin itemPropertiesCoverItem($items, $margin) {\n' + |
'\twidth: calc((100% - ((#{$items} - 1) * #{$margin}rem)) / #{$items});\n' + |
'\tmargin: 1.6rem #{$margin}rem 1.6rem 0;\n' + |
'}') |
|
# Multiple filed issues in LESS due to not(:blah) |
t('&:first-of-type:not(:last-child) {}') |
t( |
'div {\n' + |
'\t&:not(:first-of-type) {\n' + |
'\t\tbackground: red;\n' + |
'\t}\n' + |
'}') |
|
|
#============================================================ |
# Proper handling of colon in selectors |
self.reset_options(); |
self.options.selector_separator_newline = false |
t('a :b {}') |
t('a ::b {}') |
t('a:b {}') |
t('a::b {}') |
t( |
'a {}, a::b {}, a ::b {}, a:b {}, a :b {}', |
# -- output -- |
'a {}\n' + |
', a::b {}\n' + |
', a ::b {}\n' + |
', a:b {}\n' + |
', a :b {}') |
t( |
'.card-blue ::-webkit-input-placeholder {\n' + |
'\tcolor: #87D1FF;\n' + |
'}') |
t( |
'div [attr] :not(.class) {\n' + |
'\tcolor: red;\n' + |
'}') |
|
|
#============================================================ |
# Regresssion Tests |
self.reset_options(); |
self.options.selector_separator_newline = false |
t( |
'@media(min-width:768px) {\n' + |
'\t.selector::after {\n' + |
'\t\t/* property: value */\n' + |
'\t}\n' + |
'\t.other-selector {\n' + |
'\t\t/* property: value */\n' + |
'\t}\n' + |
'}') |
t( |
'.fa-rotate-270 {\n' + |
'\tfilter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);\n' + |
'}') |
|
|
#============================================================ |
# |
self.reset_options(); |
|
|
|
def testNewline(self): |
self.reset_options() |
t = self.decodesto |
|
self.options.end_with_newline = True |
t("", "\n") |
t("\n", "\n") |
t(".tabs{}\n", ".tabs {}\n") |
t(".tabs{}", ".tabs {}\n") |
|
def testBasics(self): |
self.reset_options() |
t = self.decodesto |
|
t("", "") |
t("\n", "") |
t(".tabs{}\n", ".tabs {}") |
t(".tabs{}", ".tabs {}") |
t(".tabs{color:red}", ".tabs {\n\tcolor: red\n}") |
t(".tabs{color:rgb(255, 255, 0)}", ".tabs {\n\tcolor: rgb(255, 255, 0)\n}") |
t(".tabs{background:url('back.jpg')}", ".tabs {\n\tbackground: url('back.jpg')\n}") |
t("#bla, #foo{color:red}", "#bla,\n#foo {\n\tcolor: red\n}") |
t("@media print {.tab{}}", "@media print {\n\t.tab {}\n}") |
t("@media print {.tab{background-image:url(foo@2x.png)}}", "@media print {\n\t.tab {\n\t\tbackground-image: url(foo@2x.png)\n\t}\n}") |
|
t("a:before {\n" + |
"\tcontent: 'a{color:black;}\"\"\\'\\'\"\\n\\n\\na{color:black}\';\n" + |
"}"); |
|
# may not eat the space before "[" |
t('html.js [data-custom="123"] {\n\topacity: 1.00;\n}') |
t('html.js *[data-custom="123"] {\n\topacity: 1.00;\n}') |
|
# lead-in whitespace determines base-indent. |
# lead-in newlines are stripped. |
t("\n\na, img {padding: 0.2px}", "a,\nimg {\n\tpadding: 0.2px\n}") |
t(" a, img {padding: 0.2px}", " a,\n img {\n \tpadding: 0.2px\n }") |
t(" \t \na, img {padding: 0.2px}", " \t a,\n \t img {\n \t \tpadding: 0.2px\n \t }") |
t("\n\n a, img {padding: 0.2px}", "a,\nimg {\n\tpadding: 0.2px\n}") |
|
def testSeperateSelectors(self): |
self.reset_options() |
t = self.decodesto |
|
t("#bla, #foo{color:red}", "#bla,\n#foo {\n\tcolor: red\n}") |
t("a, img {padding: 0.2px}", "a,\nimg {\n\tpadding: 0.2px\n}") |
|
|
def testBlockNesting(self): |
self.reset_options() |
t = self.decodesto |
|
t("#foo {\n\tbackground-image: url(foo@2x.png);\n\t@font-face {\n\t\tfont-family: 'Bitstream Vera Serif Bold';\n\t\tsrc: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');\n\t}\n}") |
t("@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n\t@font-face {\n\t\tfont-family: 'Bitstream Vera Serif Bold';\n\t\tsrc: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');\n\t}\n}") |
|
# @font-face { |
# font-family: 'Bitstream Vera Serif Bold'; |
# src: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf'); |
# } |
# @media screen { |
# #foo:hover { |
# background-image: url(foo.png); |
# } |
# @media screen and (min-device-pixel-ratio: 2) { |
# @font-face { |
# font-family: 'Helvetica Neue' |
# } |
# #foo:hover { |
# background-image: url(foo@2x.png); |
# } |
# } |
# } |
t("@font-face {\n\tfont-family: 'Bitstream Vera Serif Bold';\n\tsrc: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');\n}\n@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo.png);\n\t}\n\t@media screen and (min-device-pixel-ratio: 2) {\n\t\t@font-face {\n\t\t\tfont-family: 'Helvetica Neue'\n\t\t}\n\t\t#foo:hover {\n\t\t\tbackground-image: url(foo@2x.png);\n\t\t}\n\t}\n}") |
|
|
def testOptions(self): |
self.reset_options() |
self.options.indent_size = 2 |
self.options.indent_char = ' ' |
self.options.selector_separator_newline = False |
t = self.decodesto |
|
# pseudo-classes and pseudo-elements |
t("#foo:hover {\n background-image: url(foo@2x.png)\n}") |
t("#foo *:hover {\n color: purple\n}") |
t("::selection {\n color: #ff0000;\n}") |
|
# TODO: don't break nested pseduo-classes |
t("@media screen {.tab,.bat:hover {color:red}}", "@media screen {\n .tab, .bat:hover {\n color: red\n }\n}") |
|
# particular edge case with braces and semicolons inside tags that allows custom text |
t( "a:not(\"foobar\\\";{}omg\"){\ncontent: 'example\\';{} text';\ncontent: \"example\\\";{} text\";}", |
"a:not(\"foobar\\\";{}omg\") {\n content: 'example\\';{} text';\n content: \"example\\\";{} text\";\n}") |
|
def testLessCss(self): |
self.reset_options() |
t = self.decodesto |
|
t('.well{ \n @well-bg:@bg-color;@well-fg:@fg-color;}','.well {\n\t@well-bg: @bg-color;\n\t@well-fg: @fg-color;\n}') |
t('.well {&.active {\nbox-shadow: 0 1px 1px @border-color, 1px 0 1px @border-color;}}', |
'.well {\n' + |
'\t&.active {\n' + |
'\t\tbox-shadow: 0 1px 1px @border-color, 1px 0 1px @border-color;\n' + |
'\t}\n' + |
'}') |
t('a {\n' + |
'\tcolor: blue;\n' + |
'\t&:hover {\n' + |
'\t\tcolor: green;\n' + |
'\t}\n' + |
'\t& & &&&.active {\n' + |
'\t\tcolor: green;\n' + |
'\t}\n' + |
'}') |
|
# Not sure if this is sensible |
# but I believe it is correct to not remove the space in "&: hover". |
t('a {\n' + |
'\t&: hover {\n' + |
'\t\tcolor: green;\n' + |
'\t}\n' + |
'}'); |
|
# import |
t('@import "test";'); |
|
# don't break nested pseudo-classes |
t("a:first-child{color:red;div:first-child{color:black;}}", |
"a:first-child {\n\tcolor: red;\n\tdiv:first-child {\n\t\tcolor: black;\n\t}\n}"); |
|
# handle SASS/LESS parent reference |
t("div{&:first-letter {text-transform: uppercase;}}", |
"div {\n\t&:first-letter {\n\t\ttext-transform: uppercase;\n\t}\n}"); |
|
# nested modifiers (&:hover etc) |
t(".tabs{&:hover{width:10px;}}", ".tabs {\n\t&:hover {\n\t\twidth: 10px;\n\t}\n}") |
t(".tabs{&.big{width:10px;}}", ".tabs {\n\t&.big {\n\t\twidth: 10px;\n\t}\n}") |
t(".tabs{&>big{width:10px;}}", ".tabs {\n\t&>big {\n\t\twidth: 10px;\n\t}\n}") |
t(".tabs{&+.big{width:10px;}}", ".tabs {\n\t&+.big {\n\t\twidth: 10px;\n\t}\n}") |
|
# nested rules |
t(".tabs{.child{width:10px;}}", ".tabs {\n\t.child {\n\t\twidth: 10px;\n\t}\n}") |
|
# variables |
t("@myvar:10px;.tabs{width:10px;}", "@myvar: 10px;\n.tabs {\n\twidth: 10px;\n}") |
t("@myvar:10px; .tabs{width:10px;}", "@myvar: 10px;\n.tabs {\n\twidth: 10px;\n}") |
|
def decodesto(self, input, expectation=None): |
if expectation == None: |
expectation = input |
|
self.assertMultiLineEqual( |
cssbeautifier.beautify(input, self.options), expectation) |
|
# if the expected is different from input, run it again |
# expected output should be unchanged when run twice. |
if not expectation != input: |
self.assertMultiLineEqual( |
cssbeautifier.beautify(expectation, self.options), expectation) |
|
# Everywhere we do newlines, they should be replaced with opts.eol |
self.options.eol = '\r\\n'; |
expectation = expectation.replace('\n', '\r\n') |
self.assertMultiLineEqual( |
cssbeautifier.beautify(input, self.options), expectation) |
if input.find('\n') != -1: |
input = input.replace('\n', '\r\n') |
self.assertMultiLineEqual( |
cssbeautifier.beautify(input, self.options), expectation) |
# Ensure support for auto eol detection |
self.options.eol = 'auto' |
self.assertMultiLineEqual( |
cssbeautifier.beautify(input, self.options), expectation) |
self.options.eol = '\n' |
|
if __name__ == '__main__': |
unittest.main() |