Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
|
|
@ -0,0 +1,2 @@
|
|||
include js-beautify
|
||||
include js-beautify-test
|
||||
|
|
@ -0,0 +1,467 @@
|
|||
from __future__ import print_function
|
||||
import sys
|
||||
import re
|
||||
from cssbeautifier.__version__ import __version__
|
||||
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
|
||||
# Copyright (c) 2013 Einar Lielmanis 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.selector_separator_newline = True
|
||||
self.end_with_newline = False
|
||||
self.newline_between_rules = True
|
||||
self.eol = '\n'
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return \
|
||||
"""indent_size = %d
|
||||
indent_char = [%s]
|
||||
indent_with_tabs = [%s]
|
||||
separate_selectors_newline = [%s]
|
||||
end_with_newline = [%s]
|
||||
newline_between_rules = [%s]
|
||||
""" % (self.indent_size, self.indent_char, self.indent_with_tabs,
|
||||
self.selector_separator_newline, self.end_with_newline, self.newline_between_rules)
|
||||
|
||||
|
||||
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, indent_char, indent_size, default_indent=""):
|
||||
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("{")
|
||||
self.newLine()
|
||||
|
||||
def closeBracket(self):
|
||||
self.newLine()
|
||||
self.output.append("}")
|
||||
self.newLine()
|
||||
|
||||
def semicolon(self):
|
||||
self.output.append(";")
|
||||
self.newLine()
|
||||
|
||||
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()
|
||||
|
||||
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")
|
||||
|
||||
if not source_text:
|
||||
source_text = ''
|
||||
|
||||
# HACK: newline parsing inconsistent. This brute force normalizes the input newlines.
|
||||
lineBreak = re.compile(self.six.u("\r\n|[\r\u2028\u2029]"))
|
||||
source_text = re.sub(lineBreak, '\n', source_text)
|
||||
|
||||
self.source_text = source_text
|
||||
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
|
||||
|
||||
self.opts.eol = self.opts.eol.replace('\\r', '\r').replace('\\n', '\n')
|
||||
|
||||
# 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"]
|
||||
|
||||
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):
|
||||
result = ''
|
||||
while WHITE_RE.search(self.peek()) is not None:
|
||||
self.next()
|
||||
result += self.ch
|
||||
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):
|
||||
m = re.search("^[\t ]*", self.source_text)
|
||||
baseIndentString = m.group(0)
|
||||
printer = Printer(self.indentChar, self.indentSize, baseIndentString)
|
||||
|
||||
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)
|
||||
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.newLine()
|
||||
if 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()
|
||||
insideRule = False
|
||||
insidePropertyValue = False
|
||||
if printer.nestedLevel:
|
||||
printer.nestedLevel -= 1
|
||||
if 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()):
|
||||
# 'property: value' delimiter
|
||||
# which could be in a conditional group query
|
||||
insidePropertyValue = True
|
||||
printer.push(":")
|
||||
printer.singleSpace()
|
||||
else:
|
||||
# sass/less parent reference don't use a space
|
||||
# sass nested pseudo-class don't use a space
|
||||
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()
|
||||
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)
|
||||
self.eatWhitespace()
|
||||
if not insidePropertyValue and self.opts.selector_separator_newline and parenLevel < 1:
|
||||
printer.newLine()
|
||||
else:
|
||||
printer.singleSpace()
|
||||
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()
|
||||
self.ch = '='
|
||||
printer.push(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
|
||||
|
|
@ -0,0 +1 @@
|
|||
__version__ = '1.0.0'
|
||||
|
|
@ -0,0 +1 @@
|
|||
# Empty file :)
|
||||
|
|
@ -0,0 +1,342 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import unittest
|
||||
import cssbeautifier
|
||||
|
||||
|
||||
class CSSBeautifierTest(unittest.TestCase):
|
||||
|
||||
def resetOptions(self):
|
||||
false = False
|
||||
true = True
|
||||
self.options = cssbeautifier.default_options()
|
||||
self.options.indent_size = 1
|
||||
self.options.indent_char = '\t'
|
||||
self.options.selector_separator_newline = true
|
||||
self.options.end_with_newline = false
|
||||
self.options.newline_between_rules = false
|
||||
|
||||
def testGenerated(self):
|
||||
self.resetOptions()
|
||||
test_fragment = self.decodesto
|
||||
t = self.decodesto
|
||||
|
||||
false = False
|
||||
true = True
|
||||
|
||||
self.options.indent_size = 1
|
||||
self.options.indent_char = '\t'
|
||||
self.options.selector_separator_newline = true
|
||||
self.options.end_with_newline = false
|
||||
self.options.newline_between_rules = false
|
||||
|
||||
# End With Newline - (eof = "\n")
|
||||
self.options.end_with_newline = true
|
||||
test_fragment('', '\n')
|
||||
test_fragment(' .tabs{}', ' .tabs {}\n')
|
||||
test_fragment(' \n\n.tabs{}\n\n\n\n', ' .tabs {}\n')
|
||||
test_fragment('\n')
|
||||
|
||||
# End With Newline - (eof = "")
|
||||
self.options.end_with_newline = false
|
||||
test_fragment('')
|
||||
test_fragment(' .tabs{}', ' .tabs {}')
|
||||
test_fragment(' \n\n.tabs{}\n\n\n\n', ' .tabs {}')
|
||||
test_fragment('\n', '')
|
||||
|
||||
# Empty braces
|
||||
t('.tabs{}', '.tabs {}')
|
||||
t('.tabs { }', '.tabs {}')
|
||||
t('.tabs { }', '.tabs {}')
|
||||
t('.tabs \n{\n \n }', '.tabs {}')
|
||||
|
||||
#
|
||||
t('#cboxOverlay {\n\tbackground: url(images/overlay.png) repeat 0 0;\n\topacity: 0.9;\n\tfilter: alpha(opacity = 90);\n}', '#cboxOverlay {\n\tbackground: url(images/overlay.png) repeat 0 0;\n\topacity: 0.9;\n\tfilter: alpha(opacity=90);\n}')
|
||||
|
||||
# Selector Separator - (separator = " ", separator1 = " ")
|
||||
self.options.selector_separator_newline = false
|
||||
self.options.selector_separator = " "
|
||||
t('#bla, #foo{color:green}', '#bla, #foo {\n\tcolor: green\n}')
|
||||
t('@media print {.tab{}}', '@media print {\n\t.tab {}\n}')
|
||||
t('@media print {.tab,.bat{}}', '@media print {\n\t.tab, .bat {}\n}')
|
||||
t('#bla, #foo{color:black}', '#bla, #foo {\n\tcolor: black\n}')
|
||||
t('a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}', '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.options.selector_separator_newline = false
|
||||
self.options.selector_separator = " "
|
||||
t('#bla, #foo{color:green}', '#bla, #foo {\n\tcolor: green\n}')
|
||||
t('@media print {.tab{}}', '@media print {\n\t.tab {}\n}')
|
||||
t('@media print {.tab,.bat{}}', '@media print {\n\t.tab, .bat {}\n}')
|
||||
t('#bla, #foo{color:black}', '#bla, #foo {\n\tcolor: black\n}')
|
||||
t('a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}', '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.options.selector_separator_newline = true
|
||||
self.options.selector_separator = " "
|
||||
t('#bla, #foo{color:green}', '#bla,\n#foo {\n\tcolor: green\n}')
|
||||
t('@media print {.tab{}}', '@media print {\n\t.tab {}\n}')
|
||||
t('@media print {.tab,.bat{}}', '@media print {\n\t.tab,\n\t.bat {}\n}')
|
||||
t('#bla, #foo{color:black}', '#bla,\n#foo {\n\tcolor: black\n}')
|
||||
t('a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}', '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.options.selector_separator_newline = true
|
||||
self.options.selector_separator = " "
|
||||
t('#bla, #foo{color:green}', '#bla,\n#foo {\n\tcolor: green\n}')
|
||||
t('@media print {.tab{}}', '@media print {\n\t.tab {}\n}')
|
||||
t('@media print {.tab,.bat{}}', '@media print {\n\t.tab,\n\t.bat {}\n}')
|
||||
t('#bla, #foo{color:black}', '#bla,\n#foo {\n\tcolor: black\n}')
|
||||
t('a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}', 'a:first-child,\na:first-child {\n\tcolor: red;\n\tdiv:first-child,\n\tdiv:hover {\n\t\tcolor: black;\n\t}\n}')
|
||||
|
||||
# Newline Between Rules - (separator = "\n")
|
||||
self.options.newline_between_rules = true
|
||||
t('.div {}\n.span {}', '.div {}\n\n.span {}')
|
||||
t('.div{}\n \n.span{}', '.div {}\n\n.span {}')
|
||||
t('.div {} \n \n.span { } \n', '.div {}\n\n.span {}')
|
||||
t('.div {\n \n} \n .span {\n } ', '.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;}', '.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\nheight:10px;//another\n}\n.div{height:15px;}', '.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;}', '#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;}', '@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}', '@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;}', '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;}', '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.options.newline_between_rules = false
|
||||
t('.div {}\n.span {}')
|
||||
t('.div{}\n \n.span{}', '.div {}\n.span {}')
|
||||
t('.div {} \n \n.span { } \n', '.div {}\n.span {}')
|
||||
t('.div {\n \n} \n .span {\n } ', '.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;}', '.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\nheight:10px;//another\n}\n.div{height:15px;}', '.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;}', '#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;}', '@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;}', '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;}', '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
|
||||
t('.tabs(){}', '.tabs() {}')
|
||||
t('.tabs (){}', '.tabs () {}')
|
||||
t('.tabs (pa, pa(1,2)), .cols { }', '.tabs (pa, pa(1, 2)),\n.cols {}')
|
||||
t('.tabs(pa, pa(1,2)), .cols { }', '.tabs(pa, pa(1, 2)),\n.cols {}')
|
||||
t('.tabs ( ) { }', '.tabs () {}')
|
||||
t('.tabs( ) { }', '.tabs() {}')
|
||||
t('.tabs (t, t2) \n{\n key: val(p1 ,p2); \n }', '.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
|
||||
t('/* test */')
|
||||
t('.tabs{/* test */}', '.tabs {\n\t/* test */\n}')
|
||||
t('.tabs{/* test */}', '.tabs {\n\t/* test */\n}')
|
||||
t('/* header */.tabs {}', '/* header */\n\n.tabs {}')
|
||||
t('.tabs {\n/* non-header */\nwidth:10px;}', '.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}', '.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\nwidth:10px;\n}', '.tabs {\n\t// comment\n\twidth: 10px;\n}')
|
||||
t('.tabs{// comment\nwidth:10px;\n}', '.tabs {\n\t// comment\n\twidth: 10px;\n}')
|
||||
t('//comment\n.tabs{width:10px;}', '//comment\n.tabs {\n\twidth: 10px;\n}')
|
||||
t('.tabs{//comment\n//2nd single line comment\nwidth:10px;}', '.tabs {\n\t//comment\n\t//2nd single line comment\n\twidth: 10px;\n}')
|
||||
t('.tabs{width:10px;//end of line comment\n}', '.tabs {\n\twidth: 10px; //end of line comment\n}')
|
||||
t('.tabs{width:10px;//end of line comment\nheight:10px;}', '.tabs {\n\twidth: 10px; //end of line comment\n\theight: 10px;\n}')
|
||||
t('.tabs{width:10px;//end of line comment\nheight:10px;//another\n}', '.tabs {\n\twidth: 10px; //end of line comment\n\theight: 10px; //another\n}')
|
||||
|
||||
# Psuedo-classes vs Variables
|
||||
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
|
||||
|
||||
# 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' +
|
||||
'}')
|
||||
|
||||
#
|
||||
|
||||
|
||||
def testNewline(self):
|
||||
self.resetOptions()
|
||||
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.resetOptions()
|
||||
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.resetOptions()
|
||||
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.resetOptions()
|
||||
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.resetOptions()
|
||||
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.resetOptions()
|
||||
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)
|
||||
input = input.replace('\n', '\r\n')
|
||||
self.assertMultiLineEqual(
|
||||
cssbeautifier.beautify(input, self.options), expectation)
|
||||
self.options.eol = '\n'
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#! /usr/bin/env python
|
||||
#
|
||||
# Stub script to run jsbeautifier
|
||||
#
|
||||
import sys
|
||||
from jsbeautifier import main
|
||||
sys.exit(main())
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#! /usr/bin/env python
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
#Speedup things...
|
||||
try:
|
||||
import cProfile as profile
|
||||
except ImportError:
|
||||
import profile
|
||||
|
||||
def run():
|
||||
sys.argv.append('discover')
|
||||
unittest.main()
|
||||
|
||||
profile.run('run()')
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# Test suite launcher
|
||||
#
|
||||
|
||||
if [ -z $PYTHON ]; then
|
||||
env python -m unittest discover "$@"
|
||||
else
|
||||
env $PYTHON -m unittest discover "$@"
|
||||
fi
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1 @@
|
|||
__version__ = '1.5.10'
|
||||
|
|
@ -0,0 +1 @@
|
|||
# Empty file :)
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
#!/bin/bash
|
||||
|
||||
REL_SCRIPT_DIR="`dirname \"$0\"`"
|
||||
SCRIPT_DIR="`( cd \"$REL_SCRIPT_DIR\" && pwd )`"
|
||||
|
||||
test_cli_common()
|
||||
{
|
||||
echo ----------------------------------------
|
||||
echo Testing common cli behavior...
|
||||
CLI_SCRIPT_NAME=${1:?missing_param}
|
||||
CLI_SCRIPT=$SCRIPT_DIR/../../$CLI_SCRIPT_NAME
|
||||
echo Script: $CLI_SCRIPT
|
||||
|
||||
# should find the minimal help output
|
||||
$CLI_SCRIPT 2>&1 | grep -q "Must define at least one file\." || {
|
||||
echo "[$CLI_SCRIPT_NAME] Output should be help message."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT 2> /dev/null && {
|
||||
echo "[$CLI_SCRIPT_NAME (with no parameters)] Return code should be error."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT -Z 2> /dev/null && {
|
||||
echo "[$CLI_SCRIPT_NAME -Z] Return code for invalid parameter should be error."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT -h > /dev/null || {
|
||||
echo "[$CLI_SCRIPT_NAME -h] Return code should be success."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT -v > /dev/null || {
|
||||
echo "[$CLI_SCRIPT_NAME -v] Return code should be success."
|
||||
exit 1
|
||||
}
|
||||
|
||||
MISSING_FILE="$SCRIPT_DIR/../../../js/bin/missing_file"
|
||||
MISSING_FILE_MESSAGE="No such file or directory"
|
||||
$CLI_SCRIPT $MISSING_FILE 2> /dev/null && {
|
||||
echo "[$CLI_SCRIPT_NAME $MISSING_FILE] Return code should be error."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT $MISSING_FILE 2>&1 | grep -q "$MISSING_FILE_MESSAGE" || {
|
||||
echo "[$CLI_SCRIPT_NAME $MISSING_FILE] Stderr should have useful message."
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ "`$CLI_SCRIPT $MISSING_FILE 2> /dev/null`" != "" ]; then
|
||||
echo "[$CLI_SCRIPT_NAME $MISSING_FILE] Stdout should have no text."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
test_cli_js_beautify()
|
||||
{
|
||||
echo ----------------------------------------
|
||||
echo Testing js-beautify cli behavior...
|
||||
CLI_SCRIPT=$SCRIPT_DIR/../../js-beautify
|
||||
|
||||
$CLI_SCRIPT $SCRIPT_DIR/../../../js/bin/js-beautify.js > /dev/null || {
|
||||
echo "js-beautify output for $SCRIPT_DIR/../bin/js-beautify.js was expected succeed."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT $SCRIPT_DIR/../../../js/bin/css-beautify.js > /dev/null || {
|
||||
echo "js-beautify output for $SCRIPT_DIR/../../../js/bin/css-beautify.js was expected succeed."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT $SCRIPT_DIR/../../../js/bin/js-beautify.js | diff $SCRIPT_DIR/../../../js/bin/js-beautify.js - || {
|
||||
echo "js-beautify output for $SCRIPT_DIR/../../../js/bin/js-beautify.js was expected to be unchanged."
|
||||
exit 1
|
||||
}
|
||||
|
||||
rm -rf /tmp/js-beautify-mkdir
|
||||
$CLI_SCRIPT -o /tmp/js-beautify-mkdir/js-beautify.js $SCRIPT_DIR/../../../js/bin/js-beautify.js && diff $SCRIPT_DIR/../../../js/bin/js-beautify.js /tmp/js-beautify-mkdir/js-beautify.js || {
|
||||
echo "js-beautify output for $SCRIPT_DIR/../../../js/bin/js-beautify.js should have been created in /tmp/js-beautify-mkdir/js-beautify.js."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ensure unchanged files are not overwritten
|
||||
cp -p /tmp/js-beautify-mkdir/js-beautify.js /tmp/js-beautify-mkdir/js-beautify-old.js
|
||||
touch -A -05 /tmp/js-beautify-mkdir/js-beautify.js
|
||||
touch -A -01 /tmp/js-beautify-mkdir/js-beautify-old.js
|
||||
$CLI_SCRIPT -r /tmp/js-beautify-mkdir/js-beautify.js && test /tmp/js-beautify-mkdir/js-beautify.js -nt /tmp/js-beautify-mkdir/js-beautify-old.js && {
|
||||
echo "js-beautify should not replace unchanged file /tmp/js-beautify-mkdir/js-beautify.js when using -r"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT -o /tmp/js-beautify-mkdir/js-beautify.js /tmp/js-beautify-mkdir/js-beautify.js && test /tmp/js-beautify-mkdir/js-beautify.js -nt /tmp/js-beautify-mkdir/js-beautify-old.js && {
|
||||
echo "js-beautify should not replace unchanged file /tmp/js-beautify-mkdir/js-beautify.js when using -o and same file name"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT -o /tmp/js-beautify-mkdir/js-beautify.js /tmp/js-beautify-mkdir/js-beautify-old.js && test /tmp/js-beautify-mkdir/js-beautify.js -nt /tmp/js-beautify-mkdir/js-beautify-old.js && {
|
||||
echo "js-beautify should not replace unchanged file /tmp/js-beautify-mkdir/js-beautify.js when using -o and different file name"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT $SCRIPT_DIR/../../../js/bin/css-beautify.js | diff -q $SCRIPT_DIR/../../../js/bin/css-beautify.js - && {
|
||||
echo "js-beautify output for $SCRIPT_DIR/../../../js/bin/css-beautify.js was expected to be different."
|
||||
exit 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
test_smoke_js_beautify()
|
||||
{
|
||||
echo ----------------------------------------
|
||||
echo Testing beautify functionality...
|
||||
PYTHON=python $SCRIPT_DIR/../../js-beautify-test || exit 1
|
||||
}
|
||||
|
||||
test_perf_js_beautify()
|
||||
{
|
||||
echo ----------------------------------------
|
||||
echo Testing beautify performance...
|
||||
# PYTHON=python $SCRIPT_DIR/../../js-beautify-profile || exit 1
|
||||
python $SCRIPT_DIR/test-perf-jsbeautifier.py || exit 1
|
||||
|
||||
}
|
||||
#test_cli_common css-beautify
|
||||
#test_cli_common html-beautify
|
||||
test_cli_common js-beautify
|
||||
|
||||
test_cli_js_beautify
|
||||
test_smoke_js_beautify
|
||||
test_perf_js_beautify
|
||||
|
||||
echo ----------------------------------------
|
||||
echo $0 - PASSED.
|
||||
echo ----------------------------------------
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import copy
|
||||
import jsbeautifier
|
||||
options = jsbeautifier.default_options()
|
||||
options.wrap_line_length = 80
|
||||
data = ''
|
||||
data_min = ''
|
||||
|
||||
def beautifier_test_underscore():
|
||||
jsbeautifier.beautify(data, options)
|
||||
|
||||
def beautifier_test_underscore_min():
|
||||
jsbeautifier.beautify(data_min, options)
|
||||
|
||||
def report_perf(fn):
|
||||
import timeit
|
||||
iter = 50
|
||||
time = timeit.timeit(fn + "()", setup="from __main__ import " + fn + "; gc.enable()", number=iter)
|
||||
print(fn + ": " + str(iter/time) + " cycles/sec")
|
||||
|
||||
if __name__ == '__main__':
|
||||
dirname = os.path.dirname(os.path.abspath(__file__))
|
||||
underscore_file = os.path.join(dirname, "../../../", "test/underscore.js")
|
||||
underscore_min_file = os.path.join(dirname, "../../../", "test/underscore-min.js")
|
||||
data = copy.copy(''.join(open(underscore_file).readlines()))
|
||||
data_min = copy.copy(''.join(open(underscore_min_file).readlines()))
|
||||
|
||||
# warm up
|
||||
beautifier_test_underscore()
|
||||
beautifier_test_underscore_min()
|
||||
|
||||
report_perf("beautifier_test_underscore")
|
||||
report_perf("beautifier_test_underscore_min")
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
import re
|
||||
import unittest
|
||||
import jsbeautifier
|
||||
|
||||
class TestJSBeautifierIndentation(unittest.TestCase):
|
||||
def test_tabs(self):
|
||||
test_fragment = self.decodesto
|
||||
|
||||
self.options.indent_with_tabs = 1;
|
||||
test_fragment('{tabs()}', "{\n\ttabs()\n}");
|
||||
|
||||
def test_function_indent(self):
|
||||
test_fragment = self.decodesto
|
||||
|
||||
self.options.indent_with_tabs = 1;
|
||||
self.options.keep_function_indentation = 1;
|
||||
test_fragment('var foo = function(){ bar() }();', "var foo = function() {\n\tbar()\n}();");
|
||||
|
||||
self.options.tabs = 1;
|
||||
self.options.keep_function_indentation = 0;
|
||||
test_fragment('var foo = function(){ baz() }();', "var foo = function() {\n\tbaz()\n}();");
|
||||
|
||||
def decodesto(self, input, expectation=None):
|
||||
self.assertEqual(
|
||||
jsbeautifier.beautify(input, self.options), expectation or input)
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
options = jsbeautifier.default_options()
|
||||
options.indent_size = 4
|
||||
options.indent_char = ' '
|
||||
options.preserve_newlines = True
|
||||
options.jslint_happy = False
|
||||
options.keep_array_indentation = False
|
||||
options.brace_style = 'collapse'
|
||||
options.indent_level = 0
|
||||
|
||||
cls.options = options
|
||||
cls.wrapregex = re.compile('^(.+)$', re.MULTILINE)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,25 @@
|
|||
# UNPACKERS SPECIFICATIONS
|
||||
|
||||
Nothing very difficult: an unpacker is a submodule placed in the directory
|
||||
where this file was found. Each unpacker must define three symbols:
|
||||
|
||||
* `PRIORITY` : integer number expressing the priority in applying this
|
||||
unpacker. Lower number means higher priority.
|
||||
Makes sense only if a source file has been packed with
|
||||
more than one packer.
|
||||
* `detect(source)` : returns `True` if source is packed, otherwise, `False`.
|
||||
* `unpack(source)` : takes a `source` string and unpacks it. Must always return
|
||||
valid JavaScript. That is to say, your code should look
|
||||
like:
|
||||
|
||||
```
|
||||
if detect(source):
|
||||
return do_your_fancy_things_with(source)
|
||||
else:
|
||||
return source
|
||||
```
|
||||
|
||||
*You can safely define any other symbol in your module, as it will be ignored.*
|
||||
|
||||
`__init__` code will automatically load new unpackers, without any further step
|
||||
to be accomplished. Simply drop it in this directory.
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
#
|
||||
# General code for JSBeautifier unpackers infrastructure. See README.specs
|
||||
# written by Stefano Sanfilippo <a.little.coder@gmail.com>
|
||||
#
|
||||
|
||||
"""General code for JSBeautifier unpackers infrastructure."""
|
||||
|
||||
import pkgutil
|
||||
import re
|
||||
from jsbeautifier.unpackers import evalbased
|
||||
|
||||
# NOTE: AT THE MOMENT, IT IS DEACTIVATED FOR YOUR SECURITY: it runs js!
|
||||
BLACKLIST = ['jsbeautifier.unpackers.evalbased']
|
||||
|
||||
class UnpackingError(Exception):
|
||||
"""Badly packed source or general error. Argument is a
|
||||
meaningful description."""
|
||||
pass
|
||||
|
||||
def getunpackers():
|
||||
"""Scans the unpackers dir, finds unpackers and add them to UNPACKERS list.
|
||||
An unpacker will be loaded only if it is a valid python module (name must
|
||||
adhere to naming conventions) and it is not blacklisted (i.e. inserted
|
||||
into BLACKLIST."""
|
||||
path = __path__
|
||||
prefix = __name__ + '.'
|
||||
unpackers = []
|
||||
interface = ['unpack', 'detect', 'PRIORITY']
|
||||
for _importer, modname, _ispkg in pkgutil.iter_modules(path, prefix):
|
||||
if 'tests' not in modname and modname not in BLACKLIST:
|
||||
try:
|
||||
module = __import__(modname, fromlist=interface)
|
||||
except ImportError:
|
||||
raise UnpackingError('Bad unpacker: %s' % modname)
|
||||
else:
|
||||
unpackers.append(module)
|
||||
|
||||
return sorted(unpackers, key = lambda mod: mod.PRIORITY)
|
||||
|
||||
UNPACKERS = getunpackers()
|
||||
|
||||
def run(source, evalcode=False):
|
||||
"""Runs the applicable unpackers and return unpacked source as a string."""
|
||||
for unpacker in [mod for mod in UNPACKERS if mod.detect(source)]:
|
||||
source = unpacker.unpack(source)
|
||||
if evalcode and evalbased.detect(source):
|
||||
source = evalbased.unpack(source)
|
||||
return source
|
||||
|
||||
def filtercomments(source):
|
||||
"""NOT USED: strips trailing comments and put them at the top."""
|
||||
trailing_comments = []
|
||||
comment = True
|
||||
|
||||
while comment:
|
||||
if re.search(r'^\s*\/\*', source):
|
||||
comment = source[0, source.index('*/') + 2]
|
||||
elif re.search(r'^\s*\/\/', source):
|
||||
comment = re.search(r'^\s*\/\/', source).group(0)
|
||||
else:
|
||||
comment = None
|
||||
|
||||
if comment:
|
||||
source = re.sub(r'^\s+', '', source[len(comment):])
|
||||
trailing_comments.append(comment)
|
||||
|
||||
return '\n'.join(trailing_comments) + source
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#
|
||||
# Unpacker for eval() based packers, a part of javascript beautifier
|
||||
# by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
#
|
||||
# written by Stefano Sanfilippo <a.little.coder@gmail.com>
|
||||
#
|
||||
# usage:
|
||||
#
|
||||
# if detect(some_string):
|
||||
# unpacked = unpack(some_string)
|
||||
#
|
||||
|
||||
"""Unpacker for eval() based packers: runs JS code and returns result.
|
||||
Works only if a JS interpreter (e.g. Mozilla's Rhino) is installed and
|
||||
properly set up on host."""
|
||||
|
||||
from subprocess import PIPE, Popen
|
||||
|
||||
PRIORITY = 3
|
||||
|
||||
def detect(source):
|
||||
"""Detects if source is likely to be eval() packed."""
|
||||
return source.strip().lower().startswith('eval(function(')
|
||||
|
||||
def unpack(source):
|
||||
"""Runs source and return resulting code."""
|
||||
return jseval('print %s;' % source[4:]) if detect(source) else source
|
||||
|
||||
# In case of failure, we'll just return the original, without crashing on user.
|
||||
def jseval(script):
|
||||
"""Run code in the JS interpreter and return output."""
|
||||
try:
|
||||
interpreter = Popen(['js'], stdin=PIPE, stdout=PIPE)
|
||||
except OSError:
|
||||
return script
|
||||
result, errors = interpreter.communicate(script)
|
||||
if interpreter.poll() or errors:
|
||||
return script
|
||||
return result
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
#
|
||||
# simple unpacker/deobfuscator for scripts messed up with
|
||||
# javascriptobfuscator.com
|
||||
#
|
||||
# written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
# rewritten in Python by Stefano Sanfilippo <a.little.coder@gmail.com>
|
||||
#
|
||||
# Will always return valid javascript: if `detect()` is false, `code` is
|
||||
# returned, unmodified.
|
||||
#
|
||||
# usage:
|
||||
#
|
||||
# if javascriptobfuscator.detect(some_string):
|
||||
# some_string = javascriptobfuscator.unpack(some_string)
|
||||
#
|
||||
|
||||
"""deobfuscator for scripts messed up with JavascriptObfuscator.com"""
|
||||
|
||||
import re
|
||||
|
||||
PRIORITY = 1
|
||||
|
||||
def smartsplit(code):
|
||||
"""Split `code` at " symbol, only if it is not escaped."""
|
||||
strings = []
|
||||
pos = 0
|
||||
while pos < len(code):
|
||||
if code[pos] == '"':
|
||||
word = '' # new word
|
||||
pos += 1
|
||||
while pos < len(code):
|
||||
if code[pos] == '"':
|
||||
break
|
||||
if code[pos] == '\\':
|
||||
word += '\\'
|
||||
pos += 1
|
||||
word += code[pos]
|
||||
pos += 1
|
||||
strings.append('"%s"' % word)
|
||||
pos += 1
|
||||
return strings
|
||||
|
||||
def detect(code):
|
||||
"""Detects if `code` is JavascriptObfuscator.com packed."""
|
||||
# prefer `is not` idiom, so that a true boolean is returned
|
||||
return (re.search(r'^var _0x[a-f0-9]+ ?\= ?\[', code) is not None)
|
||||
|
||||
def unpack(code):
|
||||
"""Unpacks JavascriptObfuscator.com packed code."""
|
||||
if detect(code):
|
||||
matches = re.search(r'var (_0x[a-f\d]+) ?\= ?\[(.*?)\];', code)
|
||||
if matches:
|
||||
variable = matches.group(1)
|
||||
dictionary = smartsplit(matches.group(2))
|
||||
code = code[len(matches.group(0)):]
|
||||
for key, value in enumerate(dictionary):
|
||||
code = code.replace(r'%s[%s]' % (variable, key), value)
|
||||
return code
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
#
|
||||
# deobfuscator for scripts messed up with myobfuscate.com
|
||||
# by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
#
|
||||
# written by Stefano Sanfilippo <a.little.coder@gmail.com>
|
||||
#
|
||||
# usage:
|
||||
#
|
||||
# if detect(some_string):
|
||||
# unpacked = unpack(some_string)
|
||||
#
|
||||
|
||||
# CAVEAT by Einar Lielmanis
|
||||
|
||||
#
|
||||
# You really don't want to obfuscate your scripts there: they're tracking
|
||||
# your unpackings, your script gets turned into something like this,
|
||||
# as of 2011-08-26:
|
||||
#
|
||||
# var _escape = 'your_script_escaped';
|
||||
# var _111 = document.createElement('script');
|
||||
# _111.src = 'http://api.www.myobfuscate.com/?getsrc=ok' +
|
||||
# '&ref=' + encodeURIComponent(document.referrer) +
|
||||
# '&url=' + encodeURIComponent(document.URL);
|
||||
# var 000 = document.getElementsByTagName('head')[0];
|
||||
# 000.appendChild(_111);
|
||||
# document.write(unescape(_escape));
|
||||
#
|
||||
|
||||
"""Deobfuscator for scripts messed up with MyObfuscate.com"""
|
||||
|
||||
import re
|
||||
import base64
|
||||
|
||||
# Python 2 retrocompatibility
|
||||
# pylint: disable=F0401
|
||||
# pylint: disable=E0611
|
||||
try:
|
||||
from urllib import unquote
|
||||
except ImportError:
|
||||
from urllib.parse import unquote
|
||||
|
||||
from jsbeautifier.unpackers import UnpackingError
|
||||
|
||||
PRIORITY = 1
|
||||
|
||||
CAVEAT = """//
|
||||
// Unpacker warning: be careful when using myobfuscate.com for your projects:
|
||||
// scripts obfuscated by the free online version call back home.
|
||||
//
|
||||
|
||||
"""
|
||||
|
||||
SIGNATURE = (r'["\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F'
|
||||
r'\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x61\x62\x63\x64\x65'
|
||||
r'\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\x73\x74\x75'
|
||||
r'\x76\x77\x78\x79\x7A\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x2B'
|
||||
r'\x2F\x3D","","\x63\x68\x61\x72\x41\x74","\x69\x6E\x64\x65\x78'
|
||||
r'\x4F\x66","\x66\x72\x6F\x6D\x43\x68\x61\x72\x43\x6F\x64\x65","'
|
||||
r'\x6C\x65\x6E\x67\x74\x68"]')
|
||||
|
||||
def detect(source):
|
||||
"""Detects MyObfuscate.com packer."""
|
||||
return SIGNATURE in source
|
||||
|
||||
def unpack(source):
|
||||
"""Unpacks js code packed with MyObfuscate.com"""
|
||||
if not detect(source):
|
||||
return source
|
||||
payload = unquote(_filter(source))
|
||||
match = re.search(r"^var _escape\='<script>(.*)<\/script>'",
|
||||
payload, re.DOTALL)
|
||||
polished = match.group(1) if match else source
|
||||
return CAVEAT + polished
|
||||
|
||||
def _filter(source):
|
||||
"""Extracts and decode payload (original file) from `source`"""
|
||||
try:
|
||||
varname = re.search(r'eval\(\w+\(\w+\((\w+)\)\)\);', source).group(1)
|
||||
reverse = re.search(r"var +%s *\= *'(.*)';" % varname, source).group(1)
|
||||
except AttributeError:
|
||||
raise UnpackingError('Malformed MyObfuscate data.')
|
||||
try:
|
||||
return base64.b64decode(reverse[::-1].encode('utf8')).decode('utf8')
|
||||
except TypeError:
|
||||
raise UnpackingError('MyObfuscate payload is not base64-encoded.')
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
#
|
||||
# Unpacker for Dean Edward's p.a.c.k.e.r, a part of javascript beautifier
|
||||
# by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
#
|
||||
# written by Stefano Sanfilippo <a.little.coder@gmail.com>
|
||||
#
|
||||
# usage:
|
||||
#
|
||||
# if detect(some_string):
|
||||
# unpacked = unpack(some_string)
|
||||
#
|
||||
|
||||
"""Unpacker for Dean Edward's p.a.c.k.e.r"""
|
||||
|
||||
import re
|
||||
import string
|
||||
from jsbeautifier.unpackers import UnpackingError
|
||||
|
||||
PRIORITY = 1
|
||||
|
||||
def detect(source):
|
||||
"""Detects whether `source` is P.A.C.K.E.R. coded."""
|
||||
return source.replace(' ', '').startswith('eval(function(p,a,c,k,e,')
|
||||
|
||||
def unpack(source):
|
||||
"""Unpacks P.A.C.K.E.R. packed js code."""
|
||||
payload, symtab, radix, count = _filterargs(source)
|
||||
|
||||
if count != len(symtab):
|
||||
raise UnpackingError('Malformed p.a.c.k.e.r. symtab.')
|
||||
|
||||
try:
|
||||
unbase = Unbaser(radix)
|
||||
except TypeError:
|
||||
raise UnpackingError('Unknown p.a.c.k.e.r. encoding.')
|
||||
|
||||
def lookup(match):
|
||||
"""Look up symbols in the synthetic symtab."""
|
||||
word = match.group(0)
|
||||
return symtab[unbase(word)] or word
|
||||
|
||||
source = re.sub(r'\b\w+\b', lookup, payload)
|
||||
return _replacestrings(source)
|
||||
|
||||
def _filterargs(source):
|
||||
"""Juice from a source file the four args needed by decoder."""
|
||||
juicers = [ (r"}\('(.*)', *(\d+), *(\d+), *'(.*)'\.split\('\|'\), *(\d+), *(.*)\)\)"),
|
||||
(r"}\('(.*)', *(\d+), *(\d+), *'(.*)'\.split\('\|'\)"),
|
||||
]
|
||||
for juicer in juicers:
|
||||
args = re.search(juicer, source, re.DOTALL)
|
||||
if args:
|
||||
a = args.groups()
|
||||
try:
|
||||
return a[0], a[3].split('|'), int(a[1]), int(a[2])
|
||||
except ValueError:
|
||||
raise UnpackingError('Corrupted p.a.c.k.e.r. data.')
|
||||
|
||||
# could not find a satisfying regex
|
||||
raise UnpackingError('Could not make sense of p.a.c.k.e.r data (unexpected code structure)')
|
||||
|
||||
|
||||
|
||||
def _replacestrings(source):
|
||||
"""Strip string lookup table (list) and replace values in source."""
|
||||
match = re.search(r'var *(_\w+)\=\["(.*?)"\];', source, re.DOTALL)
|
||||
|
||||
if match:
|
||||
varname, strings = match.groups()
|
||||
startpoint = len(match.group(0))
|
||||
lookup = strings.split('","')
|
||||
variable = '%s[%%d]' % varname
|
||||
for index, value in enumerate(lookup):
|
||||
source = source.replace(variable % index, '"%s"' % value)
|
||||
return source[startpoint:]
|
||||
return source
|
||||
|
||||
|
||||
class Unbaser(object):
|
||||
"""Functor for a given base. Will efficiently convert
|
||||
strings to natural numbers."""
|
||||
ALPHABET = {
|
||||
62 : '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||
95 : (' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
'[\]^_`abcdefghijklmnopqrstuvwxyz{|}~')
|
||||
}
|
||||
|
||||
def __init__(self, base):
|
||||
self.base = base
|
||||
|
||||
# If base can be handled by int() builtin, let it do it for us
|
||||
if 2 <= base <= 36:
|
||||
self.unbase = lambda string: int(string, base)
|
||||
else:
|
||||
# Build conversion dictionary cache
|
||||
try:
|
||||
self.dictionary = dict((cipher, index) for
|
||||
index, cipher in enumerate(self.ALPHABET[base]))
|
||||
except KeyError:
|
||||
raise TypeError('Unsupported base encoding.')
|
||||
|
||||
self.unbase = self._dictunbaser
|
||||
|
||||
def __call__(self, string):
|
||||
return self.unbase(string)
|
||||
|
||||
def _dictunbaser(self, string):
|
||||
"""Decodes a value to an integer."""
|
||||
ret = 0
|
||||
for index, cipher in enumerate(string[::-1]):
|
||||
ret += (self.base ** index) * self.dictionary[cipher]
|
||||
return ret
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
# Empty file :)
|
||||
# pylint: disable=C0111
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,65 @@
|
|||
//
|
||||
// Unpacker warning: be careful when using myobfuscate.com for your projects:
|
||||
// scripts obfuscated by the free online version call back home.
|
||||
//
|
||||
|
||||
//
|
||||
// Unpacker for Dean Edward's p.a.c.k.e.r, a part of javascript beautifier
|
||||
// written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
//
|
||||
// Coincidentally, it can defeat a couple of other eval-based compressors.
|
||||
//
|
||||
// usage:
|
||||
//
|
||||
// if (P_A_C_K_E_R.detect(some_string)) {
|
||||
// var unpacked = P_A_C_K_E_R.unpack(some_string);
|
||||
// }
|
||||
//
|
||||
//
|
||||
|
||||
var P_A_C_K_E_R = {
|
||||
detect: function (str) {
|
||||
return P_A_C_K_E_R._starts_with(str.toLowerCase().replace(/ +/g, ''), 'eval(function(') ||
|
||||
P_A_C_K_E_R._starts_with(str.toLowerCase().replace(/ +/g, ''), 'eval((function(') ;
|
||||
},
|
||||
|
||||
unpack: function (str) {
|
||||
var unpacked_source = '';
|
||||
if (P_A_C_K_E_R.detect(str)) {
|
||||
try {
|
||||
eval('unpacked_source = ' + str.substring(4) + ';')
|
||||
if (typeof unpacked_source == 'string' && unpacked_source) {
|
||||
str = unpacked_source;
|
||||
}
|
||||
} catch (error) {
|
||||
// well, it failed. we'll just return the original, instead of crashing on user.
|
||||
}
|
||||
}
|
||||
return str;
|
||||
},
|
||||
|
||||
_starts_with: function (str, what) {
|
||||
return str.substr(0, what.length) === what;
|
||||
},
|
||||
|
||||
run_tests: function (sanity_test) {
|
||||
var t = sanity_test || new SanityTest();
|
||||
t.test_function(P_A_C_K_E_R.detect, "P_A_C_K_E_R.detect");
|
||||
t.expect('', false);
|
||||
t.expect('var a = b', false);
|
||||
t.expect('eval(function(p,a,c,k,e,r', true);
|
||||
t.expect('eval ( function(p, a, c, k, e, r', true);
|
||||
|
||||
t.test_function(P_A_C_K_E_R.unpack, 'P_A_C_K_E_R.unpack');
|
||||
t.expect("eval(function(p,a,c,k,e,r){e=String;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('0 2=1',3,3,'var||a'.split('|'),0,{}))",
|
||||
'var a=1');
|
||||
|
||||
var starts_with_a = function(what) { return P_A_C_K_E_R._starts_with(what, 'a'); }
|
||||
t.test_function(starts_with_a, "P_A_C_K_E_R._starts_with(?, a)");
|
||||
t.expect('abc', true);
|
||||
t.expect('bcd', false);
|
||||
t.expect('a', true);
|
||||
t.expect('', false);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('9 H=(j["Y"]["n"]("1h")!=-1)?s:v;9 I=(j["Y"]["w"]()["n"]("1i")!=-1)?s:v;9 J=(j["K"]["n"]("1j")!=-1)?s:v;p Z(){9 a;9 b;9 c;y{b=o z("l.l.7");a=b.P("$Q")}A(c){};i(!a){y{b=o z("l.l.6");a="R 6,0,21,0";b["1k"]="1l";a=b.P("$Q")}A(c){}};i(!a){y{b=o z("l.l.3");a=b.P("$Q")}A(c){}};i(!a){y{b=o z("l.l.3");a="R 3,0,18,0"}A(c){}};i(!a){y{b=o z("l.l");a="R 2,0,0,11"}A(c){a=-1}};m a};p 10(){9 a=-1;i(j["t"]!=12&&j["t"]["13"]>0){i(j["t"]["L M 2.0"]||j["t"]["L M"]){9 b=j["t"]["L M 2.0"]?" 2.0":"";9 c=j["t"]["L M"+b]["1m"];9 d=c["B"](" ");9 e=d[2]["B"](".");9 f=e[0];9 g=e[1];9 h=d[3];i(h==""){h=d[4]};i(h[0]=="d"){h=h["S"](1)}k{i(h[0]=="r"){h=h["S"](1);i(h["n"]("d")>0){h=h["S"](0,h["n"]("d"))}}};9 a=f+"."+g+"."+h}}k{i(j["K"]["w"]()["n"]("T/2.6")!=-1){a=4}k{i(j["K"]["w"]()["n"]("T/2.5")!=-1){a=3}k{i(j["K"]["w"]()["n"]("T")!=-1){a=2}k{i(H&&I&&!J){a=Z()}}}}};m a};p 1n(a,b,c){C=10();i(C==-1){m v}k{i(C!=0){i(H&&I&&!J){14=C["B"](" ");15=14[1];D=15["B"](",")}k{D=C["B"](".")};9 d=D[0];9 e=D[1];9 f=D[2];i(d>E(a)){m s}k{i(d==E(a)){i(e>E(b)){m s}k{i(e==E(b)){i(f>=E(c)){m s}}}}};m v}}};p 16(a,b){i(a["n"]("?")!=-1){m a["1o"](/\\?/,b+"?")}k{m a+b}};p U(a,b,c){9 d="";i(H&&I&&!J){d+="<17 ";N(9 e V a){d+=e+"=""+a[e]+"" "};d+=">";N(9 e V b){d+="<1p 19=""+e+"" 1q=""+b[e]+"" /> "};d+="</17>"}k{d+="<1a ";N(9 e V c){d+=e+"=""+c[e]+"" "};d+="> </1a>"};1r["1s"](d)};p 1t(){9 a=W(1b,".1u","1c","1d:1v-1w-1x-1y-1e","1z/x-1A-1B");U(a["u"],a["F"],a["q"])};p 1C(){9 a=W(1b,".1D","X","1d:1E-1F-1G-1H-1e",12);U(a["u"],a["F"],a["q"])};p W(a,b,c,d,e){9 f=o O();f["q"]=o O();f["F"]=o O();f["u"]=o O();N(9 g=0;g<a["13"];g=g+2){9 h=a[g]["w"]();1I(h){8"1f":G;8"1J":f["q"][a[g]]=a[g+1];G;8"X":;8"1c":a[g+1]=16(a[g+1],b);f["q"]["X"]=a[g+1];f["F"][c]=a[g+1];G;8"1K":;8"1L":;8"1M":;8"1N":;8"1O":;8"1P":;8"1Q":;8"1R":;8"1S":;8"1T":;8"1U":;8"1V":;8"1W":;8"1X":;8"1Y":;8"1Z":;8"20":;8"22":;8"23":;8"24":;8"25":;8"26":;8"27":;8"28":;8"29":;8"2a":;8"2b":;8"2c":;8"2d":;8"2e":;8"2f":;8"2g":;8"2h":;8"2i":;8"2j":;8"2k":;8"2l":;8"1g":;8"2m":;8"2n":f["u"][a[g]]=a[g+1];G;8"2o":;8"2p":;8"2q":;8"2r":;8"2s":;8"2t":;8"2u":;8"2v":;8"19":;8"2w":f["q"][a[g]]=f["u"][a[g]]=a[g+1];G;2x:f["q"][a[g]]=f["F"][a[g]]=a[g+1]}};f["u"]["1f"]=d;i(e){f["q"]["1g"]=e};m f};',62,158,'||||||||case|var|||||||||if|navigator|else|ShockwaveFlash|return|indexOf|new|function|embedAttrs||true|plugins|objAttrs|false|toLowerCase||try|ActiveXObject|catch|split|versionStr|versionArray|parseFloat|params|break|isIE|isWin|isOpera|userAgent|Shockwave|Flash|for|Object|GetVariable|version|WIN|substring|webtv|AC_Generateobj|in|AC_GetArgs|src|appVersion|ControlVersion|GetSwfVer||null|length|tempArray|tempString|AC_AddExtension|object||name|embed|arguments|movie|clsid|444553540000|classid|type|MSIE|win|Opera|AllowScriptAccess|always|description|DetectFlashVer|replace|param|value|document|write|AC_FL_RunContent|swf|d27cdb6e|ae6d|11cf|96b8|application|shockwave|flash|AC_SW_RunContent|dcr|166B1BCA|3F9C|11CF|8075|switch|pluginspage|onafterupdate|onbeforeupdate|onblur|oncellchange|onclick|ondblclick|ondrag|ondragend|ondragenter|ondragleave|ondragover|ondrop|onfinish|onfocus|onhelp|onmousedown|onmouseup||onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup|onload|onlosecapture|onpropertychange|onreadystatechange|onrowsdelete|onrowenter|onrowexit|onrowsinserted|onstart|onscroll|onbeforeeditfocus|onactivate|onbeforedeactivate|ondeactivate|codebase|id|width|height|align|vspace|hspace|class|title|accesskey|tabindex|default'.split('|'),0,{}))
|
||||
|
|
@ -0,0 +1 @@
|
|||
var isIE=(navigator["appVersion"]["indexOf"]("MSIE")!=-1)?true:false;var isWin=(navigator["appVersion"]["toLowerCase"]()["indexOf"]("win")!=-1)?true:false;var isOpera=(navigator["userAgent"]["indexOf"]("Opera")!=-1)?true:false;function ControlVersion(){var a;var b;var c;try{b=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");a=b.GetVariable("$version")}catch(c){};if(!a){try{b=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");a="WIN 6,0,21,0";b["AllowScriptAccess"]="always";a=b.GetVariable("$version")}catch(c){}};if(!a){try{b=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");a=b.GetVariable("$version")}catch(c){}};if(!a){try{b=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");a="WIN 3,0,18,0"}catch(c){}};if(!a){try{b=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");a="WIN 2,0,0,11"}catch(c){a=-1}};return a};function GetSwfVer(){var a=-1;if(navigator["plugins"]!=null&&navigator["plugins"]["length"]>0){if(navigator["plugins"]["Shockwave Flash 2.0"]||navigator["plugins"]["Shockwave Flash"]){var b=navigator["plugins"]["Shockwave Flash 2.0"]?" 2.0":"";var c=navigator["plugins"]["Shockwave Flash"+b]["description"];var d=c["split"](" ");var e=d[2]["split"](".");var f=e[0];var g=e[1];var h=d[3];if(h==""){h=d[4]};if(h[0]=="d"){h=h["substring"](1)}else{if(h[0]=="r"){h=h["substring"](1);if(h["indexOf"]("d")>0){h=h["substring"](0,h["indexOf"]("d"))}}};var a=f+"."+g+"."+h}}else{if(navigator["userAgent"]["toLowerCase"]()["indexOf"]("webtv/2.6")!=-1){a=4}else{if(navigator["userAgent"]["toLowerCase"]()["indexOf"]("webtv/2.5")!=-1){a=3}else{if(navigator["userAgent"]["toLowerCase"]()["indexOf"]("webtv")!=-1){a=2}else{if(isIE&&isWin&&!isOpera){a=ControlVersion()}}}}};return a};function DetectFlashVer(a,b,c){versionStr=GetSwfVer();if(versionStr==-1){return false}else{if(versionStr!=0){if(isIE&&isWin&&!isOpera){tempArray=versionStr["split"](" ");tempString=tempArray[1];versionArray=tempString["split"](",")}else{versionArray=versionStr["split"](".")};var d=versionArray[0];var e=versionArray[1];var f=versionArray[2];if(d>parseFloat(a)){return true}else{if(d==parseFloat(a)){if(e>parseFloat(b)){return true}else{if(e==parseFloat(b)){if(f>=parseFloat(c)){return true}}}}};return false}}};function AC_AddExtension(a,b){if(a["indexOf"]("?")!=-1){return a["replace"](/\?/,b+"?")}else{return a+b}};function AC_Generateobj(a,b,c){var d="";if(isIE&&isWin&&!isOpera){d+="<object ";for(var e in a){d+=e+"=""+a[e]+"" "};d+=">";for(var e in b){d+="<param name=""+e+"" value=""+b[e]+"" /> "};d+="</object>"}else{d+="<embed ";for(var e in c){d+=e+"=""+c[e]+"" "};d+="> </embed>"};document["write"](d)};function AC_FL_RunContent(){var a=AC_GetArgs(arguments,".swf","movie","clsid:d27cdb6e-ae6d-11cf-96b8-444553540000","application/x-shockwave-flash");AC_Generateobj(a["objAttrs"],a["params"],a["embedAttrs"])};function AC_SW_RunContent(){var a=AC_GetArgs(arguments,".dcr","src","clsid:166B1BCA-3F9C-11CF-8075-444553540000",null);AC_Generateobj(a["objAttrs"],a["params"],a["embedAttrs"])};function AC_GetArgs(a,b,c,d,e){var f=new Object();f["embedAttrs"]=new Object();f["params"]=new Object();f["objAttrs"]=new Object();for(var g=0;g<a["length"];g=g+2){var h=a[g]["toLowerCase"]();switch(h){case"classid":break;case"pluginspage":f["embedAttrs"][a[g]]=a[g+1];break;case"src":;case"movie":a[g+1]=AC_AddExtension(a[g+1],b);f["embedAttrs"]["src"]=a[g+1];f["params"][c]=a[g+1];break;case"onafterupdate":;case"onbeforeupdate":;case"onblur":;case"oncellchange":;case"onclick":;case"ondblclick":;case"ondrag":;case"ondragend":;case"ondragenter":;case"ondragleave":;case"ondragover":;case"ondrop":;case"onfinish":;case"onfocus":;case"onhelp":;case"onmousedown":;case"onmouseup":;case"onmouseover":;case"onmousemove":;case"onmouseout":;case"onkeypress":;case"onkeydown":;case"onkeyup":;case"onload":;case"onlosecapture":;case"onpropertychange":;case"onreadystatechange":;case"onrowsdelete":;case"onrowenter":;case"onrowexit":;case"onrowsinserted":;case"onstart":;case"onscroll":;case"onbeforeeditfocus":;case"onactivate":;case"onbeforedeactivate":;case"ondeactivate":;case"type":;case"codebase":;case"id":f["objAttrs"][a[g]]=a[g+1];break;case"width":;case"height":;case"align":;case"vspace":;case"hspace":;case"class":;case"title":;case"accesskey":;case"name":;case"tabindex":f["embedAttrs"][a[g]]=f["objAttrs"][a[g]]=a[g+1];break;default:f["embedAttrs"][a[g]]=f["params"][a[g]]=a[g+1]}};f["objAttrs"]["classid"]=d;if(e){f["embedAttrs"]["type"]=e};return f};
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
#
|
||||
# written by Stefano Sanfilippo <a.little.coder@gmail.com>
|
||||
#
|
||||
|
||||
"""Tests for JavaScriptObfuscator unpacker."""
|
||||
|
||||
import unittest
|
||||
from jsbeautifier.unpackers.javascriptobfuscator import (
|
||||
unpack, detect, smartsplit)
|
||||
|
||||
# pylint: disable=R0904
|
||||
class TestJavascriptObfuscator(unittest.TestCase):
|
||||
"""JavascriptObfuscator.com test case."""
|
||||
def test_smartsplit(self):
|
||||
"""Test smartsplit() function."""
|
||||
split = smartsplit
|
||||
equals = lambda data, result: self.assertEqual(split(data), result)
|
||||
|
||||
equals('', [])
|
||||
equals('"a", "b"', ['"a"', '"b"'])
|
||||
equals('"aaa","bbbb"', ['"aaa"', '"bbbb"'])
|
||||
equals('"a", "b\\\""', ['"a"', '"b\\\""'])
|
||||
|
||||
def test_detect(self):
|
||||
"""Test detect() function."""
|
||||
positive = lambda source: self.assertTrue(detect(source))
|
||||
negative = lambda source: self.assertFalse(detect(source))
|
||||
|
||||
negative('')
|
||||
negative('abcd')
|
||||
negative('var _0xaaaa')
|
||||
positive('var _0xaaaa = ["a", "b"]')
|
||||
positive('var _0xaaaa=["a", "b"]')
|
||||
positive('var _0x1234=["a","b"]')
|
||||
|
||||
def test_unpack(self):
|
||||
"""Test unpack() function."""
|
||||
decodeto = lambda ob, original: self.assertEqual(unpack(ob), original)
|
||||
|
||||
decodeto('var _0x8df3=[];var a=10;', 'var a=10;')
|
||||
decodeto('var _0xb2a7=["\x74\x27\x65\x73\x74"];var i;for(i=0;i<10;++i)'
|
||||
'{alert(_0xb2a7[0]);} ;', 'var i;for(i=0;i<10;++i){alert'
|
||||
'("t\'est");} ;')
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
#
|
||||
# written by Stefano Sanfilippo <a.little.coder@gmail.com>
|
||||
#
|
||||
|
||||
"""Tests for MyObfuscate unpacker."""
|
||||
|
||||
import unittest
|
||||
import os
|
||||
from jsbeautifier.unpackers.myobfuscate import detect, unpack
|
||||
from jsbeautifier.unpackers.tests import __path__ as path
|
||||
|
||||
INPUT = os.path.join(path[0], 'test-myobfuscate-input.js')
|
||||
OUTPUT = os.path.join(path[0], 'test-myobfuscate-output.js')
|
||||
|
||||
# pylint: disable=R0904
|
||||
class TestMyObfuscate(unittest.TestCase):
|
||||
# pylint: disable=C0103
|
||||
"""MyObfuscate obfuscator testcase."""
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
"""Load source files (encoded and decoded version) for tests."""
|
||||
with open(INPUT, 'r') as data:
|
||||
cls.input = data.read()
|
||||
with open(OUTPUT, 'r') as data:
|
||||
cls.output = data.read()
|
||||
|
||||
def test_detect(self):
|
||||
"""Test detect() function."""
|
||||
detected = lambda source: self.assertTrue(detect(source))
|
||||
|
||||
detected(self.input)
|
||||
|
||||
def test_unpack(self):
|
||||
"""Test unpack() function."""
|
||||
check = lambda inp, out: self.assertEqual(unpack(inp), out)
|
||||
|
||||
check(self.input, self.output)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#
|
||||
# written by Stefano Sanfilippo <a.little.coder@gmail.com>
|
||||
#
|
||||
|
||||
"""Tests for P.A.C.K.E.R. unpacker."""
|
||||
|
||||
import unittest
|
||||
from jsbeautifier.unpackers.packer import detect, unpack
|
||||
|
||||
# pylint: disable=R0904
|
||||
class TestPacker(unittest.TestCase):
|
||||
"""P.A.C.K.E.R. testcase."""
|
||||
def test_detect(self):
|
||||
"""Test detect() function."""
|
||||
positive = lambda source: self.assertTrue(detect(source))
|
||||
negative = lambda source: self.assertFalse(detect(source))
|
||||
|
||||
negative('')
|
||||
negative('var a = b')
|
||||
positive('eval(function(p,a,c,k,e,r')
|
||||
positive('eval ( function(p, a, c, k, e, r')
|
||||
|
||||
def test_unpack(self):
|
||||
"""Test unpack() function."""
|
||||
check = lambda inp, out: self.assertEqual(unpack(inp), out)
|
||||
|
||||
check("eval(function(p,a,c,k,e,r){e=String;if(!''.replace(/^/,String)"
|
||||
"){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e="
|
||||
"function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace("
|
||||
"new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('0 2=1',"
|
||||
"62,3,'var||a'.split('|'),0,{}))", 'var a=1')
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#
|
||||
# written by Stefano Sanfilippo <a.little.coder@gmail.com>
|
||||
#
|
||||
|
||||
"""Tests for urlencoded unpacker."""
|
||||
|
||||
import unittest
|
||||
|
||||
from jsbeautifier.unpackers.urlencode import detect, unpack
|
||||
|
||||
# pylint: disable=R0904
|
||||
class TestUrlencode(unittest.TestCase):
|
||||
"""urlencode test case."""
|
||||
def test_detect(self):
|
||||
"""Test detect() function."""
|
||||
encoded = lambda source: self.assertTrue(detect(source))
|
||||
unencoded = lambda source: self.assertFalse(detect(source))
|
||||
|
||||
unencoded('')
|
||||
unencoded('var a = b')
|
||||
encoded('var%20a+=+b')
|
||||
encoded('var%20a=b')
|
||||
encoded('var%20%21%22')
|
||||
|
||||
def test_unpack(self):
|
||||
"""Test unpack function."""
|
||||
equals = lambda source, result: self.assertEqual(unpack(source), result)
|
||||
|
||||
equals('', '')
|
||||
equals('abcd', 'abcd')
|
||||
equals('var a = b', 'var a = b')
|
||||
equals('var%20a=b', 'var a=b')
|
||||
equals('var%20a+=+b', 'var a = b')
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#
|
||||
# Trivial bookmarklet/escaped script detector for the javascript beautifier
|
||||
# written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
# rewritten in Python by Stefano Sanfilippo <a.little.coder@gmail.com>
|
||||
#
|
||||
# Will always return valid javascript: if `detect()` is false, `code` is
|
||||
# returned, unmodified.
|
||||
#
|
||||
# usage:
|
||||
#
|
||||
# some_string = urlencode.unpack(some_string)
|
||||
#
|
||||
|
||||
"""Bookmarklet/escaped script unpacker."""
|
||||
|
||||
# Python 2 retrocompatibility
|
||||
# pylint: disable=F0401
|
||||
# pylint: disable=E0611
|
||||
try:
|
||||
from urllib import unquote_plus
|
||||
except ImportError:
|
||||
from urllib.parse import unquote_plus
|
||||
|
||||
PRIORITY = 0
|
||||
|
||||
def detect(code):
|
||||
"""Detects if a scriptlet is urlencoded."""
|
||||
# the fact that script doesn't contain any space, but has %20 instead
|
||||
# should be sufficient check for now.
|
||||
return ' ' not in code and ('%20' in code or code.count('%') > 3)
|
||||
|
||||
def unpack(code):
|
||||
"""URL decode `code` source string."""
|
||||
return unquote_plus(code) if detect(code) else code
|
||||
19
gaia/distros/spark/apps/customizer/components/js-beautify/python/setup.py
Executable file
19
gaia/distros/spark/apps/customizer/components/js-beautify/python/setup.py
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from distutils.core import setup
|
||||
from jsbeautifier.__version__ import __version__
|
||||
|
||||
setup(name='jsbeautifier',
|
||||
version=__version__,
|
||||
description='JavaScript unobfuscator and beautifier.',
|
||||
long_description=('Beautify, unpack or deobfuscate JavaScript. '
|
||||
'Handles popular online obfuscators.'),
|
||||
author='Einar Lielmanis, Stefano Sanfilippo et al.',
|
||||
author_email='einar@jsbeautifier.org',
|
||||
url='http://jsbeautifier.org',
|
||||
scripts=['js-beautify'],
|
||||
packages=['jsbeautifier', 'jsbeautifier.tests',
|
||||
'jsbeautifier.unpackers', 'jsbeautifier.unpackers.tests'],
|
||||
install_requires=["six>=1.6.1"],
|
||||
license='MIT',
|
||||
)
|
||||
Loading…
Reference in a new issue