pax_global_header00006660000000000000000000000064147562745140014531gustar00rootroot0000000000000052 comment=4ca6fba6b989dcf20700fbdc135d6c67f1743939 python-jsbeautifier-1.15.3/000077500000000000000000000000001475627451400156135ustar00rootroot00000000000000python-jsbeautifier-1.15.3/MANIFEST.in000066400000000000000000000000551475627451400173510ustar00rootroot00000000000000include js-beautify include js-beautify-test python-jsbeautifier-1.15.3/PKG-INFO000066400000000000000000000004671475627451400167170ustar00rootroot00000000000000Metadata-Version: 2.1 Name: jsbeautifier Version: 1.15.3 Summary: JavaScript unobfuscator and beautifier. Home-page: https://beautifier.io Author: Liam Newman, Einar Lielmanis, et al. Author-email: team@beautifier.io License: MIT Beautify, unpack or deobfuscate JavaScript. Handles popular online obfuscators. python-jsbeautifier-1.15.3/js-beautify-test000077500000000000000000000002151475627451400207360ustar00rootroot00000000000000#! /bin/sh # # Test suite launcher # if [ -z $PYTHON ]; then env python js-beautify-test.py else env $PYTHON js-beautify-test.py fi python-jsbeautifier-1.15.3/jsbeautifier.egg-info/000077500000000000000000000000001475627451400217615ustar00rootroot00000000000000python-jsbeautifier-1.15.3/jsbeautifier.egg-info/PKG-INFO000066400000000000000000000004671475627451400230650ustar00rootroot00000000000000Metadata-Version: 2.1 Name: jsbeautifier Version: 1.15.3 Summary: JavaScript unobfuscator and beautifier. Home-page: https://beautifier.io Author: Liam Newman, Einar Lielmanis, et al. Author-email: team@beautifier.io License: MIT Beautify, unpack or deobfuscate JavaScript. Handles popular online obfuscators. python-jsbeautifier-1.15.3/jsbeautifier.egg-info/SOURCES.txt000066400000000000000000000027231475627451400236510ustar00rootroot00000000000000MANIFEST.in js-beautify-test pyproject.toml setup.py jsbeautifier/__init__.py jsbeautifier/__version__.py jsbeautifier.egg-info/PKG-INFO jsbeautifier.egg-info/SOURCES.txt jsbeautifier.egg-info/dependency_links.txt jsbeautifier.egg-info/entry_points.txt jsbeautifier.egg-info/requires.txt jsbeautifier.egg-info/top_level.txt jsbeautifier/cli/__init__.py jsbeautifier/core/__init__.py jsbeautifier/core/directives.py jsbeautifier/core/inputscanner.py jsbeautifier/core/options.py jsbeautifier/core/output.py jsbeautifier/core/pattern.py jsbeautifier/core/templatablepattern.py jsbeautifier/core/token.py jsbeautifier/core/tokenizer.py jsbeautifier/core/tokenstream.py jsbeautifier/core/whitespacepattern.py jsbeautifier/javascript/__init__.py jsbeautifier/javascript/acorn.py jsbeautifier/javascript/beautifier.py jsbeautifier/javascript/options.py jsbeautifier/javascript/tokenizer.py jsbeautifier/tests/__init__.py jsbeautifier/tests/testindentation.py jsbeautifier/tests/generated/__init__.py jsbeautifier/tests/generated/tests.py jsbeautifier/unpackers/__init__.py jsbeautifier/unpackers/evalbased.py jsbeautifier/unpackers/javascriptobfuscator.py jsbeautifier/unpackers/myobfuscate.py jsbeautifier/unpackers/packer.py jsbeautifier/unpackers/urlencode.py jsbeautifier/unpackers/tests/__init__.py jsbeautifier/unpackers/tests/testjavascriptobfuscator.py jsbeautifier/unpackers/tests/testmyobfuscate.py jsbeautifier/unpackers/tests/testpacker.py jsbeautifier/unpackers/tests/testurlencode.pypython-jsbeautifier-1.15.3/jsbeautifier.egg-info/dependency_links.txt000066400000000000000000000000011475627451400260270ustar00rootroot00000000000000 python-jsbeautifier-1.15.3/jsbeautifier.egg-info/entry_points.txt000066400000000000000000000000621475627451400252550ustar00rootroot00000000000000[console_scripts] js-beautify = jsbeautifier:main python-jsbeautifier-1.15.3/jsbeautifier.egg-info/requires.txt000066400000000000000000000000411475627451400243540ustar00rootroot00000000000000six>=1.13.0 editorconfig>=0.12.2 python-jsbeautifier-1.15.3/jsbeautifier.egg-info/top_level.txt000066400000000000000000000000151475627451400245070ustar00rootroot00000000000000jsbeautifier python-jsbeautifier-1.15.3/jsbeautifier/000077500000000000000000000000001475627451400202675ustar00rootroot00000000000000python-jsbeautifier-1.15.3/jsbeautifier/__init__.py000066400000000000000000000261231475627451400224040ustar00rootroot00000000000000from __future__ import print_function import sys import os import platform import io import getopt import re import string import errno import copy import glob from jsbeautifier.__version__ import __version__ from jsbeautifier.cli import * from jsbeautifier.javascript.options import BeautifierOptions from jsbeautifier.javascript.beautifier import Beautifier # # The MIT License (MIT) # Copyright (c) 2007-2018 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. # # Originally written by Einar Lielmanis et al., # Conversion to python by Einar Lielmanis, einar@beautifier.io, # Parsing improvement for brace-less and semicolon-less statements # by Liam Newman # Python is not my native language, feel free to push things around. # # Use either from command line (script displays its usage when run # without any parameters), # # # or, alternatively, use it as a module: # # import jsbeautifier # res = jsbeautifier.beautify('your javascript string') # res = jsbeautifier.beautify_file('some_file.js') # # you may specify some options: # # opts = jsbeautifier.default_options() # opts.indent_size = 2 # res = jsbeautifier.beautify('some javascript', opts) # # # Here are the available options: (read source) __all__ = [ "default_options", "beautify", "beautify_file", "usage", "main", ] def default_options(): return BeautifierOptions() def beautify(string, opts=default_options()): b = Beautifier() return b.beautify(string, opts) def beautify_file(file_name, opts=default_options()): return process_file(file_name, opts, beautify) def usage(stream=sys.stdout): print( "jsbeautifier.py@" + __version__ + """ Javascript beautifier (https://beautifier.io/) Usage: jsbeautifier.py [options] can be "-", which means stdin. Input options: -i, --stdin Read input from stdin Output options: -s, --indent-size=NUMBER Indentation size. (default 4). -c, --indent-char=CHAR Character to indent with. (default space). -e, --eol=STRING Character(s) to use as line terminators. (default first newline in file, otherwise "\\n") -t, --indent-with-tabs Indent with tabs, overrides -s and -c -d, --disable-preserve-newlines Do not preserve existing line breaks. -P, --space-in-paren Add padding spaces within paren, ie. f( a, b ) -E, --space-in-empty-paren Add a single space inside empty paren, ie. f( ) -j, --jslint-happy More jslint-compatible output -a, --space-after-anon-function Add a space before an anonymous function's parens, ie. function () --space-after-named-function Add a space before a named function's parens, i.e. function example () -b, --brace-style=collapse Brace style (collapse, expand, end-expand, none)(,preserve-inline) -k, --keep-array-indentation Keep array indentation. --quiet Suppress info about a file if nothing was changed. -r, --replace Write output in-place, replacing input -o, --outfile=FILE Specify a file to output to (default stdout) -f, --keep-function-indentation Do not re-indent function bodies defined in var lines. -x, --unescape-strings Decode printable chars encoded in \\xNN notation. -X, --e4x Pass E4X xml literals through untouched -C, --comma-first Put commas at the beginning of new line instead of end. -m, --max-preserve-newlines=NUMBER Number of line-breaks to be preserved in one chunk (default 10) -O, --operator-position=STRING Set operator position (before-newline, after-newline, preserve-newline) -w, --wrap-line-length Attempt to wrap line when it exceeds this length. NOTE: Line continues until next wrap point is found. -n, --end-with-newline End output with newline --indent-empty-lines Keep indentation on empty lines --templating List of templating languages (auto,none,django,erb,handlebars,php,smarty,angular) ["auto"] auto = none in JavaScript, all in html --editorconfig Enable setting configuration from EditorConfig Rarely needed options: --eval-code evaluate code if a JS interpreter is installed. May be useful with some obfuscated script but poses a potential security issue. -l, --indent-level=NUMBER Initial indentation level. (default 0). -h, --help, --usage Prints this help statement. -v, --version Show the version """, file=stream, ) if stream == sys.stderr: return 1 else: return 0 def main(): argv = sys.argv[1:] try: opts, args = getopt.getopt( argv, "f:s:c:e:o:rdEPjab:kil:xhtvXnCO:w:m:", [ "brace-style=", "comma-first", "disable-preserve-newlines", "e4x", "editorconfig", "end-with-newline", "eol=", "eval-code", "file=", "help", "indent-char=", "indent-empty-lines", "indent-level=", "indent-size=", "indent-with-tabs", "jslint-happy", "keep-array-indentation", "keep-function-indentation", "max-preserve-newlines=", "operator-position=", "outfile=", "quiet", "replace", "space-after-anon-function", "space-after-named-function", "space-in-empty-paren", "space-in-paren", "stdin", "templating=", "unescape-strings", "usage", "version", "wrap-line-length", ], ) except getopt.GetoptError as ex: print(ex, file=sys.stderr) return usage(sys.stderr) js_options = default_options() filepath_params = [] filepath_params.extend(args) outfile_param = "stdout" replace = False for opt, arg in opts: if opt in ("--file", "-f"): filepath_params.append(arg) elif opt in ("--keep-array-indentation", "-k"): js_options.keep_array_indentation = True elif opt in ("--keep-function-indentation",): js_options.keep_function_indentation = True elif opt in ("--outfile", "-o"): outfile_param = arg elif opt in ("--replace", "-r"): replace = True elif opt in ("--indent-size", "-s"): js_options.indent_size = int(arg) elif opt in ("--indent-char", "-c"): js_options.indent_char = arg elif opt in ("--eol", "-e"): js_options.eol = arg elif opt in ("--indent-with-tabs", "-t"): js_options.indent_with_tabs = True elif opt in ("--disable-preserve-newlines", "-d"): js_options.preserve_newlines = False elif opt in ("--max-preserve-newlines", "-m"): js_options.max_preserve_newlines = int(arg) elif opt in ("--space-in-paren", "-P"): js_options.space_in_paren = True elif opt in ("--space-in-empty-paren", "-E"): js_options.space_in_empty_paren = True elif opt in ("--jslint-happy", "-j"): js_options.jslint_happy = True elif opt in ("--space-after-anon-function", "-a"): js_options.space_after_anon_function = True elif opt in ("--space-after-named-function",): js_options.space_after_named_function = True elif opt in ("--eval-code",): js_options.eval_code = True elif opt in ("--quiet",): js_options.keep_quiet = True elif opt in ("--brace-style", "-b"): js_options.brace_style = arg elif opt in ("--unescape-strings", "-x"): js_options.unescape_strings = True elif opt in ("--e4x", "-X"): js_options.e4x = True elif opt in ("--end-with-newline", "-n"): js_options.end_with_newline = True elif opt in ("--comma-first", "-C"): js_options.comma_first = True elif opt in ("--operator-position", "-O"): js_options.operator_position = arg elif opt in ("--wrap-line-length ", "-w"): js_options.wrap_line_length = int(arg) elif opt in ("--indent-empty-lines",): js_options.indent_empty_lines = True elif opt in ("--templating",): js_options.templating = arg.split(",") elif opt in ("--stdin", "-i"): # stdin is the default if no files are passed filepath_params = [] elif opt in ("--editorconfig",): js_options.editorconfig = True elif opt in ("--version", "-v"): return print(__version__) elif opt in ("--help", "--usage", "-h"): return usage() try: filepaths, replace = get_filepaths_from_params(filepath_params, replace) for filepath in filepaths: if not replace: outfile = outfile_param else: outfile = filepath js_options = integrate_editorconfig_options( filepath, js_options, outfile, "js" ) pretty = beautify_file(filepath, js_options) write_beautified_output(pretty, js_options, outfile) except MissingInputStreamError: print("Must pipe input or define at least one file.\n", file=sys.stderr) usage(sys.stderr) return 1 except UnicodeError as ex: print("Error while decoding input or encoding output:", file=sys.stderr) print(ex, file=sys.stderr) return 1 except Exception as ex: print(ex, file=sys.stderr) return 1 # Success return 0 if __name__ == "__main__": main() python-jsbeautifier-1.15.3/jsbeautifier/__version__.py000066400000000000000000000000271475627451400231210ustar00rootroot00000000000000__version__ = "1.15.3" python-jsbeautifier-1.15.3/jsbeautifier/cli/000077500000000000000000000000001475627451400210365ustar00rootroot00000000000000python-jsbeautifier-1.15.3/jsbeautifier/cli/__init__.py000066400000000000000000000210221475627451400231440ustar00rootroot00000000000000from __future__ import print_function import sys import os import platform import io import getopt import re import string import errno import copy import glob from jsbeautifier.__version__ import __version__ from jsbeautifier.javascript.options import BeautifierOptions from jsbeautifier.javascript.beautifier import Beautifier # # The MIT License (MIT) # Copyright (c) 2007-2020 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. __all__ = [ "MissingInputStreamError", "process_file", "get_filepaths_from_params", "integrate_editorconfig_options", "write_beautified_output", ] class MissingInputStreamError(Exception): pass def set_file_editorconfig_opts(filename, js_options): from editorconfig import get_properties, EditorConfigError try: _ecoptions = get_properties(os.path.abspath(filename)) if _ecoptions.get("indent_style") == "tab": js_options.indent_with_tabs = True elif _ecoptions.get("indent_style") == "space": js_options.indent_with_tabs = False if _ecoptions.get("indent_size"): js_options.indent_size = int(_ecoptions["indent_size"]) if _ecoptions.get("max_line_length"): if _ecoptions.get("max_line_length") == "off": js_options.wrap_line_length = 0 else: js_options.wrap_line_length = int(_ecoptions["max_line_length"]) if _ecoptions.get("insert_final_newline") == "true": js_options.end_with_newline = True elif _ecoptions.get("insert_final_newline") == "false": js_options.end_with_newline = False if _ecoptions.get("end_of_line"): if _ecoptions["end_of_line"] == "cr": js_options.eol = "\r" elif _ecoptions["end_of_line"] == "lf": js_options.eol = "\n" elif _ecoptions["end_of_line"] == "crlf": js_options.eol = "\r\n" except EditorConfigError: # do not error on bad editor config print("Error loading EditorConfig. Ignoring.", file=sys.stderr) def process_file(file_name, opts, beautify_code): input_string = "" if file_name == "-": # stdin if sys.stdin.isatty(): raise MissingInputStreamError() stream = sys.stdin if platform.platform().lower().startswith("windows"): if sys.version_info.major >= 3: # for python 3 on windows this prevents conversion stream = io.TextIOWrapper(sys.stdin.buffer, newline="") elif platform.architecture()[0] == "32bit": # for python 2 x86 on windows this prevents conversion import msvcrt msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) else: raise Exception( "Pipe to stdin not supported on Windows with Python 2.x 64-bit." ) input_string = stream.read() # if you pipe an empty string, that is a failure if input_string == "": raise MissingInputStreamError() else: stream = io.open(file_name, "rt", newline="", encoding="UTF-8") input_string = stream.read() return beautify_code(input_string, opts) def mkdir_p(path): try: if path: os.makedirs(path) except OSError as exc: # Python >2.5 if exc.errno == errno.EEXIST and os.path.isdir(path): pass else: raise Exception() def isFileDifferent(filepath, expected): try: return "".join(io.open(filepath, "rt", newline="").readlines()) != expected except BaseException: return True def get_filepaths_from_params(filepath_params, replace): filepaths = [] if not filepath_params or (len(filepath_params) == 1 and filepath_params[0] == "-"): # default to stdin filepath_params = [] filepaths.append("-") for filepath_param in filepath_params: # ignore stdin setting if files are specified if "-" == filepath_param: continue # Check if each literal filepath exists if os.path.isfile(filepath_param): filepaths.append(filepath_param) elif "*" in filepath_param or "?" in filepath_param: # handle globs # empty result is okay if sys.version_info.major == 2 or ( sys.version_info.major == 3 and sys.version_info.minor <= 4 ): if "**" in filepath_param: raise Exception("Recursive globs not supported on Python <= 3.4.") filepaths.extend(glob.glob(filepath_param)) else: filepaths.extend(glob.glob(filepath_param, recursive=True)) else: # not a glob and not a file raise OSError(errno.ENOENT, os.strerror(errno.ENOENT), filepath_param) if len(filepaths) > 1: replace = True elif filepaths and filepaths[0] == "-": replace = False # remove duplicates filepaths = set(filepaths) return filepaths, replace def integrate_editorconfig_options(filepath, local_options, outfile, default_file_type): # Editorconfig used only on files, not stdin if getattr(local_options, "editorconfig"): editorconfig_filepath = filepath if editorconfig_filepath == "-": if outfile != "stdout": editorconfig_filepath = outfile else: fileType = default_file_type editorconfig_filepath = "stdin." + fileType # debug("EditorConfig is enabled for ", editorconfig_filepath); local_options = copy.copy(local_options) set_file_editorconfig_opts(editorconfig_filepath, local_options) return local_options def write_beautified_output(pretty, local_options, outfile): if outfile == "stdout": stream = sys.stdout # python automatically converts newlines in text to "\r\n" when on windows # switch to binary to prevent this if platform.platform().lower().startswith("windows"): if sys.version_info.major >= 3: # for python 3 on windows this prevents conversion stream = io.TextIOWrapper(sys.stdout.buffer, newline="") elif platform.architecture()[0] == "32bit": # for python 2 x86 on windows this prevents conversion import msvcrt msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) else: raise Exception( "Pipe to stdout not supported on Windows with Python 2.x 64-bit." ) stream.write(pretty) else: if isFileDifferent(outfile, pretty): mkdir_p(os.path.dirname(outfile)) # python automatically converts newlines in text to "\r\n" when on windows # set newline to empty to prevent this with io.open(outfile, "wt", newline="", encoding="UTF-8") as f: if not local_options.keep_quiet: print("beautified " + outfile, file=sys.stdout) try: f.write(pretty) except TypeError: # 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. six = __import__("six") f.write(six.u(pretty)) elif not local_options.keep_quiet: print("beautified " + outfile + " - unchanged", file=sys.stdout) python-jsbeautifier-1.15.3/jsbeautifier/core/000077500000000000000000000000001475627451400212175ustar00rootroot00000000000000python-jsbeautifier-1.15.3/jsbeautifier/core/__init__.py000066400000000000000000000000201475627451400233200ustar00rootroot00000000000000# Empty file :) python-jsbeautifier-1.15.3/jsbeautifier/core/directives.py000066400000000000000000000042211475627451400237310ustar00rootroot00000000000000# The MIT License (MIT) # # Copyright (c) 2007-2018 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 re class Directives: def __init__(self, start_block_pattern, end_block_pattern): self.__directives_block_pattern = re.compile( start_block_pattern + r" beautify( \w+[:]\w+)+ " + end_block_pattern ) self.__directive_pattern = re.compile(r" (\w+)[:](\w+)") self.__directives_end_ignore_pattern = re.compile( start_block_pattern + r"\sbeautify\signore:end\s" + end_block_pattern ) def get_directives(self, text): if not self.__directives_block_pattern.match(text): return None directives = {} directive_match = self.__directive_pattern.search(text) while directive_match: directives[directive_match.group(1)] = directive_match.group(2) directive_match = self.__directive_pattern.search( text, directive_match.end() ) return directives def readIgnored(self, input): return input.readUntilAfter(self.__directives_end_ignore_pattern) python-jsbeautifier-1.15.3/jsbeautifier/core/inputscanner.py000066400000000000000000000110431475627451400243010ustar00rootroot00000000000000# The MIT License (MIT) # # Copyright (c) 2007-2018 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 re class InputScanner: def __init__(self, input_string): self.__six = __import__("six") if input_string is None: input_string = "" self.__input = input_string self.__input_length = len(self.__input) self.__position = 0 def restart(self): self.__position = 0 def back(self): if self.__position > 0: self.__position -= 1 def hasNext(self): return self.__position < self.__input_length def next(self): val = None if self.hasNext(): val = self.__input[self.__position] self.__position += 1 return val def peek(self, index=0): val = None index += self.__position if index >= 0 and index < self.__input_length: val = self.__input[index] return val def test(self, pattern, index=0): index += self.__position return ( index >= 0 and index < self.__input_length and bool(pattern.match(self.__input, index)) ) def testChar(self, pattern, index=0): # test one character regex match val = self.peek(index) return val is not None and bool(pattern.match(val)) def match(self, pattern): pattern_match = None if self.hasNext(): pattern_match = pattern.match(self.__input, self.__position) if bool(pattern_match): self.__position = pattern_match.end(0) return pattern_match def read(self, starting_pattern, until_pattern=None, until_after=False): val = "" pattern_match = None if bool(starting_pattern): pattern_match = self.match(starting_pattern) if bool(pattern_match): val = pattern_match.group(0) if bool(until_pattern) and (bool(pattern_match) or not bool(starting_pattern)): val += self.readUntil(until_pattern, until_after) return val def readUntil(self, pattern, include_match=False): val = "" pattern_match = None match_index = self.__position if self.hasNext(): pattern_match = pattern.search(self.__input, self.__position) if bool(pattern_match): if include_match: match_index = pattern_match.end(0) else: match_index = pattern_match.start(0) else: match_index = self.__input_length val = self.__input[self.__position : match_index] self.__position = match_index return val def readUntilAfter(self, pattern): return self.readUntil(pattern, True) def get_regexp(self, pattern, match_from=False): result = None # strings are converted to regexp if isinstance(pattern, self.__six.string_types) and pattern != "": result = re.compile(pattern) elif pattern is not None: result = re.compile(pattern.pattern) return result # css beautifier legacy helpers def peekUntilAfter(self, pattern): start = self.__position val = self.readUntilAfter(pattern) self.__position = start return val def lookBack(self, testVal): start = self.__position - 1 return ( start >= len(testVal) and self.__input[start - len(testVal) : start].lower() == testVal ) python-jsbeautifier-1.15.3/jsbeautifier/core/options.py000066400000000000000000000177261475627451400233010ustar00rootroot00000000000000# The MIT License (MIT) # # Copyright (c) 2007-2018 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 copy import re from collections import namedtuple class Options: def __init__(self, options=None, merge_child_field=None): self.css = None self.js = None self.html = None self.raw_options = _mergeOpts(options, merge_child_field) # Support passing the source text back with no change self.disabled = self._get_boolean("disabled") self.eol = self._get_characters("eol", "auto") self.end_with_newline = self._get_boolean("end_with_newline") self.indent_size = self._get_number("indent_size", 4) self.indent_char = self._get_characters("indent_char", " ") self.indent_level = self._get_number("indent_level") self.preserve_newlines = self._get_boolean("preserve_newlines", True) self.max_preserve_newlines = self._get_number("max_preserve_newlines", 32786) if not self.preserve_newlines: self.max_preserve_newlines = 0 self.indent_with_tabs = self._get_boolean( "indent_with_tabs", self.indent_char == "\t" ) if self.indent_with_tabs: self.indent_char = "\t" # indent_size behavior changed after 1.8.6 # It used to be that indent_size would be # set to 1 for indent_with_tabs. That is no longer needed and # actually doesn't make sense - why not use spaces? Further, # that might produce unexpected behavior - tabs being used # for single-column alignment. So, when indent_with_tabs is true # and indent_size is 1, reset indent_size to 4. if self.indent_size == 1: self.indent_size = 4 # Backwards compat with 1.3.x self.wrap_line_length = self._get_number( "wrap_line_length", self._get_number("max_char") ) # Support editor config setting self.editorconfig = False self.indent_empty_lines = self._get_boolean("indent_empty_lines") # valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty', 'angular'] # For now, 'auto' = all off for javascript, all except angular on for html (and inline javascript/css). # other values ignored self.templating = self._get_selection_list( "templating", ["auto", "none", "angular", "django", "erb", "handlebars", "php", "smarty"], ["auto"], ) def _get_array(self, name, default_value=[]): option_value = getattr(self.raw_options, name, default_value) result = [] if isinstance(option_value, list): result = copy.copy(option_value) elif isinstance(option_value, str): result = re.compile(r"[^a-zA-Z0-9_/\-]+").split(option_value) return result def _get_boolean(self, name, default_value=False): option_value = getattr(self.raw_options, name, default_value) result = False try: result = bool(option_value) except ValueError: pass return result def _get_characters(self, name, default_value=""): option_value = getattr(self.raw_options, name, default_value) result = "" if isinstance(option_value, str): result = ( option_value.replace("\\r", "\r") .replace("\\n", "\n") .replace("\\t", "\t") ) return result def _get_number(self, name, default_value=0): option_value = getattr(self.raw_options, name, default_value) result = 0 try: result = int(option_value) except ValueError: pass return result def _get_selection(self, name, selection_list, default_value=None): result = self._get_selection_list(name, selection_list, default_value) if len(result) != 1: raise ValueError( "Invalid Option Value: The option '" + name + "' can only be one of the following values:\n" + str(selection_list) + "\nYou passed in: '" + str(getattr(self.raw_options, name, None)) + "'" ) return result[0] def _get_selection_list(self, name, selection_list, default_value=None): if not selection_list: raise ValueError("Selection list cannot be empty.") default_value = default_value or [selection_list[0]] if not self._is_valid_selection(default_value, selection_list): raise ValueError("Invalid Default Value!") result = self._get_array(name, default_value) if not self._is_valid_selection(result, selection_list): raise ValueError( "Invalid Option Value: The option '" + name + "' can contain only the following values:\n" + str(selection_list) + "\nYou passed in: '" + str(getattr(self.raw_options, name, None)) + "'" ) return result def _is_valid_selection(self, result, selection_list): if len(result) == 0 or len(selection_list) == 0: return False for item in result: if item not in selection_list: return False return True # merges child options up with the parent options object # Example: obj = {a: 1, b: {a: 2}} # mergeOpts(obj, 'b') # # Returns: {a: 2} def _mergeOpts(options, childFieldName): if options is None: options = {} if isinstance(options, tuple): options = dict(options) options = _normalizeOpts(options) finalOpts = copy.copy(options) if isinstance(options, dict): local = finalOpts.get(childFieldName, None) if local: del finalOpts[childFieldName] for key in local: finalOpts[key] = local[key] finalOpts = namedtuple("CustomOptions", finalOpts.keys())(*finalOpts.values()) if isinstance(options, Options): local = getattr(finalOpts, childFieldName, None) if local: delattr(finalOpts, childFieldName) for key in local: setattr(finalOpts, key, local[key]) return finalOpts def _normalizeOpts(options): convertedOpts = copy.copy(options) if isinstance(convertedOpts, dict): option_keys = list(convertedOpts.keys()) for key in option_keys: if "-" in key: del convertedOpts[key] convertedOpts[key.replace("-", "_")] = options[key] else: option_keys = list(getattr(convertedOpts, "__dict__", {})) for key in option_keys: if "-" in key: delattr(convertedOpts, key) setattr( convertedOpts, key.replace("-", "_"), getattr(options, key, None) ) return convertedOpts python-jsbeautifier-1.15.3/jsbeautifier/core/output.py000066400000000000000000000274601475627451400231420ustar00rootroot00000000000000# The MIT License (MIT) # # Copyright (c) 2007-2018 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 re import math # Using object instead of string to allow for later expansion of info # about each line __all__ = ["Output"] class OutputLine: def __init__(self, parent): self.__parent = parent self.__character_count = 0 self.__indent_count = -1 self.__alignment_count = 0 self.__wrap_point_index = 0 self.__wrap_point_character_count = 0 self.__wrap_point_indent_count = -1 self.__wrap_point_alignment_count = 0 self.__items = [] def clone_empty(self): line = OutputLine(self.__parent) line.set_indent(self.__indent_count, self.__alignment_count) return line def item(self, index): return self.__items[index] def is_empty(self): return len(self.__items) == 0 def set_indent(self, indent=0, alignment=0): if self.is_empty(): self.__indent_count = indent self.__alignment_count = alignment self.__character_count = self.__parent.get_indent_size( self.__indent_count, self.__alignment_count ) def _set_wrap_point(self): if self.__parent.wrap_line_length: self.__wrap_point_index = len(self.__items) self.__wrap_point_character_count = self.__character_count self.__wrap_point_indent_count = self.__parent.next_line.__indent_count self.__wrap_point_alignment_count = ( self.__parent.next_line.__alignment_count ) def _should_wrap(self): return ( self.__wrap_point_index and self.__character_count > self.__parent.wrap_line_length and self.__wrap_point_character_count > self.__parent.next_line.__character_count ) def _allow_wrap(self): if self._should_wrap(): self.__parent.add_new_line() next = self.__parent.current_line next.set_indent( self.__wrap_point_indent_count, self.__wrap_point_alignment_count ) next.__items = self.__items[self.__wrap_point_index :] self.__items = self.__items[: self.__wrap_point_index] next.__character_count += ( self.__character_count - self.__wrap_point_character_count ) self.__character_count = self.__wrap_point_character_count if next.__items[0] == " ": next.__items.pop(0) next.__character_count -= 1 return True return False def last(self): if not self.is_empty(): return self.__items[-1] return None def push(self, item): self.__items.append(item) last_newline_index = item.rfind("\n") if last_newline_index != -1: self.__character_count = len(item) - last_newline_index else: self.__character_count += len(item) def pop(self): item = None if not self.is_empty(): item = self.__items.pop() self.__character_count -= len(item) return item def _remove_indent(self): if self.__indent_count > 0: self.__indent_count -= 1 self.__character_count -= self.__parent.indent_size def _remove_wrap_indent(self): if self.__wrap_point_indent_count > 0: self.__wrap_point_indent_count -= 1 def trim(self): while self.last() == " ": self.__items.pop() self.__character_count -= 1 def toString(self): result = "" if self.is_empty(): if self.__parent.indent_empty_lines: result = self.__parent.get_indent_string(self.__indent_count) else: result = self.__parent.get_indent_string( self.__indent_count, self.__alignment_count ) result += "".join(self.__items) return result class IndentStringCache: def __init__(self, options, base_string): self.__cache = [""] self.__indent_size = options.indent_size self.__indent_string = options.indent_char if not options.indent_with_tabs: self.__indent_string = options.indent_char * options.indent_size # Set to null to continue support of auto detection of base indent base_string = base_string or "" if options.indent_level > 0: base_string = options.indent_level * self.__indent_string self.__base_string = base_string self.__base_string_length = len(base_string) def get_indent_size(self, indent, column=0): result = self.__base_string_length if indent < 0: result = 0 result += indent * self.__indent_size result += column return result def get_indent_string(self, indent_level, column=0): result = self.__base_string if indent_level < 0: indent_level = 0 result = "" column += indent_level * self.__indent_size self.__ensure_cache(column) result += self.__cache[column] return result def __ensure_cache(self, column): while column >= len(self.__cache): self.__add_column() def __add_column(self): column = len(self.__cache) indent = 0 result = "" if self.__indent_size and column >= self.__indent_size: indent = int(math.floor(column / self.__indent_size)) column -= indent * self.__indent_size result = indent * self.__indent_string if column: result += column * " " self.__cache.append(result) class Output: def __init__(self, options, baseIndentString=""): self.__indent_cache = IndentStringCache(options, baseIndentString) self.raw = False self._end_with_newline = options.end_with_newline self.indent_size = options.indent_size self.wrap_line_length = options.wrap_line_length self.indent_empty_lines = options.indent_empty_lines self.__lines = [] self.previous_line = None self.current_line = None self.next_line = OutputLine(self) self.space_before_token = False self.non_breaking_space = False self.previous_token_wrapped = False # initialize self.__add_outputline() def __add_outputline(self): self.previous_line = self.current_line self.current_line = self.next_line.clone_empty() self.__lines.append(self.current_line) def get_line_number(self): return len(self.__lines) def get_indent_string(self, indent, column=0): return self.__indent_cache.get_indent_string(indent, column) def get_indent_size(self, indent, column=0): return self.__indent_cache.get_indent_size(indent, column) def is_empty(self): return self.previous_line is None and self.current_line.is_empty() def add_new_line(self, force_newline=False): # never newline at the start of file # otherwise, newline only if we didn't just add one or we're forced if self.is_empty() or (not force_newline and self.just_added_newline()): return False # if raw output is enabled, don't print additional newlines, # but still return True as though you had if not self.raw: self.__add_outputline() return True def get_code(self, eol): self.trim(True) # handle some edge cases where the last tokens # has text that ends with newline(s) last_item = self.current_line.pop() if last_item: if last_item[-1] == "\n": last_item = re.sub(r"[\n]+$", "", last_item) self.current_line.push(last_item) if self._end_with_newline: self.__add_outputline() sweet_code = "\n".join(line.toString() for line in self.__lines) if not eol == "\n": sweet_code = sweet_code.replace("\n", eol) return sweet_code def set_wrap_point(self): self.current_line._set_wrap_point() def set_indent(self, indent=0, alignment=0): # Next line stores alignment values self.next_line.set_indent(indent, alignment) # Never indent your first output indent at the start of the file if len(self.__lines) > 1: self.current_line.set_indent(indent, alignment) return True self.current_line.set_indent() return False def add_raw_token(self, token): for _ in range(token.newlines): self.__add_outputline() self.current_line.set_indent(-1) self.current_line.push(token.whitespace_before) self.current_line.push(token.text) self.space_before_token = False self.non_breaking_space = False self.previous_token_wrapped = False def add_token(self, printable_token): self.__add_space_before_token() self.current_line.push(printable_token) self.space_before_token = False self.non_breaking_space = False self.previous_token_wrapped = self.current_line._allow_wrap() def __add_space_before_token(self): if self.space_before_token and not self.just_added_newline(): if not self.non_breaking_space: self.set_wrap_point() self.current_line.push(" ") self.space_before_token = False def remove_indent(self, index): while index < len(self.__lines): self.__lines[index]._remove_indent() index += 1 self.current_line._remove_wrap_indent() def trim(self, eat_newlines=False): self.current_line.trim() while eat_newlines and len(self.__lines) > 1 and self.current_line.is_empty(): self.__lines.pop() self.current_line = self.__lines[-1] self.current_line.trim() if len(self.__lines) > 1: self.previous_line = self.__lines[-2] else: self.previous_line = None def just_added_newline(self): return self.current_line.is_empty() def just_added_blankline(self): return self.is_empty() or ( self.current_line.is_empty() and self.previous_line.is_empty() ) def ensure_empty_line_above(self, starts_with, ends_with): index = len(self.__lines) - 2 while index >= 0: potentialEmptyLine = self.__lines[index] if potentialEmptyLine.is_empty(): break elif ( not potentialEmptyLine.item(0).startswith(starts_with) and potentialEmptyLine.item(-1) != ends_with ): self.__lines.insert(index + 1, OutputLine(self)) self.previous_line = self.__lines[-2] break index -= 1 python-jsbeautifier-1.15.3/jsbeautifier/core/pattern.py000066400000000000000000000057121475627451400232530ustar00rootroot00000000000000# The MIT License (MIT) # # Copyright (c) 2007-2018 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. __all__ = ["Pattern"] class Pattern: def __init__(self, input_scanner, parent=None): self._input = input_scanner self._starting_pattern = None self._match_pattern = None self._until_pattern = None self._until_after = False if parent is not None: self._starting_pattern = self._input.get_regexp(parent._starting_pattern) self._match_pattern = self._input.get_regexp(parent._match_pattern) self._until_pattern = self._input.get_regexp(parent._until_pattern) self._until_after = parent._until_after def read(self): result = self._input.read(self._starting_pattern) if (self._starting_pattern is None) or result: result += self._input.read( self._match_pattern, self._until_pattern, self._until_after ) return result def read_match(self): return self._input.match(self._match_pattern) def until_after(self, pattern): result = self._create() result._until_after = True result._until_pattern = self._input.get_regexp(pattern) result._update() return result def until(self, pattern): result = self._create() result._until_after = False result._until_pattern = self._input.get_regexp(pattern) result._update() return result def starting_with(self, pattern): result = self._create() result._starting_pattern = self._input.get_regexp(pattern) result._update() return result def matching(self, pattern): result = self._create() result._match_pattern = self._input.get_regexp(pattern) result._update() return result def _create(self): return Pattern(self._input, self) def _update(self): pass python-jsbeautifier-1.15.3/jsbeautifier/core/templatablepattern.py000066400000000000000000000172011475627451400254620ustar00rootroot00000000000000# The MIT License (MIT) # # Copyright (c) 2007-2018 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 copy from ..core.pattern import Pattern __all__ = ["TemplatablePattern"] class TemplateNames: def __init__(self): self.django = False self.erb = False self.handlebars = False self.php = False self.smarty = False self.angular = False class TemplatePatterns: def __init__(self, input_scanner): pattern = Pattern(input_scanner) self.handlebars_comment = pattern.starting_with(r"{{!--").until_after(r"--}}") self.handlebars_unescaped = pattern.starting_with(r"{{{").until_after(r"}}}") self.handlebars = pattern.starting_with(r"{{").until_after(r"}}") self.php = pattern.starting_with(r"<\?(?:[= ]|php)").until_after(r"\?>") self.erb = pattern.starting_with(r"<%[^%]").until_after(r"[^%]%>") # django coflicts with handlebars a bit. self.django = pattern.starting_with(r"{%").until_after(r"%}") self.django_value = pattern.starting_with(r"{{").until_after(r"}}") self.django_comment = pattern.starting_with(r"{#").until_after(r"#}") self.smarty_value = pattern.starting_with(r"{(?=[^}{\s\n])").until_after(r"}") self.smarty_comment = pattern.starting_with(r"{\*").until_after(r"\*}") self.smarty_literal = pattern.starting_with(r"{literal}").until_after( r"{/literal}" ) class TemplatablePattern(Pattern): def __init__(self, input_scanner, parent=None): Pattern.__init__(self, input_scanner, parent) self.__template_pattern = None self._disabled = TemplateNames() self._excluded = TemplateNames() if parent is not None: self.__template_pattern = self._input.get_regexp(parent.__template_pattern) self._disabled = copy.copy(parent._disabled) self._excluded = copy.copy(parent._excluded) self.__patterns = TemplatePatterns(input_scanner) def _create(self): return TemplatablePattern(self._input, self) def _update(self): self.__set_templated_pattern() def read_options(self, options): result = self._create() for language in ["django", "erb", "handlebars", "php", "smarty", "angular"]: setattr(result._disabled, language, not (language in options.templating)) result._update() return result def disable(self, language): result = self._create() setattr(result._disabled, language, True) result._update() return result def exclude(self, language): result = self._create() setattr(result._excluded, language, True) result._update() return result def read(self): result = "" if bool(self._match_pattern): result = self._input.read(self._starting_pattern) else: result = self._input.read(self._starting_pattern, self.__template_pattern) next = self._read_template() while bool(next): if self._match_pattern is not None: next += self._input.read(self._match_pattern) else: next += self._input.readUntil(self.__template_pattern) result += next next = self._read_template() if self._until_after: result += self._input.readUntilAfter(self._until_pattern) return result def __set_templated_pattern(self): items = list() if not self._disabled.php: items.append(self.__patterns.php._starting_pattern.pattern) if not self._disabled.handlebars: items.append(self.__patterns.handlebars._starting_pattern.pattern) if not self._disabled.erb: items.append(self.__patterns.erb._starting_pattern.pattern) if not self._disabled.django: items.append(self.__patterns.django._starting_pattern.pattern) # The starting pattern for django is more complex because it has different # patterns for value, comment, and other sections items.append(self.__patterns.django_value._starting_pattern.pattern) items.append(self.__patterns.django_comment._starting_pattern.pattern) if not self._disabled.smarty: items.append(self.__patterns.smarty._starting_pattern.pattern) if self._until_pattern: items.append(self._until_pattern.pattern) self.__template_pattern = self._input.get_regexp(r"(?:" + "|".join(items) + ")") def _read_template(self): resulting_string = "" c = self._input.peek() if c == "<": peek1 = self._input.peek(1) if not self._disabled.php and not self._excluded.php and peek1 == "?": resulting_string = resulting_string or self.__patterns.php.read() if not self._disabled.erb and not self._excluded.erb and peek1 == "%": resulting_string = resulting_string or self.__patterns.erb.read() elif c == "{": if not self._disabled.handlebars and not self._excluded.handlebars: resulting_string = ( resulting_string or self.__patterns.handlebars_comment.read() ) resulting_string = ( resulting_string or self.__patterns.handlebars_unescaped.read() ) resulting_string = resulting_string or self.__patterns.handlebars.read() if not self._disabled.django: # django coflicts with handlebars a bit. if not self._excluded.django and not self._excluded.handlebars: resulting_string = ( resulting_string or self.__patterns.django_value.read() ) if not self._excluded.django: resulting_string = ( resulting_string or self.__patterns.django_comment.read() ) resulting_string = resulting_string or self.__patterns.django.read() if not self._disabled.smarty: # smarty cannot be enabled with django or handlebars enabled if self._disabled.django and self._disabled.handlebars: resulting_string = ( resulting_string or self.__patterns.smarty_comment.read() ) resulting_string = ( resulting_string or self.__patterns.smarty_literal.read() ) resulting_string = resulting_string or self.__patterns.smarty.read() return resulting_string python-jsbeautifier-1.15.3/jsbeautifier/core/token.py000066400000000000000000000030561475627451400227150ustar00rootroot00000000000000# The MIT License (MIT) # # Copyright (c) 2007-2018 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 Token: def __init__(self, type, text, newlines=0, whitespace_before=""): self.type = type self.text = text self.comments_before = None self.newlines = newlines self.whitespace_before = whitespace_before self.parent = None self.next = None self.previous = None self.opened = None self.closed = None self.directives = None python-jsbeautifier-1.15.3/jsbeautifier/core/tokenizer.py000066400000000000000000000104451475627451400236070ustar00rootroot00000000000000# The MIT License (MIT) # # Copyright (c) 2007-2018 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 re from ..core.inputscanner import InputScanner from ..core.token import Token from ..core.tokenstream import TokenStream from ..core.pattern import Pattern from ..core.whitespacepattern import WhitespacePattern __all__ = ["TOKEN", "Tokenizer", "TokenizerPatterns", "TokenTypes"] class TokenTypes: START = "TK_START" RAW = "TK_RAW" EOF = "TK_EOF" def __init__(self): pass TOKEN = TokenTypes() class TokenizerPatterns: def __init__(self, input_scanner): self.whitespace = WhitespacePattern(input_scanner) class Tokenizer: def __init__(self, input_string, options): self._input = InputScanner(input_string) self._options = options self.__tokens = None self._patterns = TokenizerPatterns(self._input) def tokenize(self): self._input.restart() self.__tokens = TokenStream() current = None previous = Token(TOKEN.START, "") open_token = None open_stack = [] comments = TokenStream() while previous.type != TOKEN.EOF: current = self.__get_next_token_with_comments(previous, open_token) if self._is_opening(current): open_stack.append(open_token) open_token = current elif open_token is not None and self._is_closing(current, open_token): current.opened = open_token open_token.closed = current open_token = open_stack.pop() current.parent = open_token self.__tokens.add(current) previous = current return self.__tokens def __get_next_token_with_comments(self, previous, open_token): current = self._get_next_token(previous, open_token) if self._is_comment(current): comments = TokenStream() while self._is_comment(current): comments.add(current) current = self._get_next_token(previous, open_token) if not comments.isEmpty(): current.comments_before = comments comments = TokenStream() current.parent = open_token current.previous = previous previous.next = current return current def _is_first_token(self): return self.__tokens.isEmpty() def _reset(self): pass def _get_next_token(self, previous_token, open_token): self._readWhitespace() resulting_string = self._input.read(re.compile(r".+")) if resulting_string: return self._create_token(TOKEN.RAW, resulting_string) else: return self._create_token(TOKEN.EOF, "") def _is_comment(self, current_token): return False def _is_opening(self, current_token): return False def _is_closing(self, current_token, open_token): return False def _create_token(self, token_type, text): token = Token( token_type, text, self._patterns.whitespace.newline_count, self._patterns.whitespace.whitespace_before_token, ) return token def _readWhitespace(self): return self._patterns.whitespace.read() python-jsbeautifier-1.15.3/jsbeautifier/core/tokenstream.py000066400000000000000000000044541475627451400241340ustar00rootroot00000000000000# The MIT License (MIT) # # Copyright (c) 2007-2018 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 re from ..core.inputscanner import InputScanner from ..core.token import Token class TokenStream: def __init__(self, parent_token=None): self.__tokens = [] self.__tokens_length = len(self.__tokens) self.__position = 0 self.__parent_token = parent_token def restart(self): self.__position = 0 def isEmpty(self): return self.__tokens_length == 0 def hasNext(self): return self.__position < self.__tokens_length def next(self): if self.hasNext(): val = self.__tokens[self.__position] self.__position += 1 return val else: raise StopIteration def peek(self, index=0): val = None index += self.__position if index >= 0 and index < self.__tokens_length: val = self.__tokens[index] return val def add(self, token): if self.__parent_token: token.parent = self.__parent_token self.__tokens.append(token) self.__tokens_length += 1 def __iter__(self): self.restart() return self def __next__(self): return self.next() python-jsbeautifier-1.15.3/jsbeautifier/core/whitespacepattern.py000066400000000000000000000053041475627451400253250ustar00rootroot00000000000000# The MIT License (MIT) # # Copyright (c) 2007-2018 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 re from ..core.pattern import Pattern __all__ = ["WhitespacePattern"] class WhitespacePattern(Pattern): def __init__(self, input_scanner, parent=None): Pattern.__init__(self, input_scanner, parent) if parent is not None: self._newline_regexp = self._input.get_regexp(parent._newline_regexp) else: self.__set_whitespace_patterns("", "") self.newline_count = 0 self.whitespace_before_token = "" def __set_whitespace_patterns(self, whitespace_chars, newline_chars): whitespace_chars += "\\t " newline_chars += "\\n\\r" self._match_pattern = self._input.get_regexp( "[" + whitespace_chars + newline_chars + "]+" ) self._newline_regexp = self._input.get_regexp("\\r\\n|[" + newline_chars + "]") def read(self): self.newline_count = 0 self.whitespace_before_token = "" resulting_string = self._input.read(self._match_pattern) if resulting_string == " ": self.whitespace_before_token = " " elif bool(resulting_string): lines = self._newline_regexp.split(resulting_string) self.newline_count = len(lines) - 1 self.whitespace_before_token = lines[-1] return resulting_string def matching(self, whitespace_chars, newline_chars): result = self._create() result.__set_whitespace_patterns(whitespace_chars, newline_chars) result._update() return result def _create(self): return WhitespacePattern(self._input, self) python-jsbeautifier-1.15.3/jsbeautifier/javascript/000077500000000000000000000000001475627451400224355ustar00rootroot00000000000000python-jsbeautifier-1.15.3/jsbeautifier/javascript/__init__.py000066400000000000000000000000201475627451400245360ustar00rootroot00000000000000# Empty file :) python-jsbeautifier-1.15.3/jsbeautifier/javascript/acorn.py000066400000000000000000000224101475627451400241100ustar00rootroot00000000000000import re # This section of code was translated to python from acorn (javascript). # # Acorn was written by Marijn Haverbeke and released under an MIT # license. The Unicode regexps (for identifiers and whitespace) were # taken from [Esprima](http://esprima.org) by Ariya Hidayat. # # Git repositories for Acorn are available at # # http://marijnhaverbeke.nl/git/acorn # https://github.com/marijnh/acorn.git # 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. six = __import__("six") # ## Character categories # acorn used char codes to squeeze the last bit of performance out # Beautifier is okay without that, so we're using regex # permit #(23), $ (36), and @ (64). @ is used in ES7 decorators. # 65 through 91 are uppercase letters. # permit _ (95). # 97 through 123 are lowercase letters. _baseASCIIidentifierStartChars = six.u(r"\x23\x24\x40\x41-\x5a\x5f\x61-\x7a") # inside an identifier @ is not allowed but 0-9 are. _baseASCIIidentifierChars = six.u(r"\x24\x30-\x39\x41-\x5a\x5f\x61-\x7a") # Big ugly regular expressions that match characters in the # whitespace, identifier, and identifier-start categories. These # are only applied when a character is found to actually have a # code point above 128. # IMPORTANT: These strings must be run through six to handle \u chars _nonASCIIidentifierStartChars = six.u( r"\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc" ) _nonASCIIidentifierChars = six.u( r"\u0300-\u036f\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u0620-\u0649\u0672-\u06d3\u06e7-\u06e8\u06fb-\u06fc\u0730-\u074a\u0800-\u0814\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0840-\u0857\u08e4-\u08fe\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962-\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09d7\u09df-\u09e0\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5f-\u0b60\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2-\u0ce3\u0ce6-\u0cef\u0d02\u0d03\u0d46-\u0d48\u0d57\u0d62-\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e34-\u0e3a\u0e40-\u0e45\u0e50-\u0e59\u0eb4-\u0eb9\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f41-\u0f47\u0f71-\u0f84\u0f86-\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1029\u1040-\u1049\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u170e-\u1710\u1720-\u1730\u1740-\u1750\u1772\u1773\u1780-\u17b2\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1920-\u192b\u1930-\u193b\u1951-\u196d\u19b0-\u19c0\u19c8-\u19c9\u19d0-\u19d9\u1a00-\u1a15\u1a20-\u1a53\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1b46-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1bb0-\u1bb9\u1be6-\u1bf3\u1c00-\u1c22\u1c40-\u1c49\u1c5b-\u1c7d\u1cd0-\u1cd2\u1d00-\u1dbe\u1e01-\u1f15\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2d81-\u2d96\u2de0-\u2dff\u3021-\u3028\u3099\u309a\ua640-\ua66d\ua674-\ua67d\ua69f\ua6f0-\ua6f1\ua7f8-\ua800\ua806\ua80b\ua823-\ua827\ua880-\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8f3-\ua8f7\ua900-\ua909\ua926-\ua92d\ua930-\ua945\ua980-\ua983\ua9b3-\ua9c0\uaa00-\uaa27\uaa40-\uaa41\uaa4c-\uaa4d\uaa50-\uaa59\uaa7b\uaae0-\uaae9\uaaf2-\uaaf3\uabc0-\uabe1\uabec\uabed\uabf0-\uabf9\ufb20-\ufb28\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f" ) # _nonASCIIidentifierStart = re.compile("[" + _nonASCIIidentifierStartChars + "]") # _nonASCIIidentifier = re.compile("[" + _nonASCIIidentifierStartChars + _nonASCIIidentifierChars + "]") _unicodeEscapeOrCodePoint = six.u(r"\\u[0-9a-fA-F]{4}|\\u\{[0-9a-fA-F]+\}") _identifierStart = ( six.u("(?:") + _unicodeEscapeOrCodePoint + six.u("|[") + _baseASCIIidentifierStartChars + _nonASCIIidentifierStartChars + six.u("])") ) _identifierChars = ( six.u("(?:") + _unicodeEscapeOrCodePoint + six.u("|[") + _baseASCIIidentifierChars + _nonASCIIidentifierStartChars + _nonASCIIidentifierChars + six.u("])*") ) identifier = re.compile(_identifierStart + _identifierChars) identifierStart = re.compile(_identifierStart) identifierMatch = re.compile( six.u("(?:") + _unicodeEscapeOrCodePoint + six.u("|[") + _baseASCIIidentifierChars + _nonASCIIidentifierStartChars + _nonASCIIidentifierChars + six.u("])+") ) _nonASCIIwhitespace = re.compile( six.u(r"[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]") ) # Whether a single character denotes a newline. # IMPORTANT: This string must be run through six to handle \u chars newline = re.compile(six.u(r"[\n\r\u2028\u2029]")) # Matches a whole line break (where CRLF is considered a single # line break). Used to count lines. # in javascript, these two differ # in python they are the same, different methods are called on them # IMPORTANT: This string must be run through six to handle \u chars lineBreak = re.compile(six.u(r"\r\n|[\n\r\u2028\u2029]")) allLineBreaks = lineBreak python-jsbeautifier-1.15.3/jsbeautifier/javascript/beautifier.py000066400000000000000000001770231475627451400251400ustar00rootroot00000000000000# The MIT License (MIT) # # Copyright (c) 2007-2018 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 re import string import copy from ..core.token import Token from .tokenizer import Tokenizer from .tokenizer import TOKEN from .options import BeautifierOptions from ..core.output import Output def default_options(): return BeautifierOptions() class BeautifierFlags: def __init__(self, mode): self.mode = mode self.parent = None self.last_token = Token(TOKEN.START_BLOCK, "") self.last_word = "" self.declaration_statement = False self.declaration_assignment = False self.multiline_frame = False self.inline_frame = False self.if_block = False self.else_block = False self.class_start_block = False self.do_block = False self.do_while = False self.import_block = False self.in_case = False self.in_case_statement = False self.case_body = False self.case_block = False self.indentation_level = 0 self.alignment = 0 self.line_indent_level = 0 self.start_line_index = 0 self.ternary_depth = 0 def apply_base(self, flags_base, added_newline): next_indent_level = flags_base.indentation_level if not added_newline and flags_base.line_indent_level > next_indent_level: next_indent_level = flags_base.line_indent_level self.parent = flags_base self.last_token = flags_base.last_token self.last_word = flags_base.last_word self.indentation_level = next_indent_level OPERATOR_POSITION = { "before_newline": "before-newline", "after_newline": "after-newline", "preserve_newline": "preserve-newline", } OPERATOR_POSITION_BEFORE_OR_PRESERVE = [ OPERATOR_POSITION["before_newline"], OPERATOR_POSITION["preserve_newline"], ] class MODE: ( BlockStatement, Statement, ObjectLiteral, ArrayLiteral, ForInitializer, Conditional, Expression, ) = range(7) def remove_redundant_indentation(output, frame): # This implementation is effective but has some issues: # - can cause line wrap to happen too soon due to indent removal # after wrap points are calculated # These issues are minor compared to ugly indentation. if ( frame.multiline_frame or frame.mode == MODE.ForInitializer or frame.mode == MODE.Conditional ): return # remove one indent from each line inside this section output.remove_indent(frame.start_line_index) def reserved_word(token, word): return token and token.type == TOKEN.RESERVED and token.text == word def reserved_array(token, words): return token and token.type == TOKEN.RESERVED and token.text in words _special_word_set = frozenset( [ "case", "return", "do", "if", "throw", "else", "await", "break", "continue", "async", ] ) class Beautifier: def __init__(self, opts=None): import jsbeautifier.javascript.acorn as acorn self.acorn = acorn self._options = BeautifierOptions(opts) self._blank_state() def _blank_state(self, js_source_text=None): if js_source_text is None: js_source_text = "" # internal flags self._flags = None self._previous_flags = None self._flag_store = [] self._tokens = None if self._options.eol == "auto": self._options.eol = "\n" if self.acorn.lineBreak.search(js_source_text or ""): self._options.eol = self.acorn.lineBreak.search(js_source_text).group() baseIndentString = re.search("^[\t ]*", js_source_text).group(0) self._last_last_text = "" # pre-last token text self._output = Output(self._options, baseIndentString) # If testing the ignore directive, start with output disable set to # true self._output.raw = self._options.test_output_raw self.set_mode(MODE.BlockStatement) return js_source_text def beautify(self, source_text="", opts=None): if opts is not None: self._options = BeautifierOptions(opts) source_text = source_text or "" if self._options.disabled: return source_text source_text = self._blank_state(source_text) source_text = self.unpack(source_text, self._options.eval_code) self._tokens = Tokenizer(source_text, self._options).tokenize() for current_token in self._tokens: self.handle_token(current_token) self._last_last_text = self._flags.last_token.text self._flags.last_token = current_token sweet_code = self._output.get_code(self._options.eol) return sweet_code def handle_token(self, current_token, preserve_statement_flags=False): if current_token.type == TOKEN.START_EXPR: self.handle_start_expr(current_token) elif current_token.type == TOKEN.END_EXPR: self.handle_end_expr(current_token) elif current_token.type == TOKEN.START_BLOCK: self.handle_start_block(current_token) elif current_token.type == TOKEN.END_BLOCK: self.handle_end_block(current_token) elif current_token.type == TOKEN.WORD: self.handle_word(current_token) elif current_token.type == TOKEN.RESERVED: self.handle_word(current_token) elif current_token.type == TOKEN.SEMICOLON: self.handle_semicolon(current_token) elif current_token.type == TOKEN.STRING: self.handle_string(current_token) elif current_token.type == TOKEN.EQUALS: self.handle_equals(current_token) elif current_token.type == TOKEN.OPERATOR: self.handle_operator(current_token) elif current_token.type == TOKEN.COMMA: self.handle_comma(current_token) elif current_token.type == TOKEN.BLOCK_COMMENT: self.handle_block_comment(current_token, preserve_statement_flags) elif current_token.type == TOKEN.COMMENT: self.handle_comment(current_token, preserve_statement_flags) elif current_token.type == TOKEN.DOT: self.handle_dot(current_token) elif current_token.type == TOKEN.EOF: self.handle_eof(current_token) elif current_token.type == TOKEN.UNKNOWN: self.handle_unknown(current_token, preserve_statement_flags) else: self.handle_unknown(current_token, preserve_statement_flags) def handle_whitespace_and_comments( self, current_token, preserve_statement_flags=False ): newlines = current_token.newlines keep_whitespace = self._options.keep_array_indentation and self.is_array( self._flags.mode ) if current_token.comments_before is not None: for comment_token in current_token.comments_before: # The cleanest handling of inline comments is to treat them # as though they aren't there. # Just continue formatting and the behavior should be logical. # Also ignore unknown tokens. Again, this should result in better # behavior. self.handle_whitespace_and_comments( comment_token, preserve_statement_flags ) self.handle_token(comment_token, preserve_statement_flags) if keep_whitespace: for i in range(newlines): self.print_newline(i > 0, preserve_statement_flags) else: # not keep_whitespace if ( self._options.max_preserve_newlines != 0 and newlines > self._options.max_preserve_newlines ): newlines = self._options.max_preserve_newlines if self._options.preserve_newlines and newlines > 1: self.print_newline(False, preserve_statement_flags) for i in range(1, newlines): self.print_newline(True, preserve_statement_flags) def unpack(self, source, evalcode=False): import jsbeautifier.unpackers as unpackers try: return unpackers.run(source, evalcode) except unpackers.UnpackingError: return source def is_array(self, mode): return mode == MODE.ArrayLiteral def is_expression(self, mode): return ( mode == MODE.Expression or mode == MODE.ForInitializer or mode == MODE.Conditional ) _newline_restricted_tokens = frozenset( ["async", "break", "continue", "return", "throw", "yield"] ) def allow_wrap_or_preserved_newline(self, current_token, force_linewrap=False): # never wrap the first token of a line. if self._output.just_added_newline(): return shouldPreserveOrForce = ( self._options.preserve_newlines and current_token.newlines ) or force_linewrap operatorLogicApplies = ( self._flags.last_token.text in Tokenizer.positionable_operators or current_token.text in Tokenizer.positionable_operators ) if operatorLogicApplies: shouldPrintOperatorNewline = ( self._flags.last_token.text in Tokenizer.positionable_operators and self._options.operator_position in OPERATOR_POSITION_BEFORE_OR_PRESERVE ) or current_token.text in Tokenizer.positionable_operators shouldPreserveOrForce = shouldPreserveOrForce and shouldPrintOperatorNewline if shouldPreserveOrForce: self.print_newline(preserve_statement_flags=True) elif self._options.wrap_line_length > 0: if reserved_array(self._flags.last_token, self._newline_restricted_tokens): # These tokens should never have a newline inserted between # them and the following expression. return self._output.set_wrap_point() def print_newline(self, force_newline=False, preserve_statement_flags=False): if not preserve_statement_flags: if ( self._flags.last_token.text != ";" and self._flags.last_token.text != "," and self._flags.last_token.text != "=" and ( self._flags.last_token.type != TOKEN.OPERATOR or self._flags.last_token.text == "--" or self._flags.last_token.text == "++" ) ): next_token = self._tokens.peek() while ( self._flags.mode == MODE.Statement and not (self._flags.if_block and reserved_word(next_token, "else")) and not self._flags.do_block ): self.restore_mode() if self._output.add_new_line(force_newline): self._flags.multiline_frame = True def print_token_line_indentation(self, current_token): if self._output.just_added_newline(): line = self._output.current_line if ( self._options.keep_array_indentation and current_token.newlines and (self.is_array(self._flags.mode) or current_token.text == "[") ): line.set_indent(-1) line.push(current_token.whitespace_before) self._output.space_before_token = False elif self._output.set_indent( self._flags.indentation_level, self._flags.alignment ): self._flags.line_indent_level = self._flags.indentation_level def print_token(self, current_token, s=None): if self._output.raw: self._output.add_raw_token(current_token) return if ( self._options.comma_first and current_token.previous and current_token.previous.type == TOKEN.COMMA and self._output.just_added_newline() ): if self._output.previous_line.last() == ",": # if the comma was already at the start of the line, # pull back onto that line and reprint the indentation popped = self._output.previous_line.pop() if self._output.previous_line.is_empty(): self._output.previous_line.push(popped) self._output.trim(True) self._output.current_line.pop() self._output.trim() # add the comma in front of the next token self.print_token_line_indentation(current_token) self._output.add_token(",") self._output.space_before_token = True if s is None: s = current_token.text self.print_token_line_indentation(current_token) self._output.non_breaking_space = True self._output.add_token(s) if self._output.previous_token_wrapped: self._flags.multiline_frame = True def indent(self): self._flags.indentation_level += 1 self._output.set_indent(self._flags.indentation_level, self._flags.alignment) def deindent(self): allow_deindent = self._flags.indentation_level > 0 and ( (self._flags.parent is None) or self._flags.indentation_level > self._flags.parent.indentation_level ) if allow_deindent: self._flags.indentation_level -= 1 self._output.set_indent(self._flags.indentation_level, self._flags.alignment) def set_mode(self, mode): if self._flags: self._flag_store.append(self._flags) self._previous_flags = self._flags else: self._previous_flags = BeautifierFlags(mode) self._flags = BeautifierFlags(mode) self._flags.apply_base(self._previous_flags, self._output.just_added_newline()) self._flags.start_line_index = self._output.get_line_number() self._output.set_indent(self._flags.indentation_level, self._flags.alignment) def restore_mode(self): if len(self._flag_store) > 0: self._previous_flags = self._flags self._flags = self._flag_store.pop() if self._previous_flags.mode == MODE.Statement: remove_redundant_indentation(self._output, self._previous_flags) self._output.set_indent(self._flags.indentation_level, self._flags.alignment) def start_of_object_property(self): return ( self._flags.parent.mode == MODE.ObjectLiteral and self._flags.mode == MODE.Statement and ( (self._flags.last_token.text == ":" and self._flags.ternary_depth == 0) or (reserved_array(self._flags.last_token, ["get", "set"])) ) ) def start_of_statement(self, current_token): start = False start = start or ( reserved_array(self._flags.last_token, ["var", "let", "const"]) and current_token.type == TOKEN.WORD ) start = start or reserved_word(self._flags.last_token, "do") start = start or ( not ( self._flags.parent.mode == MODE.ObjectLiteral and self._flags.mode == MODE.Statement ) and reserved_array(self._flags.last_token, self._newline_restricted_tokens) and not current_token.newlines ) start = start or ( reserved_word(self._flags.last_token, "else") and not ( reserved_word(current_token, "if") and current_token.comments_before is None ) ) start = start or ( self._flags.last_token.type == TOKEN.END_EXPR and ( self._previous_flags.mode == MODE.ForInitializer or self._previous_flags.mode == MODE.Conditional ) ) start = start or ( self._flags.last_token.type == TOKEN.WORD and self._flags.mode == MODE.BlockStatement and not self._flags.in_case and not (current_token.text == "--" or current_token.text == "++") and self._last_last_text != "function" and current_token.type != TOKEN.WORD and current_token.type != TOKEN.RESERVED ) start = start or ( self._flags.mode == MODE.ObjectLiteral and ( (self._flags.last_token.text == ":" and self._flags.ternary_depth == 0) or (reserved_array(self._flags.last_token, ["get", "set"])) ) ) if start: self.set_mode(MODE.Statement) self.indent() self.handle_whitespace_and_comments(current_token, True) # Issue #276: # If starting a new statement with [if, for, while, do], push to a new line. # if (a) if (b) if(c) d(); else e(); else f(); if not self.start_of_object_property(): self.allow_wrap_or_preserved_newline( current_token, reserved_array(current_token, ["do", "for", "if", "while"]), ) return True else: return False def handle_start_expr(self, current_token): if self.start_of_statement(current_token): # The conditional starts the statement if appropriate. pass else: self.handle_whitespace_and_comments(current_token) next_mode = MODE.Expression if current_token.text == "[": if ( self._flags.last_token.type == TOKEN.WORD or self._flags.last_token.text == ")" ): if reserved_array(self._flags.last_token, Tokenizer.line_starters): self._output.space_before_token = True self.print_token(current_token) self.set_mode(next_mode) self.indent() if self._options.space_in_paren: self._output.space_before_token = True return next_mode = MODE.ArrayLiteral if self.is_array(self._flags.mode): if self._flags.last_token.text == "[" or ( self._flags.last_token.text == "," and (self._last_last_text == "]" or self._last_last_text == "}") ): # ], [ goes to a new line # }, [ goes to a new line if not self._options.keep_array_indentation: self.print_newline() if self._flags.last_token.type not in [ TOKEN.START_EXPR, TOKEN.END_EXPR, TOKEN.WORD, TOKEN.OPERATOR, TOKEN.DOT, ]: self._output.space_before_token = True else: if self._flags.last_token.type == TOKEN.RESERVED: if self._flags.last_token.text == "for": self._output.space_before_token = ( self._options.space_before_conditional ) next_mode = MODE.ForInitializer elif self._flags.last_token.text in ["if", "while", "switch"]: self._output.space_before_token = ( self._options.space_before_conditional ) next_mode = MODE.Conditional elif self._flags.last_word in ["await", "async"]: # Should be a space between await and an IIFE, or async and # an arrow function self._output.space_before_token = True elif ( self._flags.last_token.text == "import" and current_token.whitespace_before == "" ): self._output.space_before_token = False elif ( self._flags.last_token.text in Tokenizer.line_starters or self._flags.last_token.text == "catch" ): self._output.space_before_token = True elif self._flags.last_token.type in [TOKEN.EQUALS, TOKEN.OPERATOR]: # Support of this kind of newline preservation: # a = (b && # (c || d)); if not self.start_of_object_property(): self.allow_wrap_or_preserved_newline(current_token) elif self._flags.last_token.type == TOKEN.WORD: self._output.space_before_token = False # function name() vs function name () # function* name() vs function* name () # async name() vs async name () # In ES6, you can also define the method properties of an object # var obj = {a: function() {}} # It can be abbreviated # var obj = {a() {}} # var obj = { a() {}} vs var obj = { a () {}} # var obj = { * a() {}} vs var obj = { * a () {}} peek_back_two = self._tokens.peek(-3) if self._options.space_after_named_function and peek_back_two: # peek starts at next character so -1 is current token peek_back_three = self._tokens.peek(-4) if reserved_array(peek_back_two, ["async", "function"]) or ( peek_back_two.text == "*" and reserved_array(peek_back_three, ["async", "function"]) ): self._output.space_before_token = True elif self._flags.mode == MODE.ObjectLiteral: if (peek_back_two.text == "{" or peek_back_two.text == ",") or ( peek_back_two.text == "*" and ( peek_back_three.text == "{" or peek_back_three.text == "," ) ): self._output.space_before_token = True elif self._flags.parent and self._flags.parent.class_start_block: self._output.space_before_token = True else: # Support preserving wrapped arrow function expressions # a.b('c', # () => d.e # ) self.allow_wrap_or_preserved_newline(current_token) # function() vs function (), typeof() vs typeof () # function*() vs function* (), yield*() vs yield* () if ( self._flags.last_token.type == TOKEN.RESERVED and ( self._flags.last_word == "function" or self._flags.last_word == "typeof" ) ) or ( self._flags.last_token.text == "*" and ( self._last_last_text in ["function", "yield"] or ( self._flags.mode == MODE.ObjectLiteral and self._last_last_text in ["{", ","] ) ) ): self._output.space_before_token = ( self._options.space_after_anon_function ) if ( self._flags.last_token.text == ";" or self._flags.last_token.type == TOKEN.START_BLOCK ): self.print_newline() elif ( self._flags.last_token.type in [TOKEN.END_EXPR, TOKEN.START_EXPR, TOKEN.END_BLOCK, TOKEN.COMMA] or self._flags.last_token.text == "." ): # do nothing on (( and )( and ][ and ]( and .( # TODO: Consider whether forcing this is required. Review failing # tests when removed. self.allow_wrap_or_preserved_newline(current_token, current_token.newlines) self.print_token(current_token) self.set_mode(next_mode) if self._options.space_in_paren: self._output.space_before_token = True # In all cases, if we newline while inside an expression it should be # indented. self.indent() def handle_end_expr(self, current_token): # statements inside expressions are not valid syntax, but... # statements must all be closed when their container closes while self._flags.mode == MODE.Statement: self.restore_mode() self.handle_whitespace_and_comments(current_token) if self._flags.multiline_frame: self.allow_wrap_or_preserved_newline( current_token, current_token.text == "]" and self.is_array(self._flags.mode) and not self._options.keep_array_indentation, ) if self._options.space_in_paren: if ( self._flags.last_token.type == TOKEN.START_EXPR and not self._options.space_in_empty_paren ): # empty parens are always "()" and "[]", not "( )" or "[ ]" self._output.space_before_token = False self._output.trim() else: self._output.space_before_token = True self.deindent() self.print_token(current_token) self.restore_mode() remove_redundant_indentation(self._output, self._previous_flags) # do {} while () // no statement required after if self._flags.do_while and self._previous_flags.mode == MODE.Conditional: self._previous_flags.mode = MODE.Expression self._flags.do_block = False self._flags.do_while = False def handle_start_block(self, current_token): self.handle_whitespace_and_comments(current_token) # Check if this is a BlockStatement that should be treated as a # ObjectLiteral next_token = self._tokens.peek() second_token = self._tokens.peek(1) if ( self._flags.last_word == "switch" and self._flags.last_token.type == TOKEN.END_EXPR ): self.set_mode(MODE.BlockStatement) self._flags.in_case_statement = True elif self._flags.case_body: self.set_mode(MODE.BlockStatement) elif second_token is not None and ( ( second_token.text in [":", ","] and next_token.type in [TOKEN.STRING, TOKEN.WORD, TOKEN.RESERVED] ) or ( next_token.text in ["get", "set", "..."] and second_token.type in [TOKEN.WORD, TOKEN.RESERVED] ) ): # We don't support TypeScript,but we didn't break it for a very long time. # We'll try to keep not breaking it. if self._last_last_text in [ "class", "interface", ] and second_token.text not in [":", ","]: self.set_mode(MODE.BlockStatement) else: self.set_mode(MODE.ObjectLiteral) elif ( self._flags.last_token.type == TOKEN.OPERATOR and self._flags.last_token.text == "=>" ): # arrow function: (param1, paramN) => { statements } self.set_mode(MODE.BlockStatement) elif self._flags.last_token.type in [ TOKEN.EQUALS, TOKEN.START_EXPR, TOKEN.COMMA, TOKEN.OPERATOR, ] or reserved_array( self._flags.last_token, ["return", "throw", "import", "default"] ): # Detecting shorthand function syntax is difficult by scanning forward, # so check the surrounding context. # If the block is being returned, imported, export default, passed as arg, # assigned with = or assigned in a nested object, treat as an # ObjectLiteral. self.set_mode(MODE.ObjectLiteral) else: self.set_mode(MODE.BlockStatement) if self._flags.last_token: if reserved_array(self._flags.last_token.previous, ["class", "extends"]): self._flags.class_start_block = True empty_braces = ( (next_token is not None) and next_token.comments_before is None and next_token.text == "}" ) empty_anonymous_function = ( empty_braces and self._flags.last_word == "function" and self._flags.last_token.type == TOKEN.END_EXPR ) if ( self._options.brace_preserve_inline ): # check for inline, set inline_frame if so # search forward for newline wanted inside this block index = 0 check_token = None self._flags.inline_frame = True do_loop = True while do_loop: index += 1 check_token = self._tokens.peek(index - 1) if check_token.newlines: self._flags.inline_frame = False do_loop = check_token.type != TOKEN.EOF and not ( check_token.type == TOKEN.END_BLOCK and check_token.opened == current_token ) if ( self._options.brace_style == "expand" or (self._options.brace_style == "none" and current_token.newlines) ) and not self._flags.inline_frame: if self._flags.last_token.type != TOKEN.OPERATOR and ( empty_anonymous_function or self._flags.last_token.type == TOKEN.EQUALS or ( reserved_array(self._flags.last_token, _special_word_set) and self._flags.last_token.text != "else" ) ): self._output.space_before_token = True else: self.print_newline(preserve_statement_flags=True) else: # collapse || inline_frame if self.is_array(self._previous_flags.mode) and ( self._flags.last_token.type == TOKEN.START_EXPR or self._flags.last_token.type == TOKEN.COMMA ): # if we're preserving inline, # allow newline between comma and next brace. if self._flags.inline_frame: self.allow_wrap_or_preserved_newline(current_token) self._flags.inline_frame = True self._previous_flags.multiline_frame = ( self._previous_flags.multiline_frame or self._flags.multiline_frame ) self._flags.multiline_frame = False elif self._flags.last_token.type == TOKEN.COMMA: self._output.space_before_token = True elif self._flags.last_token.type not in [TOKEN.OPERATOR, TOKEN.START_EXPR]: if ( self._flags.last_token.type in [TOKEN.START_BLOCK, TOKEN.SEMICOLON] and not self._flags.inline_frame ): self.print_newline() else: self._output.space_before_token = True self.print_token(current_token) self.indent() # Except for specific cases, open braces are followed by a new line. if not empty_braces and not ( self._options.brace_preserve_inline and self._flags.inline_frame ): self.print_newline() def handle_end_block(self, current_token): # statements must all be closed when their container closes self.handle_whitespace_and_comments(current_token) while self._flags.mode == MODE.Statement: self.restore_mode() empty_braces = self._flags.last_token.type == TOKEN.START_BLOCK # try inline_frame (only set if opt.braces-preserve-inline) first if self._flags.inline_frame and not empty_braces: self._output.space_before_token = True elif self._options.brace_style == "expand": if not empty_braces: self.print_newline() else: # skip {} if not empty_braces: if ( self.is_array(self._flags.mode) and self._options.keep_array_indentation ): self._options.keep_array_indentation = False self.print_newline() self._options.keep_array_indentation = True else: self.print_newline() self.restore_mode() self.print_token(current_token) def handle_word(self, current_token): if current_token.type == TOKEN.RESERVED: if ( current_token.text in ["set", "get"] and self._flags.mode != MODE.ObjectLiteral ): current_token.type = TOKEN.WORD elif current_token.text == "import" and self._tokens.peek().text in [ "(", ".", ]: current_token.type = TOKEN.WORD elif current_token.text in ["as", "from"] and not self._flags.import_block: current_token.type = TOKEN.WORD elif self._flags.mode == MODE.ObjectLiteral: next_token = self._tokens.peek() if next_token.text == ":": current_token.type = TOKEN.WORD if self.start_of_statement(current_token): # The conditional starts the statement if appropriate. if ( reserved_array(self._flags.last_token, ["var", "let", "const"]) and current_token.type == TOKEN.WORD ): self._flags.declaration_statement = True elif ( current_token.newlines and not self.is_expression(self._flags.mode) and ( self._flags.last_token.type != TOKEN.OPERATOR or ( self._flags.last_token.text == "--" or self._flags.last_token.text == "++" ) ) and self._flags.last_token.type != TOKEN.EQUALS and ( self._options.preserve_newlines or not reserved_array( self._flags.last_token, ["var", "let", "const", "set", "get"] ) ) ): self.handle_whitespace_and_comments(current_token) self.print_newline() else: self.handle_whitespace_and_comments(current_token) if self._flags.do_block and not self._flags.do_while: if reserved_word(current_token, "while"): # do {} ## while () self._output.space_before_token = True self.print_token(current_token) self._output.space_before_token = True self._flags.do_while = True return else: # do {} should always have while as the next word. # if we don't see the expected while, recover self.print_newline() self._flags.do_block = False # if may be followed by else, or not # Bare/inline ifs are tricky # Need to unwind the modes correctly: if (a) if (b) c(); else d(); else # e(); if self._flags.if_block: if (not self._flags.else_block) and reserved_word(current_token, "else"): self._flags.else_block = True else: while self._flags.mode == MODE.Statement: self.restore_mode() self._flags.if_block = False if self._flags.in_case_statement and reserved_array( current_token, ["case", "default"] ): self.print_newline() if (not self._flags.case_block) and ( self._flags.case_body or self._options.jslint_happy ): self.deindent() self._flags.case_body = False self.print_token(current_token) self._flags.in_case = True return if self._flags.last_token.type in [ TOKEN.COMMA, TOKEN.START_EXPR, TOKEN.EQUALS, TOKEN.OPERATOR, ]: if not self.start_of_object_property() and not ( # start of object property is different for numeric values with +/- prefix operators self._flags.last_token.text in ["+", "-"] and self._last_last_text == ":" and self._flags.parent.mode == MODE.ObjectLiteral ): self.allow_wrap_or_preserved_newline(current_token) if reserved_word(current_token, "function"): if self._flags.last_token.text in ["}", ";"] or ( self._output.just_added_newline() and not ( self._flags.last_token.text in ["(", "[", "{", ":", "=", ","] or self._flags.last_token.type == TOKEN.OPERATOR ) ): # make sure there is a nice clean space of at least one blank line # before a new function definition, except in arrays if ( not self._output.just_added_blankline() and current_token.comments_before is None ): self.print_newline() self.print_newline(True) if ( self._flags.last_token.type == TOKEN.RESERVED or self._flags.last_token.type == TOKEN.WORD ): if reserved_array( self._flags.last_token, ["get", "set", "new", "export"] ) or reserved_array( self._flags.last_token, self._newline_restricted_tokens ): self._output.space_before_token = True elif ( reserved_word(self._flags.last_token, "default") and self._last_last_text == "export" ): self._output.space_before_token = True elif self._flags.last_token.text == "declare": # accomodates Typescript declare function formatting self._output.space_before_token = True else: self.print_newline() elif ( self._flags.last_token.type == TOKEN.OPERATOR or self._flags.last_token.text == "=" ): # foo = function self._output.space_before_token = True elif not self._flags.multiline_frame and ( self.is_expression(self._flags.mode) or self.is_array(self._flags.mode) ): # (function pass else: self.print_newline() self.print_token(current_token) self._flags.last_word = current_token.text return prefix = "NONE" if self._flags.last_token.type == TOKEN.END_BLOCK: if self._previous_flags.inline_frame: prefix = "SPACE" elif not reserved_array( current_token, ["else", "catch", "finally", "from"] ): prefix = "NEWLINE" else: if self._options.brace_style in ["expand", "end-expand"] or ( self._options.brace_style == "none" and current_token.newlines ): prefix = "NEWLINE" else: prefix = "SPACE" self._output.space_before_token = True elif ( self._flags.last_token.type == TOKEN.SEMICOLON and self._flags.mode == MODE.BlockStatement ): # TODO: Should this be for STATEMENT as well? prefix = "NEWLINE" elif self._flags.last_token.type == TOKEN.SEMICOLON and self.is_expression( self._flags.mode ): prefix = "SPACE" elif self._flags.last_token.type == TOKEN.STRING: prefix = "NEWLINE" elif ( self._flags.last_token.type == TOKEN.RESERVED or self._flags.last_token.type == TOKEN.WORD or ( self._flags.last_token.text == "*" and ( self._last_last_text in ["function", "yield"] or ( self._flags.mode == MODE.ObjectLiteral and self._last_last_text in ["{", ","] ) ) ) ): prefix = "SPACE" elif self._flags.last_token.type == TOKEN.START_BLOCK: if self._flags.inline_frame: prefix = "SPACE" else: prefix = "NEWLINE" elif self._flags.last_token.type == TOKEN.END_EXPR: self._output.space_before_token = True prefix = "NEWLINE" if ( reserved_array(current_token, Tokenizer.line_starters) and self._flags.last_token.text != ")" ): if ( self._flags.inline_frame or self._flags.last_token.text == "else " or self._flags.last_token.text == "export" ): prefix = "SPACE" else: prefix = "NEWLINE" if reserved_array(current_token, ["else", "catch", "finally"]): if ( ( not ( self._flags.last_token.type == TOKEN.END_BLOCK and self._previous_flags.mode == MODE.BlockStatement ) ) or self._options.brace_style == "expand" or self._options.brace_style == "end-expand" or (self._options.brace_style == "none" and current_token.newlines) ) and not self._flags.inline_frame: self.print_newline() else: self._output.trim(True) # If we trimmed and there's something other than a close block before us # put a newline back in. Handles '} // comment' scenario. if self._output.current_line.last() != "}": self.print_newline() self._output.space_before_token = True elif prefix == "NEWLINE": if reserved_array(self._flags.last_token, _special_word_set): # no newline between return nnn self._output.space_before_token = True elif self._flags.last_token.text == "declare" and reserved_array( current_token, ["var", "let", "const"] ): # accomodates Typescript declare formatting self._output.space_before_token = True elif self._flags.last_token.type != TOKEN.END_EXPR: if ( self._flags.last_token.type != TOKEN.START_EXPR or not (reserved_array(current_token, ["var", "let", "const"])) ) and self._flags.last_token.text != ":": # no need to force newline on VAR - # for (var x = 0... if ( reserved_word(current_token, "if") and self._flags.last_token.text == "else" ): self._output.space_before_token = True else: self.print_newline() elif ( reserved_array(current_token, Tokenizer.line_starters) and self._flags.last_token.text != ")" ): self.print_newline() elif ( self._flags.multiline_frame and self.is_array(self._flags.mode) and self._flags.last_token.text == "," and self._last_last_text == "}" ): self.print_newline() # }, in lists get a newline elif prefix == "SPACE": self._output.space_before_token = True if current_token.previous and ( current_token.previous.type == TOKEN.WORD or current_token.previous.type == TOKEN.RESERVED ): self._output.space_before_token = True self.print_token(current_token) self._flags.last_word = current_token.text if current_token.type == TOKEN.RESERVED: if current_token.text == "do": self._flags.do_block = True elif current_token.text == "if": self._flags.if_block = True elif current_token.text == "import": self._flags.import_block = True elif current_token.text == "from" and self._flags.import_block: self._flags.import_block = False def handle_semicolon(self, current_token): if self.start_of_statement(current_token): # The conditional starts the statement if appropriate. # Semicolon can be the start (and end) of a statement self._output.space_before_token = False else: self.handle_whitespace_and_comments(current_token) next_token = self._tokens.peek() while ( self._flags.mode == MODE.Statement and not (self._flags.if_block and reserved_word(next_token, "else")) and not self._flags.do_block ): self.restore_mode() if self._flags.import_block: self._flags.import_block = False self.print_token(current_token) def handle_string(self, current_token): if ( current_token.text[0] == "`" and current_token.newlines == 0 and current_token.whitespace_before == "" and ( self._flags.last_token.type == TOKEN.WORD or current_token.previous.text == ")" ) ): # This conditional checks backtick strings and makes no changes pass elif self.start_of_statement(current_token): # The conditional starts the statement if appropriate. # One difference - strings want at least a space before self._output.space_before_token = True else: self.handle_whitespace_and_comments(current_token) if ( self._flags.last_token.type in [TOKEN.RESERVED, TOKEN.WORD] or self._flags.inline_frame ): self._output.space_before_token = True elif self._flags.last_token.type in [ TOKEN.COMMA, TOKEN.START_EXPR, TOKEN.EQUALS, TOKEN.OPERATOR, ]: if not self.start_of_object_property(): self.allow_wrap_or_preserved_newline(current_token) elif ( current_token.text[0] == "`" and self._flags.last_token.type == TOKEN.END_EXPR and current_token.previous.text in ["]", ")"] and current_token.newlines == 0 ): self._output.space_before_token = True else: self.print_newline() self.print_token(current_token) def handle_equals(self, current_token): if self.start_of_statement(current_token): # The conditional starts the statement if appropriate. pass else: self.handle_whitespace_and_comments(current_token) if self._flags.declaration_statement: # just got an '=' in a var-line, different line breaking rules will # apply self._flags.declaration_assignment = True self._output.space_before_token = True self.print_token(current_token) self._output.space_before_token = True def handle_comma(self, current_token): self.handle_whitespace_and_comments(current_token, True) self.print_token(current_token) self._output.space_before_token = True if self._flags.declaration_statement: if self.is_expression(self._flags.parent.mode): # do not break on comma, for ( var a = 1, b = 2 self._flags.declaration_assignment = False if self._flags.declaration_assignment: self._flags.declaration_assignment = False self.print_newline(preserve_statement_flags=True) elif self._options.comma_first: # for comma-first, we want to allow a newline before the comma # to turn into a newline after the comma, which we will fixup # later self.allow_wrap_or_preserved_newline(current_token) elif self._flags.mode == MODE.ObjectLiteral or ( self._flags.mode == MODE.Statement and self._flags.parent.mode == MODE.ObjectLiteral ): if self._flags.mode == MODE.Statement: self.restore_mode() if not self._flags.inline_frame: self.print_newline() elif self._options.comma_first: # EXPR or DO_BLOCK # for comma-first, we want to allow a newline before the comma # to turn into a newline after the comma, which we will fixup later self.allow_wrap_or_preserved_newline(current_token) def handle_operator(self, current_token): isGeneratorAsterisk = current_token.text == "*" and ( reserved_array(self._flags.last_token, ["function", "yield"]) or ( self._flags.last_token.type in [TOKEN.START_BLOCK, TOKEN.COMMA, TOKEN.END_BLOCK, TOKEN.SEMICOLON] ) ) isUnary = current_token.text in ["+", "-"] and ( self._flags.last_token.type in [TOKEN.START_BLOCK, TOKEN.START_EXPR, TOKEN.EQUALS, TOKEN.OPERATOR] or self._flags.last_token.text in Tokenizer.line_starters or self._flags.last_token.text == "," ) if self.start_of_statement(current_token): # The conditional starts the statement if appropriate. pass else: preserve_statement_flags = not isGeneratorAsterisk self.handle_whitespace_and_comments(current_token, preserve_statement_flags) # hack for actionscript's import .*; if current_token.text == "*" and self._flags.last_token.type == TOKEN.DOT: self.print_token(current_token) return if current_token.text == "::": # no spaces around the exotic namespacing syntax operator self.print_token(current_token) return if current_token.text in ["-", "+"] and self.start_of_object_property(): # numeric value with +/- symbol in front as a property self.print_token(current_token) return # Allow line wrapping between operators when operator_position is # set to before or preserve if ( self._flags.last_token.type == TOKEN.OPERATOR and self._options.operator_position in OPERATOR_POSITION_BEFORE_OR_PRESERVE ): self.allow_wrap_or_preserved_newline(current_token) if current_token.text == ":" and self._flags.in_case: self.print_token(current_token) self._flags.in_case = False self._flags.case_body = True if self._tokens.peek().type != TOKEN.START_BLOCK: self.indent() self.print_newline() self._flags.case_block = False else: self._output.space_before_token = True self._flags.case_block = True return space_before = True space_after = True in_ternary = False if current_token.text == ":": if self._flags.ternary_depth == 0: # Colon is invalid javascript outside of ternary and object, # but do our best to guess what was meant. space_before = False else: self._flags.ternary_depth -= 1 in_ternary = True elif current_token.text == "?": self._flags.ternary_depth += 1 # let's handle the operator_position option prior to any conflicting # logic if ( (not isUnary) and (not isGeneratorAsterisk) and self._options.preserve_newlines and current_token.text in Tokenizer.positionable_operators ): isColon = current_token.text == ":" isTernaryColon = isColon and in_ternary isOtherColon = isColon and not in_ternary if self._options.operator_position == OPERATOR_POSITION["before_newline"]: # if the current token is : and it's not a ternary statement # then we set space_before to false self._output.space_before_token = not isOtherColon self.print_token(current_token) if (not isColon) or isTernaryColon: self.allow_wrap_or_preserved_newline(current_token) self._output.space_before_token = True return elif self._options.operator_position == OPERATOR_POSITION["after_newline"]: # if the current token is anything but colon, or (via deduction) it's a colon and in a ternary statement, # then print a newline. self._output.space_before_token = True if (not isColon) or isTernaryColon: if self._tokens.peek().newlines: self.print_newline(preserve_statement_flags=True) else: self.allow_wrap_or_preserved_newline(current_token) else: self._output.space_before_token = False self.print_token(current_token) self._output.space_before_token = True return elif ( self._options.operator_position == OPERATOR_POSITION["preserve_newline"] ): if not isOtherColon: self.allow_wrap_or_preserved_newline(current_token) # if we just added a newline, or the current token is : and it's not a ternary statement, # then we set space_before to false self._output.space_before_token = not ( self._output.just_added_newline() or isOtherColon ) self.print_token(current_token) self._output.space_before_token = True return if isGeneratorAsterisk: self.allow_wrap_or_preserved_newline(current_token) space_before = False next_token = self._tokens.peek() space_after = next_token and next_token.type in [TOKEN.WORD, TOKEN.RESERVED] elif current_token.text == "...": self.allow_wrap_or_preserved_newline(current_token) space_before = self._flags.last_token.type == TOKEN.START_BLOCK space_after = False elif current_token.text in ["--", "++", "!", "~"] or isUnary: if ( self._flags.last_token.type == TOKEN.COMMA or self._flags.last_token.type == TOKEN.START_EXPR ): self.allow_wrap_or_preserved_newline(current_token) space_before = False space_after = False # http://www.ecma-international.org/ecma-262/5.1/#sec-7.9.1 # if there is a newline between -- or ++ and anything else we # should preserve it. if current_token.newlines and ( current_token.text == "--" or current_token.text == "++" or current_token.text == "~" ): new_line_needed = ( reserved_array(self._flags.last_token, _special_word_set) and current_token.newlines ) if new_line_needed and ( self._previous_flags.if_block or self._previous_flags.else_block ): self.restore_mode() self.print_newline(new_line_needed, True) if self._flags.last_token.text == ";" and self.is_expression( self._flags.mode ): # for (;; ++i) # ^^ space_before = True if self._flags.last_token.type == TOKEN.RESERVED: space_before = True elif self._flags.last_token.type == TOKEN.END_EXPR: space_before = not ( self._flags.last_token.text == "]" and current_token.text in ["--", "++"] ) elif self._flags.last_token.type == TOKEN.OPERATOR: # a++ + ++b # a - -b space_before = current_token.text in [ "--", "-", "++", "+", ] and self._flags.last_token.text in ["--", "-", "++", "+"] # + and - are not unary when preceeded by -- or ++ operator # a-- + b # a * +b # a - -b if current_token.text in ["-", "+"] and self._flags.last_token.text in [ "--", "++", ]: space_after = True if ( ( self._flags.mode == MODE.BlockStatement and not self._flags.inline_frame ) or self._flags.mode == MODE.Statement ) and self._flags.last_token.text in ["{", ";"]: # { foo: --i } # foo(): --bar self.print_newline() if space_before: self._output.space_before_token = True self.print_token(current_token) if space_after: self._output.space_before_token = True def handle_block_comment(self, current_token, preserve_statement_flags): if self._output.raw: self._output.add_raw_token(current_token) if ( current_token.directives and current_token.directives.get("preserve") == "end" ): # If we're testing the raw output behavior, do not allow a # directive to turn it off. self._output.raw = self._options.test_output_raw return if current_token.directives: self.print_newline(preserve_statement_flags=preserve_statement_flags) self.print_token(current_token) if current_token.directives.get("preserve") == "start": self._output.raw = True self.print_newline(preserve_statement_flags=True) return # inline block if ( not self.acorn.newline.search(current_token.text) and not current_token.newlines ): self._output.space_before_token = True self.print_token(current_token) self._output.space_before_token = True return lines = self.acorn.allLineBreaks.split(current_token.text) javadoc = False starless = False last_indent = current_token.whitespace_before last_indent_length = len(last_indent) # block comment starts with a new line self.print_newline(preserve_statement_flags=preserve_statement_flags) # first line always indented self.print_token(current_token, lines[0]) self.print_newline(preserve_statement_flags=preserve_statement_flags) if len(lines) > 1: lines = lines[1:] javadoc = not any( l for l in lines if (l.strip() == "" or (l.lstrip())[0] != "*") ) starless = all(l.startswith(last_indent) or l.strip() == "" for l in lines) if javadoc: self._flags.alignment = 1 for line in lines: if javadoc: # javadoc: reformat and re-indent self.print_token(current_token, line.lstrip()) elif starless and len(line) > last_indent_length: # starless: re-indent non-empty content, avoiding trim self.print_token(current_token, line[last_indent_length:]) else: # normal comments output raw self._output.current_line.set_indent(-1) self._output.add_token(line) # for comments on their own line or more than one line, # make sure there's a new line after self.print_newline(preserve_statement_flags=preserve_statement_flags) self._flags.alignment = 0 def handle_comment(self, current_token, preserve_statement_flags): if current_token.newlines: self.print_newline(preserve_statement_flags=preserve_statement_flags) if not current_token.newlines: self._output.trim(True) self._output.space_before_token = True self.print_token(current_token) self.print_newline(preserve_statement_flags=preserve_statement_flags) def handle_dot(self, current_token): if self.start_of_statement(current_token): # The conditional starts the statement if appropriate. pass else: self.handle_whitespace_and_comments(current_token, True) if re.search("^([0-9])+$", self._flags.last_token.text): self._output.space_before_token = True if reserved_array(self._flags.last_token, _special_word_set): self._output.space_before_token = False else: # allow preserved newlines before dots in general # force newlines on dots after close paren when break_chained - for # bar().baz() self.allow_wrap_or_preserved_newline( current_token, self._flags.last_token.text == ")" and self._options.break_chained_methods, ) # Only unindent chained method dot if this dot starts a new line. # Otherwise the automatic extra indentation removal # will handle any over indent if self._options.unindent_chained_methods and self._output.just_added_newline(): self.deindent() self.print_token(current_token) def handle_unknown(self, current_token, preserve_statement_flags): self.print_token(current_token) if current_token.text[-1] == "\n": self.print_newline(preserve_statement_flags=preserve_statement_flags) def handle_eof(self, current_token): # Unwind any open statements while self._flags.mode == MODE.Statement: self.restore_mode() self.handle_whitespace_and_comments(current_token) python-jsbeautifier-1.15.3/jsbeautifier/javascript/options.py000066400000000000000000000106061475627451400245050ustar00rootroot00000000000000# The MIT License (MIT) # # Copyright (c) 2007-2018 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. from ..core.options import Options as BaseOptions OPERATOR_POSITION = ["before-newline", "after-newline", "preserve-newline"] class BeautifierOptions(BaseOptions): def __init__(self, options=None): BaseOptions.__init__(self, options, "js") self.css = None self.js = None self.html = None # compatibility, re raw_brace_style = getattr(self.raw_options, "brace_style", None) if raw_brace_style == "expand-strict": # graceful handling of deprecated option setattr(self.raw_options, "brace_style", "expand") elif ( raw_brace_style == "collapse-preserve-inline" ): # graceful handling of deprecated option setattr(self.raw_options, "brace_style", "collapse,preserve-inline") # elif bool(self.raw_options.braces_on_own_line): # graceful handling of deprecated option # raw_brace_style = "expand": "collapse" # elif raw_brace_style is None: # Nothing exists to set it # setattr(self.raw_options, 'brace_style', "collapse") # preserve-inline in delimited string will trigger brace_preserve_inline, everything # else is considered a brace_style and the last one only will have an effect brace_style_split = self._get_selection_list( "brace_style", ["collapse", "expand", "end-expand", "none", "preserve-inline"], ) # preserve-inline in delimited string will trigger brace_preserve_inline # Everything else is considered a brace_style and the last one only will # have an effect # specify defaults in case one half of meta-option is missing self.brace_preserve_inline = False self.brace_style = "collapse" for bs in brace_style_split: if bs == "preserve-inline": self.brace_preserve_inline = True else: self.brace_style = bs self.unindent_chained_methods = self._get_boolean("unindent_chained_methods") self.break_chained_methods = self._get_boolean("break_chained_methods") self.space_in_paren = self._get_boolean("space_in_paren") self.space_in_empty_paren = self._get_boolean("space_in_empty_paren") self.jslint_happy = self._get_boolean("jslint_happy") self.space_after_anon_function = self._get_boolean("space_after_anon_function") self.space_after_named_function = self._get_boolean( "space_after_named_function" ) self.keep_array_indentation = self._get_boolean("keep_array_indentation") self.space_before_conditional = self._get_boolean( "space_before_conditional", True ) self.unescape_strings = self._get_boolean("unescape_strings") self.e4x = self._get_boolean("e4x") self.comma_first = self._get_boolean("comma_first") self.operator_position = self._get_selection( "operator_position", OPERATOR_POSITION ) # For testing of beautify preserve:start directive self.test_output_raw = False # force opts.space_after_anon_function to true if opts.jslint_happy if self.jslint_happy: self.space_after_anon_function = True self.keep_quiet = False self.eval_code = False python-jsbeautifier-1.15.3/jsbeautifier/javascript/tokenizer.py000066400000000000000000000545101475627451400250260ustar00rootroot00000000000000# The MIT License (MIT) # # Copyright (c) 2007-2018 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 re from ..core.inputscanner import InputScanner from ..core.tokenizer import TokenTypes as BaseTokenTypes from ..core.tokenizer import Tokenizer as BaseTokenizer from ..core.tokenizer import TokenizerPatterns as BaseTokenizerPatterns from ..core.directives import Directives from ..core.pattern import Pattern from ..core.templatablepattern import TemplatablePattern __all__ = ["TOKEN", "Tokenizer", "TokenTypes"] class TokenTypes(BaseTokenTypes): START_EXPR = "TK_START_EXPR" END_EXPR = "TK_END_EXPR" START_BLOCK = "TK_START_BLOCK" END_BLOCK = "TK_END_BLOCK" WORD = "TK_WORD" RESERVED = "TK_RESERVED" SEMICOLON = "TK_SEMICOLON" STRING = "TK_STRING" EQUALS = "TK_EQUALS" OPERATOR = "TK_OPERATOR" COMMA = "TK_COMMA" BLOCK_COMMENT = "TK_BLOCK_COMMENT" COMMENT = "TK_COMMENT" DOT = "TK_DOT" UNKNOWN = "TK_UNKNOWN" def __init__(self): pass TOKEN = TokenTypes() dot_pattern = re.compile(r"[^\d\.]") number_pattern = re.compile( r"0[xX][0123456789abcdefABCDEF_]*n?|0[oO][01234567_]*n?|0[bB][01_]*n?|\d[\d_]*n|(?:\.\d[\d_]*|\d[\d_]*\.?[\d_]*)(?:[eE][+-]?[\d_]+)?" ) digit = re.compile(r"[0-9]") positionable_operators = frozenset( ( ">>> === !== &&= ??= ||= " + "<< && >= ** != == <= >> || ?? |> " + "< / - + > : & % ? ^ | *" ).split(" ") ) punct = ( ">>>= " + "... >>= <<= === >>> !== **= &&= ??= ||= " + "=> ^= :: /= << <= == && -= >= >> != -- += ** || ?? ++ %= &= *= |= |> " + "= ! ? > < : / ^ - + * & % ~ |" ) punct = re.compile(r"([-[\]{}()*+?.,\\^$|#])").sub(r"\\\1", punct) # ?. but not if followed by a number punct = "\\?\\.(?!\\d) " + punct punct = punct.replace(" ", "|") punct_pattern = re.compile(punct) # Words which always should start on a new line line_starters = frozenset( ( "continue,try,throw,return,var,let,const,if,switch,case,default,for," + "while,break,function,import,export" ).split(",") ) reserved_words = line_starters | frozenset( [ "do", "in", "of", "else", "get", "set", "new", "catch", "finally", "typeof", "yield", "async", "await", "from", "as", "class", "extends", ] ) reserved_word_pattern = re.compile(r"^(?:" + "|".join(reserved_words) + r")$") directives_core = Directives(r"/\*", r"\*/") xmlRegExp = re.compile( r'[\s\S]*?<(\/?)([-a-zA-Z:0-9_.]+|{[^}]+?}|!\[CDATA\[[^\]]*?\]\]|)(\s*{[^}]+?}|\s+[-a-zA-Z:0-9_.]+|\s+[-a-zA-Z:0-9_.]+\s*=\s*(\'[^\']*\'|"[^"]*"|{([^{}]|{[^}]+?})+?}))*\s*(\/?)\s*>' ) class TokenizerPatterns(BaseTokenizerPatterns): def __init__(self, input_scanner, acorn, options): BaseTokenizerPatterns.__init__(self, input_scanner) # 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. six = __import__("six") # IMPORTANT: This string must be run through six to handle \u chars self.whitespace = self.whitespace.matching( six.u(r"\u00A0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff"), six.u(r"\u2028\u2029"), ) pattern = Pattern(input_scanner) templatable = TemplatablePattern(input_scanner).read_options(options) self.identifier = templatable.starting_with(acorn.identifier).matching( acorn.identifierMatch ) self.number = pattern.matching(number_pattern) self.punct = pattern.matching(punct_pattern) self.comment = pattern.starting_with(r"//").until(six.u(r"[\n\r\u2028\u2029]")) self.block_comment = pattern.starting_with(r"/\*").until_after(r"\*/") self.html_comment_start = pattern.matching(r"") self.include = pattern.starting_with(r"#include").until_after(acorn.lineBreak) self.shebang = pattern.starting_with(r"#!").until_after(acorn.lineBreak) self.xml = pattern.matching(xmlRegExp) self.single_quote = templatable.until(six.u(r"['\\\n\r\u2028\u2029]")) self.double_quote = templatable.until(six.u(r'["\\\n\r\u2028\u2029]')) self.template_text = templatable.until(r"[`\\$]") self.template_expression = templatable.until(r"[`}\\]") class Tokenizer(BaseTokenizer): positionable_operators = positionable_operators line_starters = line_starters def __init__(self, input_string, opts): BaseTokenizer.__init__(self, input_string, opts) import jsbeautifier.javascript.acorn as acorn self.acorn = acorn self.in_html_comment = False self.has_char_escapes = False self._patterns = TokenizerPatterns(self._input, self.acorn, opts) def _reset(self): self.in_html_comment = False def _is_comment(self, current_token): return ( current_token.type == TOKEN.COMMENT or current_token.type == TOKEN.BLOCK_COMMENT or current_token.type == TOKEN.UNKNOWN ) def _is_opening(self, current_token): return ( current_token.type == TOKEN.START_BLOCK or current_token.type == TOKEN.START_EXPR ) def _is_closing(self, current_token, open_token): return ( current_token.type == TOKEN.END_BLOCK or current_token.type == TOKEN.END_EXPR ) and ( open_token is not None and ( (current_token.text == "]" and open_token.text == "[") or (current_token.text == ")" and open_token.text == "(") or (current_token.text == "}" and open_token.text == "{") ) ) def _get_next_token(self, previous_token, open_token): token = None self._readWhitespace() c = self._input.peek() if c is None: token = self._create_token(TOKEN.EOF, "") token = token or self._read_non_javascript(c) token = token or self._read_string(c) token = token or self._read_pair( c, self._input.peek(1) ) # Issue #2062 hack for record type '#{' token = token or self._read_word(previous_token) token = token or self._read_singles(c) token = token or self._read_comment(c) token = token or self._read_regexp(c, previous_token) token = token or self._read_xml(c, previous_token) token = token or self._read_punctuation() token = token or self._create_token(TOKEN.UNKNOWN, self._input.next()) return token def _read_singles(self, c): token = None if c == "(" or c == "[": token = self._create_token(TOKEN.START_EXPR, c) elif c == ")" or c == "]": token = self._create_token(TOKEN.END_EXPR, c) elif c == "{": token = self._create_token(TOKEN.START_BLOCK, c) elif c == "}": token = self._create_token(TOKEN.END_BLOCK, c) elif c == ";": token = self._create_token(TOKEN.SEMICOLON, c) elif ( c == "." and self._input.peek(1) is not None and bool(dot_pattern.match(self._input.peek(1))) ): token = self._create_token(TOKEN.DOT, c) elif c == ",": token = self._create_token(TOKEN.COMMA, c) if token is not None: self._input.next() return token def _read_pair(self, c, d): token = None if c == "#" and d == "{": token = self._create_token(TOKEN.START_BLOCK, c + d) if token is not None: self._input.next() self._input.next() return token def _read_word(self, previous_token): resulting_string = self._patterns.identifier.read() if bool(resulting_string): resulting_string = re.sub(self.acorn.allLineBreaks, "\n", resulting_string) if not ( previous_token.type == TOKEN.DOT or ( previous_token.type == TOKEN.RESERVED and (previous_token.text == "set" or previous_token.text == "get") ) ) and reserved_word_pattern.match(resulting_string): if (resulting_string == "in" or resulting_string == "of") and ( previous_token.type == TOKEN.WORD or previous_token.type == TOKEN.STRING ): # in and of are operators, need to hack return self._create_token(TOKEN.OPERATOR, resulting_string) return self._create_token(TOKEN.RESERVED, resulting_string) return self._create_token(TOKEN.WORD, resulting_string) resulting_string = self._patterns.number.read() if resulting_string != "": return self._create_token(TOKEN.WORD, resulting_string) def _read_comment(self, c): token = None if c == "/": comment = "" if self._input.peek(1) == "*": # peek /* .. */ comment comment = self._patterns.block_comment.read() directives = directives_core.get_directives(comment) if directives and directives.get("ignore") == "start": comment += directives_core.readIgnored(self._input) comment = re.sub(self.acorn.allLineBreaks, "\n", comment) token = self._create_token(TOKEN.BLOCK_COMMENT, comment) token.directives = directives elif self._input.peek(1) == "/": # peek // comment comment = self._patterns.comment.read() token = self._create_token(TOKEN.COMMENT, comment) return token def _read_string(self, c): if c == "`" or c == "'" or c == '"': resulting_string = self._input.next() self.has_char_escapes = False if c == "`": resulting_string += self.parse_string("`", True, "${") else: resulting_string += self.parse_string(c) if self.has_char_escapes and self._options.unescape_strings: resulting_string = self.unescape_string(resulting_string) if self._input.peek() == c: resulting_string += self._input.next() resulting_string = re.sub(self.acorn.allLineBreaks, "\n", resulting_string) return self._create_token(TOKEN.STRING, resulting_string) return None def _read_regexp(self, c, previous_token): if c == "/" and self.allowRegExOrXML(previous_token): # handle regexp resulting_string = self._input.next() esc = False in_char_class = False while ( self._input.hasNext() and (esc or in_char_class or self._input.peek() != c) and not self._input.testChar(self.acorn.newline) ): resulting_string += self._input.peek() if not esc: esc = self._input.peek() == "\\" if self._input.peek() == "[": in_char_class = True elif self._input.peek() == "]": in_char_class = False else: esc = False self._input.next() if self._input.peek() == c: resulting_string += self._input.next() if c == "/": # regexps may have modifiers /regexp/MOD, so fetch those too # Only [gim] are valid, but if the user puts in garbage, do # what we can to take it. resulting_string += self._input.read(self.acorn.identifier) return self._create_token(TOKEN.STRING, resulting_string) return None def _read_xml(self, c, previous_token): if self._options.e4x and c == "<" and self.allowRegExOrXML(previous_token): # handle e4x xml literals xmlStr = "" match = self._patterns.xml.read_match() if match and not match.group(1): rootTag = match.group(2) rootTag = re.sub(r"^{\s+", "{", re.sub(r"\s+}$", "}", rootTag)) isCurlyRoot = rootTag.startswith("{") depth = 0 while bool(match): isEndTag = match.group(1) tagName = match.group(2) isSingletonTag = (match.groups()[-1] != "") or ( match.group(2)[0:8] == "![CDATA[" ) if not isSingletonTag and ( tagName == rootTag or ( isCurlyRoot and re.sub(r"^{\s+", "{", re.sub(r"\s+}$", "}", tagName)) ) ): if isEndTag: depth -= 1 else: depth += 1 xmlStr += match.group(0) if depth <= 0: break match = self._patterns.xml.read_match() # if we didn't close correctly, keep unformatted. if not match: xmlStr += self._input.match(re.compile(r"[\s\S]*")).group(0) xmlStr = re.sub(self.acorn.allLineBreaks, "\n", xmlStr) return self._create_token(TOKEN.STRING, xmlStr) return None def _read_non_javascript(self, c): resulting_string = "" if c == "#": # she-bang if self._is_first_token(): resulting_string = self._patterns.shebang.read() if resulting_string: return self._create_token( TOKEN.UNKNOWN, resulting_string.strip() + "\n" ) # handles extendscript #includes resulting_string = self._patterns.include.read() if resulting_string: return self._create_token( TOKEN.UNKNOWN, resulting_string.strip() + "\n" ) c = self._input.next() # Spidermonkey-specific sharp variables for circular references # https://developer.mozilla.org/En/Sharp_variables_in_JavaScript # http://mxr.mozilla.org/mozilla-central/source/js/src/jsscan.cpp # around line 1935 sharp = "#" if self._input.hasNext() and self._input.testChar(digit): while True: c = self._input.next() sharp += c if (not self._input.hasNext()) or c == "#" or c == "=": break if c == "#": pass elif self._input.peek() == "[" and self._input.peek(1) == "]": sharp += "[]" self._input.next() self._input.next() elif self._input.peek() == "{" and self._input.peek(1) == "}": sharp += "{}" self._input.next() self._input.next() return self._create_token(TOKEN.WORD, sharp) self._input.back() elif c == "<" and self._is_first_token(): if self._patterns.html_comment_start.read(): c = "") return None def _read_punctuation(self): token = None resulting_string = self._patterns.punct.read() if resulting_string != "": if resulting_string == "=": token = self._create_token(TOKEN.EQUALS, resulting_string) elif resulting_string == "?.": token = self._create_token(TOKEN.DOT, resulting_string) else: token = self._create_token(TOKEN.OPERATOR, resulting_string) return token __regexTokens = { TOKEN.COMMENT, TOKEN.START_EXPR, TOKEN.START_BLOCK, TOKEN.START, TOKEN.END_BLOCK, TOKEN.OPERATOR, TOKEN.EQUALS, TOKEN.EOF, TOKEN.SEMICOLON, TOKEN.COMMA, } def allowRegExOrXML(self, previous_token): return ( ( previous_token.type == TOKEN.RESERVED and previous_token.text in {"return", "case", "throw", "else", "do", "typeof", "yield"} ) or ( previous_token.type == TOKEN.END_EXPR and previous_token.text == ")" and previous_token.opened.previous.type == TOKEN.RESERVED and previous_token.opened.previous.text in {"if", "while", "for"} ) or (previous_token.type in self.__regexTokens) ) def parse_string(self, delimiter, allow_unescaped_newlines=False, start_sub=None): if delimiter == "'": pattern = self._patterns.single_quote elif delimiter == '"': pattern = self._patterns.double_quote elif delimiter == "`": pattern = self._patterns.template_text elif delimiter == "}": pattern = self._patterns.template_expression resulting_string = pattern.read() next = "" while self._input.hasNext(): next = self._input.next() if next == delimiter or ( not allow_unescaped_newlines and self.acorn.newline.match(next) ): self._input.back() break elif next == "\\" and self._input.hasNext(): current_char = self._input.peek() if current_char == "x" or current_char == "u": self.has_char_escapes = True elif current_char == "\r" and self._input.peek(1) == "\n": self._input.next() next += self._input.next() elif start_sub is not None: if start_sub == "${" and next == "$" and self._input.peek() == "{": next += self._input.next() if start_sub == next: if delimiter == "`": next += self.parse_string("}", allow_unescaped_newlines, "`") else: next += self.parse_string("`", allow_unescaped_newlines, "${") if self._input.hasNext(): next += self._input.next() next += pattern.read() resulting_string += next return resulting_string def unescape_string(self, s): # You think that a regex would work for this # return s.replace(/\\x([0-9a-f]{2})/gi, function(match, val) { # return String.fromCharCode(parseInt(val, 16)); # }) # However, dealing with '\xff', '\\xff', '\\\xff' makes this more fun. out = self.acorn.six.u("") escaped = 0 input_scan = InputScanner(s) matched = None while input_scan.hasNext(): # Keep any whitespace, non-slash characters # also keep slash pairs. matched = input_scan.match(re.compile(r"([\s]|[^\\]|\\\\)+")) if matched: out += matched.group(0) if input_scan.peek() != "\\": continue input_scan.next() if input_scan.peek() == "x": matched = input_scan.match(re.compile(r"x([0-9A-Fa-f]{2})")) elif input_scan.peek() == "u": matched = input_scan.match(re.compile(r"u([0-9A-Fa-f]{4})")) if not matched: matched = input_scan.match(re.compile(r"u\{([0-9A-Fa-f]+)\}")) else: out += "\\" if input_scan.hasNext(): out += input_scan.next() continue # If there's some error decoding, return the original string if not matched: return s escaped = int(matched.group(1), 16) if escaped > 0x7E and escaped <= 0xFF and matched.group(0).startswith("x"): # we bail out on \x7f..\xff, # leaving whole string escaped, # as it's probably completely binary return s elif escaped >= 0x00 and escaped < 0x20: # leave 0x00...0x1f escaped out += "\\" + matched.group(0) elif escaped > 0x10FFFF: # If the escape sequence is out of bounds, keep the original sequence and continue conversion out += "\\" + matched.group(0) elif escaped == 0x22 or escaped == 0x27 or escaped == 0x5C: # single-quote, apostrophe, backslash - escape these out += "\\" + chr(escaped) else: out += self.acorn.six.unichr(escaped) return out python-jsbeautifier-1.15.3/jsbeautifier/tests/000077500000000000000000000000001475627451400214315ustar00rootroot00000000000000python-jsbeautifier-1.15.3/jsbeautifier/tests/__init__.py000066400000000000000000000000201475627451400235320ustar00rootroot00000000000000# Empty file :) python-jsbeautifier-1.15.3/jsbeautifier/tests/generated/000077500000000000000000000000001475627451400233675ustar00rootroot00000000000000python-jsbeautifier-1.15.3/jsbeautifier/tests/generated/__init__.py000066400000000000000000000000201475627451400254700ustar00rootroot00000000000000# Empty file :) python-jsbeautifier-1.15.3/jsbeautifier/tests/generated/tests.py000066400000000000000000012152101475627451400251050ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- ''' AUTO-GENERATED. DO NOT MODIFY. Script: test/generate-tests.js Template: test/data/javascript/python.mustache Data: test/data/javascript/tests.js The MIT License (MIT) Copyright (c) 2007-2018 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 re import unittest import jsbeautifier import six import copy class TestJSBeautifier(unittest.TestCase): options = None @classmethod def setUpClass(cls): pass cls.wrapregex = re.compile('^(.+)$', re.MULTILINE) def reset_options(self): true = True false = False default_options = jsbeautifier.default_options() default_options.indent_size = 4 default_options.indent_char = ' ' default_options.preserve_newlines = true default_options.jslint_happy = false default_options.indent_level = 0 default_options.break_chained_methods = false default_options.eol = '\n' default_options.indent_size = 4 default_options.indent_char = ' ' default_options.preserve_newlines = true default_options.jslint_happy = false self.options = copy.copy(default_options) def test_unescape(self): # Test cases contributed by test_fragment = self.decodesto self.reset_options() bt = self.bt def unicode_char(value): return six.unichr(value) bt('"\\\\s"') # == "\\s" in the js source bt("'\\\\s'") # == '\\s' in the js source bt("'\\\\\\s'") # == '\\\s' in the js source bt("'\\s'") # == '\s' in the js source bt('"•"') bt('"—"') bt('"\\x41\\x42\\x43\\x01"', '"\\x41\\x42\\x43\\x01"') bt('"\\u2022"', '"\\u2022"') bt('"\\u{2022}"', '"\\u{2022}"') bt('a = /\\s+/') #bt('a = /\\x41/','a = /A/') bt('"\\u2022";a = /\\s+/;"\\x41\\x42\\x43\\x01".match(/\\x41/);','"\\u2022";\na = /\\s+/;\n"\\x41\\x42\\x43\\x01".match(/\\x41/);') test_fragment('"\\x41\\x42\\x01\\x43"') test_fragment('"\\x41\\x42\\u0001\\x43"') test_fragment('"\\x41\\x42\\u{0001}\\x43"') test_fragment('"\\x20\\x40\\x4a"') test_fragment('"\\xff\\x40\\x4a"') test_fragment('"\\u0072\\u016B\\u0137\\u012B\\u0074\\u0069\\u0073"') test_fragment('"\\u{0072}\\u{016B}\\u{110000}\\u{137}\\u012B\\x74\\u{0000069}\\u{073}"') test_fragment('"Google Chrome est\\u00E1 actualizado."') test_fragment( '"\\x22\\x27",\'\\x22\\x27\',"\\x5c",\'\\x5c\',"\\xff and \\xzz","unicode \\u0000 \\u0022 \\u0027 \\u005c \\uffff \\uzzzz"', '"\\x22\\x27", \'\\x22\\x27\', "\\x5c", \'\\x5c\', "\\xff and \\xzz", "unicode \\u0000 \\u0022 \\u0027 \\u005c \\uffff \\uzzzz"') self.options.unescape_strings = True bt('"\\x41\\x42\\x01\\x43"', '"AB\\x01C"') bt('"\\x41\\x42\\u0001\\x43"', '"AB\\u0001C"') bt('"\\x41\\x42\\u{0001}\\x43"', '"AB\\u{0001}C"') test_fragment('"\\x20\\x40\\x4a"', '" @J"') test_fragment('"\\xff\\x40\\x4a"') test_fragment('"\\u0072\\u016B\\u0137\\u012B\\u0074\\u0069\\u0073"', six.u('"\u0072\u016B\u0137\u012B\u0074\u0069\u0073"')) test_fragment('"\\u{0072}\\u{016B}\\u{110000}\\u{137}\\u012B\\x74\\u{0000069}\\u{073}"', six.u('"\u0072\u016B\\u{110000}\u0137\u012B\u0074\u0069\u0073"')) bt('a = /\\s+/') test_fragment('"\\x22\\x27",\'\\x22\\x27\',"\\x5c",\'\\x5c\',"\\xff","unicode \\u0000 \\u0022 \\u0027 \\u005c \\uffff"', '"\\"\\\'", \'\\"\\\'\', "\\\\", \'\\\\\', "\\xff", "unicode \\u0000 \\" \\\' \\\\ ' + unicode_char(0xffff) + '"') # For error case, return the string unchanged test_fragment('"\\x22\\x27",\'\\x22\\x27\',"\\x5c",\'\\x5c\',"\\xff and \\xzz","unicode \\u0000 \\u0022 \\u0027 \\u005c \\uffff \\uzzzz"', '"\\"\\\'", \'\\"\\\'\', "\\\\", \'\\\\\', "\\xff and \\xzz", "unicode \\u0000 \\u0022 \\u0027 \\u005c \\uffff \\uzzzz"') self.options.unescape_strings = False def test_beautifier(self): test_fragment = self.decodesto bt = self.bt true = True false = False def unicode_char(value): return six.unichr(value) ##============================================================ # Line wrap test inputs #....---------1---------2---------3---------4---------5---------6---------7 #....1234567890123456789012345678901234567890123456789012345678901234567890 wrap_input_1=( 'foo.bar().baz().cucumber((f && "sass") || (leans && mean));\n' + 'Test_very_long_variable_name_this_should_never_wrap\n.but_this_can\n' + 'return between_return_and_expression_should_never_wrap.but_this_can\n' + 'throw between_throw_and_expression_should_never_wrap.but_this_can\n' + 'if (wraps_can_occur && inside_an_if_block) that_is_\n.okay();\n' + 'object_literal = {\n' + ' propertx: first_token + 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap + but_this_can,\n' + ' propertz: first_token_should_never_wrap + !but_this_can,\n' + ' proper: "first_token_should_never_wrap" + "but_this_can"\n' + '}'); #....---------1---------2---------3---------4---------5---------6---------7 #....1234567890123456789012345678901234567890123456789012345678901234567890 wrap_input_2=( '{\n' + ' foo.bar().baz().cucumber((f && "sass") || (leans && mean));\n' + ' Test_very_long_variable_name_this_should_never_wrap\n.but_this_can\n' + ' return between_return_and_expression_should_never_wrap.but_this_can\n' + ' throw between_throw_and_expression_should_never_wrap.but_this_can\n' + ' if (wraps_can_occur && inside_an_if_block) that_is_\n.okay();\n' + ' object_literal = {\n' + ' propertx: first_token + 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap + but_this_can,\n' + ' propertz: first_token_should_never_wrap + !but_this_can,\n' + ' proper: "first_token_should_never_wrap" + "but_this_can"\n' + ' }' + '}'); #============================================================ # Unicode Support self.reset_options() bt('var ' + unicode_char(3232) + '_' + unicode_char(3232) + ' = "hi";') bt( 'var ' + unicode_char(228) + 'x = {\n' + ' ' + unicode_char(228) + 'rgerlich: true\n' + '};') bt( 'var \\u00E4\\u0ca0\\u0cA0\\u0Ca0 = {\n' + ' \\u0ca0rgerlich: true\n' + '};') bt( 'var \\u00E4add\\u0025 = {\n' + ' \\u0044rgerlich\\u0ca0: true\n' + '};') bt( 'var' + unicode_char(160) + unicode_char(3232) + '_' + unicode_char(3232) + ' = "hi";', # -- output -- 'var ' + unicode_char(3232) + '_' + unicode_char(3232) + ' = "hi";') # Issue #2159: Invalid prettification of object with unicode escape character as object key - test scenario: object with unicode as key bt( '{\\u{1d4b6}:"ascr"}', # -- output -- '{\n' + ' \\u{1d4b6}: "ascr"\n' + '}') bt( 'var \\u{E4}\\u{ca0}\\u{0cA0}\\u{000000Ca0} = {\n' + ' \\u{ca0}rgerlich: true\n' + '};') #============================================================ # Test template and continuation strings self.reset_options() bt('`This is a ${template} string.`') bt( '`This\n' + ' is\n' + ' a\n' + ' ${template}\n' + ' string.`') bt( 'a = `This is a continuation\\\n' + 'string.`') bt( 'a = "This is a continuation\\\n' + 'string."') bt( '`SELECT\n' + ' nextval(\'${this.options.schema ? `${this.options.schema}.` : \'\'}"${this.tableName}_${this.autoIncrementField}_seq"\'::regclass\n' + ' ) nextval;`') # Tests for #1030 bt( 'const composeUrl = (host) => {\n' + ' return `${host `test`}`;\n' + '};') bt( 'const composeUrl = (host, api, key, data) => {\n' + ' switch (api) {\n' + ' case "Init":\n' + ' return `${host}/vwapi/Init?VWID=${key}&DATA=${encodeURIComponent(\n' + ' Object.keys(data).map((k) => `${k}=${ data[k]}` ).join(";")\n' + ' )}`;\n' + ' case "Pay":\n' + ' return `${host}/vwapi/Pay?SessionId=${par}`;\n' + ' };\n' + '};') #============================================================ # Private Class Fields self.reset_options() bt('#foo') bt( 'class X {\n' + ' #foo = null;\n' + ' get foo() {\n' + ' return this.#foo;\n' + ' }\n' + '}') bt( 'class X {#foo=null;}', # -- output -- 'class X {\n' + ' #foo = null;\n' + '}') #============================================================ # ES7 Decorators self.reset_options() bt('@foo') bt('@foo(bar)') bt( '@foo(function(k, v) {\n' + ' implementation();\n' + '})') #============================================================ # ES7 exponential self.reset_options() bt('x ** 2') bt('x ** -2') #============================================================ # Spread operator self.reset_options() self.options.brace_style = "collapse,preserve-inline" bt('const m = { ...item, c: 3 };') bt( 'const m = {\n' + ' ...item,\n' + ' c: 3\n' + '};') bt('const m = { c: 3, ...item };') bt('const m = [...item, 3];') bt('const m = [3, ...item];') #============================================================ # Object literal shorthand functions self.reset_options() bt( 'return {\n' + ' foo() {\n' + ' return 42;\n' + ' }\n' + '}') bt( 'var foo = {\n' + ' * bar() {\n' + ' yield 42;\n' + ' }\n' + '};') bt( 'var foo = {bar(){return 42;},*barGen(){yield 42;}};', # -- output -- 'var foo = {\n' + ' bar() {\n' + ' return 42;\n' + ' },\n' + ' * barGen() {\n' + ' yield 42;\n' + ' }\n' + '};') # also handle generator shorthand in class - #1013 bt( 'class A {\n' + ' fn() {\n' + ' return true;\n' + ' }\n' + '\n' + ' * gen() {\n' + ' return true;\n' + ' }\n' + '}') bt( 'class A {\n' + ' * gen() {\n' + ' return true;\n' + ' }\n' + '\n' + ' fn() {\n' + ' return true;\n' + ' }\n' + '}') #============================================================ # End With Newline - (end_with_newline = "true") self.reset_options() self.options.end_with_newline = true test_fragment('', '\n') test_fragment(' return .5', ' return .5\n') test_fragment( ' \n' + '\n' + 'return .5\n' + '\n' + '\n' + '\n', # -- output -- ' return .5\n') test_fragment('\n') # End With Newline - (end_with_newline = "false") self.reset_options() self.options.end_with_newline = false test_fragment('') test_fragment(' return .5') test_fragment( ' \n' + '\n' + 'return .5\n' + '\n' + '\n' + '\n', # -- output -- ' return .5') test_fragment('\n', '') #============================================================ # Support Indent Level Options and Base Indent Autodetection - () self.reset_options() test_fragment(' a') test_fragment( ' function test(){\n' + ' console.log("this is a test");\n' + '}', # -- output -- ' function test() {\n' + ' console.log("this is a test");\n' + ' }') test_fragment( ' // This is a random comment\n' + 'function test(){\n' + ' console.log("this is a test");\n' + '}', # -- output -- ' // This is a random comment\n' + ' function test() {\n' + ' console.log("this is a test");\n' + ' }') # Support Indent Level Options and Base Indent Autodetection - (indent_level = "0") self.reset_options() self.options.indent_level = 0 test_fragment(' a') test_fragment( ' function test(){\n' + ' console.log("this is a test");\n' + '}', # -- output -- ' function test() {\n' + ' console.log("this is a test");\n' + ' }') test_fragment( ' // This is a random comment\n' + 'function test(){\n' + ' console.log("this is a test");\n' + '}', # -- output -- ' // This is a random comment\n' + ' function test() {\n' + ' console.log("this is a test");\n' + ' }') # Support Indent Level Options and Base Indent Autodetection - (indent_level = "1") self.reset_options() self.options.indent_level = 1 test_fragment(' a', ' a') test_fragment( ' function test(){\n' + ' console.log("this is a test");\n' + '}', # -- output -- ' function test() {\n' + ' console.log("this is a test");\n' + ' }') test_fragment( ' // This is a random comment\n' + 'function test(){\n' + ' console.log("this is a test");\n' + '}', # -- output -- ' // This is a random comment\n' + ' function test() {\n' + ' console.log("this is a test");\n' + ' }') # Support Indent Level Options and Base Indent Autodetection - (indent_level = "2") self.reset_options() self.options.indent_level = 2 test_fragment('a', ' a') test_fragment( 'function test(){\n' + ' console.log("this is a test");\n' + '}', # -- output -- ' function test() {\n' + ' console.log("this is a test");\n' + ' }') test_fragment( '// This is a random comment\n' + 'function test(){\n' + ' console.log("this is a test");\n' + '}', # -- output -- ' // This is a random comment\n' + ' function test() {\n' + ' console.log("this is a test");\n' + ' }') # Support Indent Level Options and Base Indent Autodetection - (indent_with_tabs = "true", indent_level = "2") self.reset_options() self.options.indent_with_tabs = true self.options.indent_level = 2 test_fragment('a', '\t\ta') test_fragment( 'function test(){\n' + ' console.log("this is a test");\n' + '}', # -- output -- '\t\tfunction test() {\n' + '\t\t\tconsole.log("this is a test");\n' + '\t\t}') test_fragment( '// This is a random comment\n' + 'function test(){\n' + ' console.log("this is a test");\n' + '}', # -- output -- '\t\t// This is a random comment\n' + '\t\tfunction test() {\n' + '\t\t\tconsole.log("this is a test");\n' + '\t\t}') # Support Indent Level Options and Base Indent Autodetection - (indent_level = "0") self.reset_options() self.options.indent_level = 0 test_fragment('\t a') test_fragment( '\t function test(){\n' + ' console.log("this is a test");\n' + '}', # -- output -- '\t function test() {\n' + '\t console.log("this is a test");\n' + '\t }') test_fragment( '\t // This is a random comment\n' + 'function test(){\n' + ' console.log("this is a test");\n' + '}', # -- output -- '\t // This is a random comment\n' + '\t function test() {\n' + '\t console.log("this is a test");\n' + '\t }') #============================================================ # Support simple language specific option inheritance/overriding - (js = "{ "indent_size": 3 }", css = "{ "indent_size": 5 }") self.reset_options() self.options.js = { 'indent_size': 3 } self.options.css = { 'indent_size': 5 } bt( 'if (a == b) {\n' + ' test();\n' + '}') # Support simple language specific option inheritance/overriding - (html = "{ "js": { "indent_size": 3 }, "css": { "indent_size": 5 } }") self.reset_options() self.options.html = { 'js': { 'indent_size': 3 }, 'css': { 'indent_size': 5 } } bt( 'if (a == b) {\n' + ' test();\n' + '}') # Support simple language specific option inheritance/overriding - (indent_size = "9", html = "{ "js": { "indent_size": 3 }, "css": { "indent_size": 5 }, "indent_size": 2}", js = "{ "indent_size": 4 }", css = "{ "indent_size": 3 }") self.reset_options() self.options.indent_size = 9 self.options.html = { 'js': { 'indent_size': 3 }, 'css': { 'indent_size': 5 }, 'indent_size': 2} self.options.js = { 'indent_size': 4 } self.options.css = { 'indent_size': 3 } bt( 'if (a == b) {\n' + ' test();\n' + '}') #============================================================ # Brace style permutations - (brace_style = ""collapse,preserve-inline"") self.reset_options() self.options.brace_style = 'collapse,preserve-inline' bt( 'var a ={a: 2};\n' + 'var a ={a: 2};', # -- output -- 'var a = { a: 2 };\n' + 'var a = { a: 2 };') bt( '//case 1\n' + 'if (a == 1){}\n' + '//case 2\n' + 'else if (a == 2){}', # -- output -- '//case 1\n' + 'if (a == 1) {}\n' + '//case 2\n' + 'else if (a == 2) {}') bt('if(1){2}else{3}', 'if (1) { 2 } else { 3 }') bt('try{a();}catch(b){c();}catch(d){}finally{e();}', 'try { a(); } catch (b) { c(); } catch (d) {} finally { e(); }') # Brace style permutations - (brace_style = ""collapse,preserve-inline"") self.reset_options() self.options.brace_style = 'collapse,preserve-inline' bt( 'var a =\n' + '{\n' + 'a: 2\n' + '}\n' + ';\n' + 'var a =\n' + '{\n' + 'a: 2\n' + '}\n' + ';', # -- output -- 'var a = {\n' + ' a: 2\n' + '};\n' + 'var a = {\n' + ' a: 2\n' + '};') bt( '//case 1\n' + 'if (a == 1)\n' + '{}\n' + '//case 2\n' + 'else if (a == 2)\n' + '{}', # -- output -- '//case 1\n' + 'if (a == 1) {}\n' + '//case 2\n' + 'else if (a == 2) {}') bt( 'if(1)\n' + '{\n' + '2\n' + '}\n' + 'else\n' + '{\n' + '3\n' + '}', # -- output -- 'if (1) {\n' + ' 2\n' + '} else {\n' + ' 3\n' + '}') bt( 'try\n' + '{\n' + 'a();\n' + '}\n' + 'catch(b)\n' + '{\n' + 'c();\n' + '}\n' + 'catch(d)\n' + '{}\n' + 'finally\n' + '{\n' + 'e();\n' + '}', # -- output -- 'try {\n' + ' a();\n' + '} catch (b) {\n' + ' c();\n' + '} catch (d) {} finally {\n' + ' e();\n' + '}') # Brace style permutations - () self.reset_options() bt( 'var a ={a: 2};\n' + 'var a ={a: 2};', # -- output -- 'var a = {\n' + ' a: 2\n' + '};\n' + 'var a = {\n' + ' a: 2\n' + '};') bt( '//case 1\n' + 'if (a == 1){}\n' + '//case 2\n' + 'else if (a == 2){}', # -- output -- '//case 1\n' + 'if (a == 1) {}\n' + '//case 2\n' + 'else if (a == 2) {}') bt( 'if(1){2}else{3}', # -- output -- 'if (1) {\n' + ' 2\n' + '} else {\n' + ' 3\n' + '}') bt( 'try{a();}catch(b){c();}catch(d){}finally{e();}', # -- output -- 'try {\n' + ' a();\n' + '} catch (b) {\n' + ' c();\n' + '} catch (d) {} finally {\n' + ' e();\n' + '}') # Brace style permutations - (brace_style = ""collapse"") self.reset_options() self.options.brace_style = 'collapse' bt( 'var a ={a: 2};\n' + 'var a ={a: 2};', # -- output -- 'var a = {\n' + ' a: 2\n' + '};\n' + 'var a = {\n' + ' a: 2\n' + '};') bt( '//case 1\n' + 'if (a == 1){}\n' + '//case 2\n' + 'else if (a == 2){}', # -- output -- '//case 1\n' + 'if (a == 1) {}\n' + '//case 2\n' + 'else if (a == 2) {}') bt( 'if(1){2}else{3}', # -- output -- 'if (1) {\n' + ' 2\n' + '} else {\n' + ' 3\n' + '}') bt( 'try{a();}catch(b){c();}catch(d){}finally{e();}', # -- output -- 'try {\n' + ' a();\n' + '} catch (b) {\n' + ' c();\n' + '} catch (d) {} finally {\n' + ' e();\n' + '}') # Brace style permutations - (brace_style = ""collapse"") self.reset_options() self.options.brace_style = 'collapse' bt( 'var a =\n' + '{\n' + 'a: 2\n' + '}\n' + ';\n' + 'var a =\n' + '{\n' + 'a: 2\n' + '}\n' + ';', # -- output -- 'var a = {\n' + ' a: 2\n' + '};\n' + 'var a = {\n' + ' a: 2\n' + '};') bt( '//case 1\n' + 'if (a == 1)\n' + '{}\n' + '//case 2\n' + 'else if (a == 2)\n' + '{}', # -- output -- '//case 1\n' + 'if (a == 1) {}\n' + '//case 2\n' + 'else if (a == 2) {}') bt( 'if(1)\n' + '{\n' + '2\n' + '}\n' + 'else\n' + '{\n' + '3\n' + '}', # -- output -- 'if (1) {\n' + ' 2\n' + '} else {\n' + ' 3\n' + '}') bt( 'try\n' + '{\n' + 'a();\n' + '}\n' + 'catch(b)\n' + '{\n' + 'c();\n' + '}\n' + 'catch(d)\n' + '{}\n' + 'finally\n' + '{\n' + 'e();\n' + '}', # -- output -- 'try {\n' + ' a();\n' + '} catch (b) {\n' + ' c();\n' + '} catch (d) {} finally {\n' + ' e();\n' + '}') #============================================================ # Comma-first option - (comma_first = "false") self.reset_options() self.options.comma_first = false bt( '{a:1, b:2}', # -- output -- '{\n' + ' a: 1,\n' + ' b: 2\n' + '}') bt( 'var a=1, b=c[d], e=6;', # -- output -- 'var a = 1,\n' + ' b = c[d],\n' + ' e = 6;') bt( 'for(var a=1,b=2,c=3;d<3;d++)\n' + 'e', # -- output -- 'for (var a = 1, b = 2, c = 3; d < 3; d++)\n' + ' e') bt( 'for(var a=1,b=2,\n' + 'c=3;d<3;d++)\n' + 'e', # -- output -- 'for (var a = 1, b = 2,\n' + ' c = 3; d < 3; d++)\n' + ' e') bt( 'function foo() {\n' + ' return [\n' + ' "one",\n' + ' "two"\n' + ' ];\n' + '}') bt( 'a=[[1,2],[4,5],[7,8]]', # -- output -- 'a = [\n' + ' [1, 2],\n' + ' [4, 5],\n' + ' [7, 8]\n' + ']') bt( 'a=[[1,2],[4,5],[7,8],]', # -- output -- 'a = [\n' + ' [1, 2],\n' + ' [4, 5],\n' + ' [7, 8],\n' + ']') bt( 'a=[[1,2],[4,5],function(){},[7,8]]', # -- output -- 'a = [\n' + ' [1, 2],\n' + ' [4, 5],\n' + ' function() {},\n' + ' [7, 8]\n' + ']') bt( 'a=[[1,2],[4,5],function(){},function(){},[7,8]]', # -- output -- 'a = [\n' + ' [1, 2],\n' + ' [4, 5],\n' + ' function() {},\n' + ' function() {},\n' + ' [7, 8]\n' + ']') bt( 'a=[[1,2],[4,5],function(){},[7,8]]', # -- output -- 'a = [\n' + ' [1, 2],\n' + ' [4, 5],\n' + ' function() {},\n' + ' [7, 8]\n' + ']') bt('a=[b,c,function(){},function(){},d]', 'a = [b, c, function() {}, function() {}, d]') bt( 'a=[b,c,\n' + 'function(){},function(){},d]', # -- output -- 'a = [b, c,\n' + ' function() {},\n' + ' function() {},\n' + ' d\n' + ']') bt('a=[a[1],b[4],c[d[7]]]', 'a = [a[1], b[4], c[d[7]]]') bt('[1,2,[3,4,[5,6],7],8]', '[1, 2, [3, 4, [5, 6], 7], 8]') bt( '[[["1","2"],["3","4"]],[["5","6","7"],["8","9","0"]],[["1","2","3"],["4","5","6","7"],["8","9","0"]]]', # -- output -- '[\n' + ' [\n' + ' ["1", "2"],\n' + ' ["3", "4"]\n' + ' ],\n' + ' [\n' + ' ["5", "6", "7"],\n' + ' ["8", "9", "0"]\n' + ' ],\n' + ' [\n' + ' ["1", "2", "3"],\n' + ' ["4", "5", "6", "7"],\n' + ' ["8", "9", "0"]\n' + ' ]\n' + ']') bt( 'changeCollection.add({\n' + ' name: "Jonathan" // New line inserted after this line on every save\n' + ' , age: 25\n' + '});', # -- output -- 'changeCollection.add({\n' + ' name: "Jonathan" // New line inserted after this line on every save\n' + ' ,\n' + ' age: 25\n' + '});') bt( 'changeCollection.add(\n' + ' function() {\n' + ' return true;\n' + ' },\n' + ' function() {\n' + ' return true;\n' + ' }\n' + ');') # Comma-first option - (comma_first = "true") self.reset_options() self.options.comma_first = true bt( '{a:1, b:2}', # -- output -- '{\n' + ' a: 1\n' + ' , b: 2\n' + '}') bt( 'var a=1, b=c[d], e=6;', # -- output -- 'var a = 1\n' + ' , b = c[d]\n' + ' , e = 6;') bt( 'for(var a=1,b=2,c=3;d<3;d++)\n' + 'e', # -- output -- 'for (var a = 1, b = 2, c = 3; d < 3; d++)\n' + ' e') bt( 'for(var a=1,b=2,\n' + 'c=3;d<3;d++)\n' + 'e', # -- output -- 'for (var a = 1, b = 2\n' + ' , c = 3; d < 3; d++)\n' + ' e') bt( 'function foo() {\n' + ' return [\n' + ' "one"\n' + ' , "two"\n' + ' ];\n' + '}') bt( 'a=[[1,2],[4,5],[7,8]]', # -- output -- 'a = [\n' + ' [1, 2]\n' + ' , [4, 5]\n' + ' , [7, 8]\n' + ']') bt( 'a=[[1,2],[4,5],[7,8],]', # -- output -- 'a = [\n' + ' [1, 2]\n' + ' , [4, 5]\n' + ' , [7, 8]\n' + ', ]') bt( 'a=[[1,2],[4,5],function(){},[7,8]]', # -- output -- 'a = [\n' + ' [1, 2]\n' + ' , [4, 5]\n' + ' , function() {}\n' + ' , [7, 8]\n' + ']') bt( 'a=[[1,2],[4,5],function(){},function(){},[7,8]]', # -- output -- 'a = [\n' + ' [1, 2]\n' + ' , [4, 5]\n' + ' , function() {}\n' + ' , function() {}\n' + ' , [7, 8]\n' + ']') bt( 'a=[[1,2],[4,5],function(){},[7,8]]', # -- output -- 'a = [\n' + ' [1, 2]\n' + ' , [4, 5]\n' + ' , function() {}\n' + ' , [7, 8]\n' + ']') bt('a=[b,c,function(){},function(){},d]', 'a = [b, c, function() {}, function() {}, d]') bt( 'a=[b,c,\n' + 'function(){},function(){},d]', # -- output -- 'a = [b, c\n' + ' , function() {}\n' + ' , function() {}\n' + ' , d\n' + ']') bt('a=[a[1],b[4],c[d[7]]]', 'a = [a[1], b[4], c[d[7]]]') bt('[1,2,[3,4,[5,6],7],8]', '[1, 2, [3, 4, [5, 6], 7], 8]') bt( '[[["1","2"],["3","4"]],[["5","6","7"],["8","9","0"]],[["1","2","3"],["4","5","6","7"],["8","9","0"]]]', # -- output -- '[\n' + ' [\n' + ' ["1", "2"]\n' + ' , ["3", "4"]\n' + ' ]\n' + ' , [\n' + ' ["5", "6", "7"]\n' + ' , ["8", "9", "0"]\n' + ' ]\n' + ' , [\n' + ' ["1", "2", "3"]\n' + ' , ["4", "5", "6", "7"]\n' + ' , ["8", "9", "0"]\n' + ' ]\n' + ']') bt( 'changeCollection.add({\n' + ' name: "Jonathan" // New line inserted after this line on every save\n' + ' , age: 25\n' + '});') bt( 'changeCollection.add(\n' + ' function() {\n' + ' return true;\n' + ' },\n' + ' function() {\n' + ' return true;\n' + ' }\n' + ');', # -- output -- 'changeCollection.add(\n' + ' function() {\n' + ' return true;\n' + ' }\n' + ' , function() {\n' + ' return true;\n' + ' }\n' + ');') #============================================================ # Unindent chained functions - (unindent_chained_methods = "true") self.reset_options() self.options.unindent_chained_methods = true bt( 'f().f().f()\n' + ' .f().f();', # -- output -- 'f().f().f()\n' + '.f().f();') bt( 'f()\n' + ' .f()\n' + ' .f();', # -- output -- 'f()\n' + '.f()\n' + '.f();') bt( 'f(function() {\n' + ' f()\n' + ' .f()\n' + ' .f();\n' + '});', # -- output -- 'f(function() {\n' + ' f()\n' + ' .f()\n' + ' .f();\n' + '});') # regression test for fix #1378 bt( 'f(function() {\n' + ' if(g === 1)\n' + ' g = 0;\n' + ' else\n' + ' g = 1;\n' + '\n' + ' f()\n' + ' .f()\n' + ' .f();\n' + '});', # -- output -- 'f(function() {\n' + ' if (g === 1)\n' + ' g = 0;\n' + ' else\n' + ' g = 1;\n' + '\n' + ' f()\n' + ' .f()\n' + ' .f();\n' + '});') # regression test for fix #1533 bt( 'angular.module("test").controller("testCtrl", function($scope) {\n' + ' $scope.tnew;\n' + ' $scope.toggle_tnew = function() {\n' + ' $scope.mode = 0;\n' + ' if (!$scope.tnew) {\n' + ' $scope.tnew = {};\n' + ' } else $scope.tnew = null;\n' + ' }\n' + ' $scope.fn = function() {\n' + ' return null;\n' + ' }\n' + '});') #============================================================ # Space in parens tests - (space_in_paren = "false", space_in_empty_paren = "false") self.reset_options() self.options.space_in_paren = false self.options.space_in_empty_paren = false bt('if(p) foo(a,b);', 'if (p) foo(a, b);') bt( 'try{while(true){willThrow()}}catch(result)switch(result){case 1:++result }', # -- output -- 'try {\n' + ' while (true) {\n' + ' willThrow()\n' + ' }\n' + '} catch (result) switch (result) {\n' + ' case 1:\n' + ' ++result\n' + '}') bt('((e/((a+(b)*c)-d))^2)*5;', '((e / ((a + (b) * c) - d)) ^ 2) * 5;') bt( 'function f(a,b) {if(a) b()}function g(a,b) {if(!a) b()}', # -- output -- 'function f(a, b) {\n' + ' if (a) b()\n' + '}\n' + '\n' + 'function g(a, b) {\n' + ' if (!a) b()\n' + '}') bt('a=[][ ]( );', 'a = [][]();') bt('a=()( )[ ];', 'a = ()()[];') bt('a=[b,c,d];', 'a = [b, c, d];') bt('a= f[b];', 'a = f[b];') # Issue #1151 - inside class methods bt( 'export default class Test extends Component {\n' + ' render() {\n' + ' someOther();\n' + ' return null;\n' + ' }\n' + '}') bt( '{\n' + ' files: a[][ {\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + ' src: b(c)[ "im/design_standards/*.*" ],\n' + ' dest: "www/gui/build"\n' + ' } ]\n' + '}', # -- output -- '{\n' + ' files: a[][{\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + ' src: b(c)["im/design_standards/*.*"],\n' + ' dest: "www/gui/build"\n' + ' }]\n' + '}') # Space in parens tests - (space_in_paren = "false", space_in_empty_paren = "true") self.reset_options() self.options.space_in_paren = false self.options.space_in_empty_paren = true bt('if(p) foo(a,b);', 'if (p) foo(a, b);') bt( 'try{while(true){willThrow()}}catch(result)switch(result){case 1:++result }', # -- output -- 'try {\n' + ' while (true) {\n' + ' willThrow()\n' + ' }\n' + '} catch (result) switch (result) {\n' + ' case 1:\n' + ' ++result\n' + '}') bt('((e/((a+(b)*c)-d))^2)*5;', '((e / ((a + (b) * c) - d)) ^ 2) * 5;') bt( 'function f(a,b) {if(a) b()}function g(a,b) {if(!a) b()}', # -- output -- 'function f(a, b) {\n' + ' if (a) b()\n' + '}\n' + '\n' + 'function g(a, b) {\n' + ' if (!a) b()\n' + '}') bt('a=[][ ]( );', 'a = [][]();') bt('a=()( )[ ];', 'a = ()()[];') bt('a=[b,c,d];', 'a = [b, c, d];') bt('a= f[b];', 'a = f[b];') # Issue #1151 - inside class methods bt( 'export default class Test extends Component {\n' + ' render() {\n' + ' someOther();\n' + ' return null;\n' + ' }\n' + '}') bt( '{\n' + ' files: a[][ {\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + ' src: b(c)[ "im/design_standards/*.*" ],\n' + ' dest: "www/gui/build"\n' + ' } ]\n' + '}', # -- output -- '{\n' + ' files: a[][{\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + ' src: b(c)["im/design_standards/*.*"],\n' + ' dest: "www/gui/build"\n' + ' }]\n' + '}') # Space in parens tests - (space_in_paren = "true", space_in_empty_paren = "false") self.reset_options() self.options.space_in_paren = true self.options.space_in_empty_paren = false bt('if(p) foo(a,b);', 'if ( p ) foo( a, b );') bt( 'try{while(true){willThrow()}}catch(result)switch(result){case 1:++result }', # -- output -- 'try {\n' + ' while ( true ) {\n' + ' willThrow()\n' + ' }\n' + '} catch ( result ) switch ( result ) {\n' + ' case 1:\n' + ' ++result\n' + '}') bt('((e/((a+(b)*c)-d))^2)*5;', '( ( e / ( ( a + ( b ) * c ) - d ) ) ^ 2 ) * 5;') bt( 'function f(a,b) {if(a) b()}function g(a,b) {if(!a) b()}', # -- output -- 'function f( a, b ) {\n' + ' if ( a ) b()\n' + '}\n' + '\n' + 'function g( a, b ) {\n' + ' if ( !a ) b()\n' + '}') bt('a=[][ ]( );', 'a = [][]();') bt('a=()( )[ ];', 'a = ()()[];') bt('a=[b,c,d];', 'a = [ b, c, d ];') bt('a= f[b];', 'a = f[ b ];') # Issue #1151 - inside class methods bt( 'export default class Test extends Component {\n' + ' render() {\n' + ' someOther();\n' + ' return null;\n' + ' }\n' + '}') bt( '{\n' + ' files: a[][ {\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + ' src: b(c)[ "im/design_standards/*.*" ],\n' + ' dest: "www/gui/build"\n' + ' } ]\n' + '}', # -- output -- '{\n' + ' files: a[][ {\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + ' src: b( c )[ "im/design_standards/*.*" ],\n' + ' dest: "www/gui/build"\n' + ' } ]\n' + '}') # Space in parens tests - (space_in_paren = "true", space_in_empty_paren = "true") self.reset_options() self.options.space_in_paren = true self.options.space_in_empty_paren = true bt('if(p) foo(a,b);', 'if ( p ) foo( a, b );') bt( 'try{while(true){willThrow()}}catch(result)switch(result){case 1:++result }', # -- output -- 'try {\n' + ' while ( true ) {\n' + ' willThrow( )\n' + ' }\n' + '} catch ( result ) switch ( result ) {\n' + ' case 1:\n' + ' ++result\n' + '}') bt('((e/((a+(b)*c)-d))^2)*5;', '( ( e / ( ( a + ( b ) * c ) - d ) ) ^ 2 ) * 5;') bt( 'function f(a,b) {if(a) b()}function g(a,b) {if(!a) b()}', # -- output -- 'function f( a, b ) {\n' + ' if ( a ) b( )\n' + '}\n' + '\n' + 'function g( a, b ) {\n' + ' if ( !a ) b( )\n' + '}') bt('a=[][ ]( );', 'a = [ ][ ]( );') bt('a=()( )[ ];', 'a = ( )( )[ ];') bt('a=[b,c,d];', 'a = [ b, c, d ];') bt('a= f[b];', 'a = f[ b ];') # Issue #1151 - inside class methods bt( 'export default class Test extends Component {\n' + ' render() {\n' + ' someOther();\n' + ' return null;\n' + ' }\n' + '}', # -- output -- 'export default class Test extends Component {\n' + ' render( ) {\n' + ' someOther( );\n' + ' return null;\n' + ' }\n' + '}') bt( '{\n' + ' files: a[][ {\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + ' src: b(c)[ "im/design_standards/*.*" ],\n' + ' dest: "www/gui/build"\n' + ' } ]\n' + '}', # -- output -- '{\n' + ' files: a[ ][ {\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + ' src: b( c )[ "im/design_standards/*.*" ],\n' + ' dest: "www/gui/build"\n' + ' } ]\n' + '}') #============================================================ # general preserve_newlines tests - (preserve_newlines = "false") self.reset_options() self.options.preserve_newlines = false bt( 'if (foo) // comment\n' + ' bar();') bt( 'if (foo) // comment\n' + ' bar();') bt( 'if (foo) // comment\n' + ' (bar());') bt( 'if (foo) // comment\n' + ' (bar());') bt( 'if (foo) // comment\n' + ' /asdf/;') bt( 'this.oa = new OAuth(\n' + ' _requestToken,\n' + ' _accessToken,\n' + ' consumer_key\n' + ');', # -- output -- 'this.oa = new OAuth(_requestToken, _accessToken, consumer_key);') bt( 'foo = {\n' + ' x: y, // #44\n' + ' w: z // #44\n' + '}') bt( 'switch (x) {\n' + ' case "a":\n' + ' // comment on newline\n' + ' break;\n' + ' case "b": // comment on same line\n' + ' break;\n' + '}') bt( 'this.type =\n' + ' this.options =\n' + ' // comment\n' + ' this.enabled null;', # -- output -- 'this.type = this.options =\n' + ' // comment\n' + ' this.enabled null;') bt( 'someObj\n' + ' .someFunc1()\n' + ' // This comment should not break the indent\n' + ' .someFunc2();', # -- output -- 'someObj.someFunc1()\n' + ' // This comment should not break the indent\n' + ' .someFunc2();') bt( 'if (true ||\n' + '!true) return;', # -- output -- 'if (true || !true) return;') bt( 'if\n' + '(foo)\n' + 'if\n' + '(bar)\n' + 'if\n' + '(baz)\n' + 'whee();\n' + 'a();', # -- output -- 'if (foo)\n' + ' if (bar)\n' + ' if (baz) whee();\n' + 'a();') bt( 'if\n' + '(foo)\n' + 'if\n' + '(bar)\n' + 'if\n' + '(baz)\n' + 'whee();\n' + 'else\n' + 'a();', # -- output -- 'if (foo)\n' + ' if (bar)\n' + ' if (baz) whee();\n' + ' else a();') bt( 'if (foo)\n' + 'bar();\n' + 'else\n' + 'car();', # -- output -- 'if (foo) bar();\n' + 'else car();') bt( 'if (foo) if (bar) if (baz);\n' + 'a();', # -- output -- 'if (foo)\n' + ' if (bar)\n' + ' if (baz);\n' + 'a();') bt( 'if (foo) if (bar) if (baz) whee();\n' + 'a();', # -- output -- 'if (foo)\n' + ' if (bar)\n' + ' if (baz) whee();\n' + 'a();') bt( 'if (foo) a()\n' + 'if (bar) if (baz) whee();\n' + 'a();', # -- output -- 'if (foo) a()\n' + 'if (bar)\n' + ' if (baz) whee();\n' + 'a();') bt( 'if (foo);\n' + 'if (bar) if (baz) whee();\n' + 'a();', # -- output -- 'if (foo);\n' + 'if (bar)\n' + ' if (baz) whee();\n' + 'a();') bt( 'if (options)\n' + ' for (var p in options)\n' + ' this[p] = options[p];', # -- output -- 'if (options)\n' + ' for (var p in options) this[p] = options[p];') bt( 'if (options) for (var p in options) this[p] = options[p];', # -- output -- 'if (options)\n' + ' for (var p in options) this[p] = options[p];') bt( 'if (options) do q(); while (b());', # -- output -- 'if (options)\n' + ' do q(); while (b());') bt( 'if (options) while (b()) q();', # -- output -- 'if (options)\n' + ' while (b()) q();') bt( 'if (options) do while (b()) q(); while (a());', # -- output -- 'if (options)\n' + ' do\n' + ' while (b()) q(); while (a());') bt( 'function f(a, b, c,\n' + 'd, e) {}', # -- output -- 'function f(a, b, c, d, e) {}') bt( 'function f(a,b) {if(a) b()}function g(a,b) {if(!a) b()}', # -- output -- 'function f(a, b) {\n' + ' if (a) b()\n' + '}\n' + '\n' + 'function g(a, b) {\n' + ' if (!a) b()\n' + '}') bt( 'function f(a,b) {if(a) b()}\n' + '\n' + '\n' + '\n' + 'function g(a,b) {if(!a) b()}', # -- output -- 'function f(a, b) {\n' + ' if (a) b()\n' + '}\n' + '\n' + 'function g(a, b) {\n' + ' if (!a) b()\n' + '}') bt( '(if(a) b())(if(a) b())', # -- output -- '(\n' + ' if (a) b())(\n' + ' if (a) b())') bt( '(if(a) b())\n' + '\n' + '\n' + '(if(a) b())', # -- output -- '(\n' + ' if (a) b())\n' + '(\n' + ' if (a) b())') bt( 'if\n' + '(a)\n' + 'b();', # -- output -- 'if (a) b();') bt( 'var a =\n' + 'foo', # -- output -- 'var a = foo') bt( 'var a = {\n' + '"a":1,\n' + '"b":2}', # -- output -- 'var a = {\n' + ' "a": 1,\n' + ' "b": 2\n' + '}') bt( 'var a = {\n' + '\'a\':1,\n' + '\'b\':2}', # -- output -- 'var a = {\n' + ' \'a\': 1,\n' + ' \'b\': 2\n' + '}') bt('var a = /*i*/ "b";') bt( 'var a = /*i*/\n' + '"b";', # -- output -- 'var a = /*i*/ "b";') bt( '{\n' + '\n' + '\n' + '"x"\n' + '}', # -- output -- '{\n' + ' "x"\n' + '}') bt( 'if(a &&\n' + 'b\n' + '||\n' + 'c\n' + '||d\n' + '&&\n' + 'e) e = f', # -- output -- 'if (a && b || c || d && e) e = f') bt( 'if(a &&\n' + '(b\n' + '||\n' + 'c\n' + '||d)\n' + '&&\n' + 'e) e = f', # -- output -- 'if (a && (b || c || d) && e) e = f') test_fragment( '\n' + '\n' + '"x"', # -- output -- '"x"') test_fragment( '{\n' + '\n' + '"x"\n' + 'h=5;\n' + '}', # -- output -- '{\n' + ' "x"\n' + ' h = 5;\n' + '}') bt( 'var a = "foo" +\n' + ' "bar";', # -- output -- 'var a = "foo" + "bar";') bt( 'var a = 42; // foo\n' + '\n' + 'var b;', # -- output -- 'var a = 42; // foo\n' + 'var b;') bt( 'var a = 42; // foo\n' + '\n' + '\n' + 'var b;', # -- output -- 'var a = 42; // foo\n' + 'var b;') bt( 'a = 1;\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + 'b = 2;', # -- output -- 'a = 1;\n' + 'b = 2;') # general preserve_newlines tests - (preserve_newlines = "true") self.reset_options() self.options.preserve_newlines = true bt( 'if (foo) // comment\n' + ' bar();') bt( 'if (foo) // comment\n' + ' bar();') bt( 'if (foo) // comment\n' + ' (bar());') bt( 'if (foo) // comment\n' + ' (bar());') bt( 'if (foo) // comment\n' + ' /asdf/;') bt( 'this.oa = new OAuth(\n' + ' _requestToken,\n' + ' _accessToken,\n' + ' consumer_key\n' + ');') bt( 'foo = {\n' + ' x: y, // #44\n' + ' w: z // #44\n' + '}') bt( 'switch (x) {\n' + ' case "a":\n' + ' // comment on newline\n' + ' break;\n' + ' case "b": // comment on same line\n' + ' break;\n' + '}') bt( 'this.type =\n' + ' this.options =\n' + ' // comment\n' + ' this.enabled null;') bt( 'someObj\n' + ' .someFunc1()\n' + ' // This comment should not break the indent\n' + ' .someFunc2();') bt( 'if (true ||\n' + '!true) return;', # -- output -- 'if (true ||\n' + ' !true) return;') bt( 'if\n' + '(foo)\n' + 'if\n' + '(bar)\n' + 'if\n' + '(baz)\n' + 'whee();\n' + 'a();', # -- output -- 'if (foo)\n' + ' if (bar)\n' + ' if (baz)\n' + ' whee();\n' + 'a();') bt( 'if\n' + '(foo)\n' + 'if\n' + '(bar)\n' + 'if\n' + '(baz)\n' + 'whee();\n' + 'else\n' + 'a();', # -- output -- 'if (foo)\n' + ' if (bar)\n' + ' if (baz)\n' + ' whee();\n' + ' else\n' + ' a();') bt( 'if (foo)\n' + 'bar();\n' + 'else\n' + 'car();', # -- output -- 'if (foo)\n' + ' bar();\n' + 'else\n' + ' car();') bt( 'if (foo) if (bar) if (baz);\n' + 'a();', # -- output -- 'if (foo)\n' + ' if (bar)\n' + ' if (baz);\n' + 'a();') bt( 'if (foo) if (bar) if (baz) whee();\n' + 'a();', # -- output -- 'if (foo)\n' + ' if (bar)\n' + ' if (baz) whee();\n' + 'a();') bt( 'if (foo) a()\n' + 'if (bar) if (baz) whee();\n' + 'a();', # -- output -- 'if (foo) a()\n' + 'if (bar)\n' + ' if (baz) whee();\n' + 'a();') bt( 'if (foo);\n' + 'if (bar) if (baz) whee();\n' + 'a();', # -- output -- 'if (foo);\n' + 'if (bar)\n' + ' if (baz) whee();\n' + 'a();') bt( 'if (options)\n' + ' for (var p in options)\n' + ' this[p] = options[p];') bt( 'if (options) for (var p in options) this[p] = options[p];', # -- output -- 'if (options)\n' + ' for (var p in options) this[p] = options[p];') bt( 'if (options) do q(); while (b());', # -- output -- 'if (options)\n' + ' do q(); while (b());') bt( 'if (options) while (b()) q();', # -- output -- 'if (options)\n' + ' while (b()) q();') bt( 'if (options) do while (b()) q(); while (a());', # -- output -- 'if (options)\n' + ' do\n' + ' while (b()) q(); while (a());') bt( 'function f(a, b, c,\n' + 'd, e) {}', # -- output -- 'function f(a, b, c,\n' + ' d, e) {}') bt( 'function f(a,b) {if(a) b()}function g(a,b) {if(!a) b()}', # -- output -- 'function f(a, b) {\n' + ' if (a) b()\n' + '}\n' + '\n' + 'function g(a, b) {\n' + ' if (!a) b()\n' + '}') bt( 'function f(a,b) {if(a) b()}\n' + '\n' + '\n' + '\n' + 'function g(a,b) {if(!a) b()}', # -- output -- 'function f(a, b) {\n' + ' if (a) b()\n' + '}\n' + '\n' + '\n' + '\n' + 'function g(a, b) {\n' + ' if (!a) b()\n' + '}') bt( '(if(a) b())(if(a) b())', # -- output -- '(\n' + ' if (a) b())(\n' + ' if (a) b())') bt( '(if(a) b())\n' + '\n' + '\n' + '(if(a) b())', # -- output -- '(\n' + ' if (a) b())\n' + '\n' + '\n' + '(\n' + ' if (a) b())') bt( 'if\n' + '(a)\n' + 'b();', # -- output -- 'if (a)\n' + ' b();') bt( 'var a =\n' + 'foo', # -- output -- 'var a =\n' + ' foo') bt( 'var a = {\n' + '"a":1,\n' + '"b":2}', # -- output -- 'var a = {\n' + ' "a": 1,\n' + ' "b": 2\n' + '}') bt( 'var a = {\n' + '\'a\':1,\n' + '\'b\':2}', # -- output -- 'var a = {\n' + ' \'a\': 1,\n' + ' \'b\': 2\n' + '}') bt('var a = /*i*/ "b";') bt( 'var a = /*i*/\n' + '"b";', # -- output -- 'var a = /*i*/\n' + ' "b";') bt( '{\n' + '\n' + '\n' + '"x"\n' + '}', # -- output -- '{\n' + '\n' + '\n' + ' "x"\n' + '}') bt( 'if(a &&\n' + 'b\n' + '||\n' + 'c\n' + '||d\n' + '&&\n' + 'e) e = f', # -- output -- 'if (a &&\n' + ' b ||\n' + ' c ||\n' + ' d &&\n' + ' e) e = f') bt( 'if(a &&\n' + '(b\n' + '||\n' + 'c\n' + '||d)\n' + '&&\n' + 'e) e = f', # -- output -- 'if (a &&\n' + ' (b ||\n' + ' c ||\n' + ' d) &&\n' + ' e) e = f') test_fragment( '\n' + '\n' + '"x"', # -- output -- '"x"') test_fragment( '{\n' + '\n' + '"x"\n' + 'h=5;\n' + '}', # -- output -- '{\n' + '\n' + ' "x"\n' + ' h = 5;\n' + '}') bt( 'var a = "foo" +\n' + ' "bar";') bt( 'var a = 42; // foo\n' + '\n' + 'var b;') bt( 'var a = 42; // foo\n' + '\n' + '\n' + 'var b;') bt( 'a = 1;\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + 'b = 2;') #============================================================ # break chained methods - (break_chained_methods = "false", preserve_newlines = "false") self.reset_options() self.options.break_chained_methods = false self.options.preserve_newlines = false bt( 'foo\n' + '.bar()\n' + '.baz().cucumber(fat)', # -- output -- 'foo.bar().baz().cucumber(fat)') bt( 'foo\n' + '.bar()\n' + '.baz().cucumber(fat); foo.bar().baz().cucumber(fat)', # -- output -- 'foo.bar().baz().cucumber(fat);\n' + 'foo.bar().baz().cucumber(fat)') bt( 'foo\n' + '.bar()\n' + '.baz().cucumber(fat)\n' + ' foo.bar().baz().cucumber(fat)', # -- output -- 'foo.bar().baz().cucumber(fat)\n' + 'foo.bar().baz().cucumber(fat)') bt( 'this\n' + '.something = foo.bar()\n' + '.baz().cucumber(fat)', # -- output -- 'this.something = foo.bar().baz().cucumber(fat)') bt('this.something.xxx = foo.moo.bar()') bt( 'this\n' + '.something\n' + '.xxx = foo.moo\n' + '.bar()', # -- output -- 'this.something.xxx = foo.moo.bar()') # optional chaining operator bt( 'foo\n' + '?.bar()\n' + '?.baz()?.cucumber(fat)', # -- output -- 'foo?.bar()?.baz()?.cucumber(fat)') bt( 'foo\n' + '?.bar()\n' + '?.baz()?.cucumber(fat); foo?.bar()?.baz()?.cucumber(fat)', # -- output -- 'foo?.bar()?.baz()?.cucumber(fat);\n' + 'foo?.bar()?.baz()?.cucumber(fat)') bt( 'foo\n' + '?.bar()\n' + '?.baz()?.cucumber(fat)\n' + ' foo?.bar()?.baz()?.cucumber(fat)', # -- output -- 'foo?.bar()?.baz()?.cucumber(fat)\n' + 'foo?.bar()?.baz()?.cucumber(fat)') bt( 'this\n' + '?.something = foo?.bar()\n' + '?.baz()?.cucumber(fat)', # -- output -- 'this?.something = foo?.bar()?.baz()?.cucumber(fat)') bt('this?.something?.xxx = foo?.moo?.bar()') bt( 'this\n' + '?.something\n' + '?.xxx = foo?.moo\n' + '?.bar()', # -- output -- 'this?.something?.xxx = foo?.moo?.bar()') # break chained methods - (break_chained_methods = "false", preserve_newlines = "true") self.reset_options() self.options.break_chained_methods = false self.options.preserve_newlines = true bt( 'foo\n' + '.bar()\n' + '.baz().cucumber(fat)', # -- output -- 'foo\n' + ' .bar()\n' + ' .baz().cucumber(fat)') bt( 'foo\n' + '.bar()\n' + '.baz().cucumber(fat); foo.bar().baz().cucumber(fat)', # -- output -- 'foo\n' + ' .bar()\n' + ' .baz().cucumber(fat);\n' + 'foo.bar().baz().cucumber(fat)') bt( 'foo\n' + '.bar()\n' + '.baz().cucumber(fat)\n' + ' foo.bar().baz().cucumber(fat)', # -- output -- 'foo\n' + ' .bar()\n' + ' .baz().cucumber(fat)\n' + 'foo.bar().baz().cucumber(fat)') bt( 'this\n' + '.something = foo.bar()\n' + '.baz().cucumber(fat)', # -- output -- 'this\n' + ' .something = foo.bar()\n' + ' .baz().cucumber(fat)') bt('this.something.xxx = foo.moo.bar()') bt( 'this\n' + '.something\n' + '.xxx = foo.moo\n' + '.bar()', # -- output -- 'this\n' + ' .something\n' + ' .xxx = foo.moo\n' + ' .bar()') # optional chaining operator bt( 'foo\n' + '?.bar()\n' + '?.baz()?.cucumber(fat)', # -- output -- 'foo\n' + ' ?.bar()\n' + ' ?.baz()?.cucumber(fat)') bt( 'foo\n' + '?.bar()\n' + '?.baz()?.cucumber(fat); foo?.bar()?.baz()?.cucumber(fat)', # -- output -- 'foo\n' + ' ?.bar()\n' + ' ?.baz()?.cucumber(fat);\n' + 'foo?.bar()?.baz()?.cucumber(fat)') bt( 'foo\n' + '?.bar()\n' + '?.baz()?.cucumber(fat)\n' + ' foo?.bar()?.baz()?.cucumber(fat)', # -- output -- 'foo\n' + ' ?.bar()\n' + ' ?.baz()?.cucumber(fat)\n' + 'foo?.bar()?.baz()?.cucumber(fat)') bt( 'this\n' + '?.something = foo?.bar()\n' + '?.baz()?.cucumber(fat)', # -- output -- 'this\n' + ' ?.something = foo?.bar()\n' + ' ?.baz()?.cucumber(fat)') bt('this?.something?.xxx = foo?.moo?.bar()') bt( 'this\n' + '?.something\n' + '?.xxx = foo?.moo\n' + '?.bar()', # -- output -- 'this\n' + ' ?.something\n' + ' ?.xxx = foo?.moo\n' + ' ?.bar()') # break chained methods - (break_chained_methods = "true", preserve_newlines = "false") self.reset_options() self.options.break_chained_methods = true self.options.preserve_newlines = false bt( 'foo\n' + '.bar()\n' + '.baz().cucumber(fat)', # -- output -- 'foo.bar()\n' + ' .baz()\n' + ' .cucumber(fat)') bt( 'foo\n' + '.bar()\n' + '.baz().cucumber(fat); foo.bar().baz().cucumber(fat)', # -- output -- 'foo.bar()\n' + ' .baz()\n' + ' .cucumber(fat);\n' + 'foo.bar()\n' + ' .baz()\n' + ' .cucumber(fat)') bt( 'foo\n' + '.bar()\n' + '.baz().cucumber(fat)\n' + ' foo.bar().baz().cucumber(fat)', # -- output -- 'foo.bar()\n' + ' .baz()\n' + ' .cucumber(fat)\n' + 'foo.bar()\n' + ' .baz()\n' + ' .cucumber(fat)') bt( 'this\n' + '.something = foo.bar()\n' + '.baz().cucumber(fat)', # -- output -- 'this.something = foo.bar()\n' + ' .baz()\n' + ' .cucumber(fat)') bt('this.something.xxx = foo.moo.bar()') bt( 'this\n' + '.something\n' + '.xxx = foo.moo\n' + '.bar()', # -- output -- 'this.something.xxx = foo.moo.bar()') # optional chaining operator bt( 'foo\n' + '?.bar()\n' + '?.baz()?.cucumber(fat)', # -- output -- 'foo?.bar()\n' + ' ?.baz()\n' + ' ?.cucumber(fat)') bt( 'foo\n' + '?.bar()\n' + '?.baz()?.cucumber(fat); foo?.bar()?.baz()?.cucumber(fat)', # -- output -- 'foo?.bar()\n' + ' ?.baz()\n' + ' ?.cucumber(fat);\n' + 'foo?.bar()\n' + ' ?.baz()\n' + ' ?.cucumber(fat)') bt( 'foo\n' + '?.bar()\n' + '?.baz()?.cucumber(fat)\n' + ' foo?.bar()?.baz()?.cucumber(fat)', # -- output -- 'foo?.bar()\n' + ' ?.baz()\n' + ' ?.cucumber(fat)\n' + 'foo?.bar()\n' + ' ?.baz()\n' + ' ?.cucumber(fat)') bt( 'this\n' + '?.something = foo?.bar()\n' + '?.baz()?.cucumber(fat)', # -- output -- 'this?.something = foo?.bar()\n' + ' ?.baz()\n' + ' ?.cucumber(fat)') bt('this?.something?.xxx = foo?.moo?.bar()') bt( 'this\n' + '?.something\n' + '?.xxx = foo?.moo\n' + '?.bar()', # -- output -- 'this?.something?.xxx = foo?.moo?.bar()') # break chained methods - (break_chained_methods = "true", preserve_newlines = "true") self.reset_options() self.options.break_chained_methods = true self.options.preserve_newlines = true bt( 'foo\n' + '.bar()\n' + '.baz().cucumber(fat)', # -- output -- 'foo\n' + ' .bar()\n' + ' .baz()\n' + ' .cucumber(fat)') bt( 'foo\n' + '.bar()\n' + '.baz().cucumber(fat); foo.bar().baz().cucumber(fat)', # -- output -- 'foo\n' + ' .bar()\n' + ' .baz()\n' + ' .cucumber(fat);\n' + 'foo.bar()\n' + ' .baz()\n' + ' .cucumber(fat)') bt( 'foo\n' + '.bar()\n' + '.baz().cucumber(fat)\n' + ' foo.bar().baz().cucumber(fat)', # -- output -- 'foo\n' + ' .bar()\n' + ' .baz()\n' + ' .cucumber(fat)\n' + 'foo.bar()\n' + ' .baz()\n' + ' .cucumber(fat)') bt( 'this\n' + '.something = foo.bar()\n' + '.baz().cucumber(fat)', # -- output -- 'this\n' + ' .something = foo.bar()\n' + ' .baz()\n' + ' .cucumber(fat)') bt('this.something.xxx = foo.moo.bar()') bt( 'this\n' + '.something\n' + '.xxx = foo.moo\n' + '.bar()', # -- output -- 'this\n' + ' .something\n' + ' .xxx = foo.moo\n' + ' .bar()') # optional chaining operator bt( 'foo\n' + '?.bar()\n' + '?.baz()?.cucumber(fat)', # -- output -- 'foo\n' + ' ?.bar()\n' + ' ?.baz()\n' + ' ?.cucumber(fat)') bt( 'foo\n' + '?.bar()\n' + '?.baz()?.cucumber(fat); foo?.bar()?.baz()?.cucumber(fat)', # -- output -- 'foo\n' + ' ?.bar()\n' + ' ?.baz()\n' + ' ?.cucumber(fat);\n' + 'foo?.bar()\n' + ' ?.baz()\n' + ' ?.cucumber(fat)') bt( 'foo\n' + '?.bar()\n' + '?.baz()?.cucumber(fat)\n' + ' foo?.bar()?.baz()?.cucumber(fat)', # -- output -- 'foo\n' + ' ?.bar()\n' + ' ?.baz()\n' + ' ?.cucumber(fat)\n' + 'foo?.bar()\n' + ' ?.baz()\n' + ' ?.cucumber(fat)') bt( 'this\n' + '?.something = foo?.bar()\n' + '?.baz()?.cucumber(fat)', # -- output -- 'this\n' + ' ?.something = foo?.bar()\n' + ' ?.baz()\n' + ' ?.cucumber(fat)') bt('this?.something?.xxx = foo?.moo?.bar()') bt( 'this\n' + '?.something\n' + '?.xxx = foo?.moo\n' + '?.bar()', # -- output -- 'this\n' + ' ?.something\n' + ' ?.xxx = foo?.moo\n' + ' ?.bar()') #============================================================ # line wrapping 0 self.reset_options() self.options.preserve_newlines = false self.options.wrap_line_length = 0 test_fragment( '' + wrap_input_1 + '', # -- output -- 'foo.bar().baz().cucumber((f && "sass") || (leans && mean));\n' + 'Test_very_long_variable_name_this_should_never_wrap.but_this_can\n' + 'return between_return_and_expression_should_never_wrap.but_this_can\n' + 'throw between_throw_and_expression_should_never_wrap.but_this_can\n' + 'if (wraps_can_occur && inside_an_if_block) that_is_.okay();\n' + 'object_literal = {\n' + ' propertx: first_token + 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap + but_this_can,\n' + ' propertz: first_token_should_never_wrap + !but_this_can,\n' + ' proper: "first_token_should_never_wrap" + "but_this_can"\n' + '}') test_fragment( '' + wrap_input_2 + '', # -- output -- '{\n' + ' foo.bar().baz().cucumber((f && "sass") || (leans && mean));\n' + ' Test_very_long_variable_name_this_should_never_wrap.but_this_can\n' + ' return between_return_and_expression_should_never_wrap.but_this_can\n' + ' throw between_throw_and_expression_should_never_wrap.but_this_can\n' + ' if (wraps_can_occur && inside_an_if_block) that_is_.okay();\n' + ' object_literal = {\n' + ' propertx: first_token + 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap + but_this_can,\n' + ' propertz: first_token_should_never_wrap + !but_this_can,\n' + ' proper: "first_token_should_never_wrap" + "but_this_can"\n' + ' }\n' + '}') #============================================================ # line wrapping 70 self.reset_options() self.options.preserve_newlines = false self.options.wrap_line_length = 70 test_fragment( '' + wrap_input_1 + '', # -- output -- 'foo.bar().baz().cucumber((f && "sass") || (leans && mean));\n' + 'Test_very_long_variable_name_this_should_never_wrap.but_this_can\n' + 'return between_return_and_expression_should_never_wrap.but_this_can\n' + 'throw between_throw_and_expression_should_never_wrap.but_this_can\n' + 'if (wraps_can_occur && inside_an_if_block) that_is_.okay();\n' + 'object_literal = {\n' + ' propertx: first_token + 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap + but_this_can,\n' + ' propertz: first_token_should_never_wrap + !but_this_can,\n' + ' proper: "first_token_should_never_wrap" + "but_this_can"\n' + '}') test_fragment( '' + wrap_input_2 + '', # -- output -- '{\n' + ' foo.bar().baz().cucumber((f && "sass") || (leans && mean));\n' + ' Test_very_long_variable_name_this_should_never_wrap.but_this_can\n' + ' return between_return_and_expression_should_never_wrap\n' + ' .but_this_can\n' + ' throw between_throw_and_expression_should_never_wrap.but_this_can\n' + ' if (wraps_can_occur && inside_an_if_block) that_is_.okay();\n' + ' object_literal = {\n' + ' propertx: first_token + 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap + but_this_can,\n' + ' propertz: first_token_should_never_wrap + !but_this_can,\n' + ' proper: "first_token_should_never_wrap" + "but_this_can"\n' + ' }\n' + '}') #============================================================ # line wrapping 40 self.reset_options() self.options.preserve_newlines = false self.options.wrap_line_length = 40 test_fragment( '' + wrap_input_1 + '', # -- output -- 'foo.bar().baz().cucumber((f &&\n' + ' "sass") || (leans && mean));\n' + 'Test_very_long_variable_name_this_should_never_wrap\n' + ' .but_this_can\n' + 'return between_return_and_expression_should_never_wrap\n' + ' .but_this_can\n' + 'throw between_throw_and_expression_should_never_wrap\n' + ' .but_this_can\n' + 'if (wraps_can_occur &&\n' + ' inside_an_if_block) that_is_.okay();\n' + 'object_literal = {\n' + ' propertx: first_token +\n' + ' 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap +\n' + ' but_this_can,\n' + ' propertz: first_token_should_never_wrap +\n' + ' !but_this_can,\n' + ' proper: "first_token_should_never_wrap" +\n' + ' "but_this_can"\n' + '}') # Issue #1932 - Javascript object property with -/+ symbol wraps issue bt( '{\n' + ' "1234567891234567891234567891234": -433,\n' + ' "abcdefghijklmnopqrstuvwxyz12345": +11\n' + '}', # -- output -- '{\n' + ' "1234567891234567891234567891234": -433,\n' + ' "abcdefghijklmnopqrstuvwxyz12345": +11\n' + '}') test_fragment( '' + wrap_input_2 + '', # -- output -- '{\n' + ' foo.bar().baz().cucumber((f &&\n' + ' "sass") || (leans &&\n' + ' mean));\n' + ' Test_very_long_variable_name_this_should_never_wrap\n' + ' .but_this_can\n' + ' return between_return_and_expression_should_never_wrap\n' + ' .but_this_can\n' + ' throw between_throw_and_expression_should_never_wrap\n' + ' .but_this_can\n' + ' if (wraps_can_occur &&\n' + ' inside_an_if_block) that_is_\n' + ' .okay();\n' + ' object_literal = {\n' + ' propertx: first_token +\n' + ' 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap +\n' + ' but_this_can,\n' + ' propertz: first_token_should_never_wrap +\n' + ' !but_this_can,\n' + ' proper: "first_token_should_never_wrap" +\n' + ' "but_this_can"\n' + ' }\n' + '}') #============================================================ # line wrapping 41 self.reset_options() self.options.preserve_newlines = false self.options.wrap_line_length = 41 test_fragment( '' + wrap_input_1 + '', # -- output -- 'foo.bar().baz().cucumber((f && "sass") ||\n' + ' (leans && mean));\n' + 'Test_very_long_variable_name_this_should_never_wrap\n' + ' .but_this_can\n' + 'return between_return_and_expression_should_never_wrap\n' + ' .but_this_can\n' + 'throw between_throw_and_expression_should_never_wrap\n' + ' .but_this_can\n' + 'if (wraps_can_occur &&\n' + ' inside_an_if_block) that_is_.okay();\n' + 'object_literal = {\n' + ' propertx: first_token +\n' + ' 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap +\n' + ' but_this_can,\n' + ' propertz: first_token_should_never_wrap +\n' + ' !but_this_can,\n' + ' proper: "first_token_should_never_wrap" +\n' + ' "but_this_can"\n' + '}') test_fragment( '' + wrap_input_2 + '', # -- output -- '{\n' + ' foo.bar().baz().cucumber((f &&\n' + ' "sass") || (leans &&\n' + ' mean));\n' + ' Test_very_long_variable_name_this_should_never_wrap\n' + ' .but_this_can\n' + ' return between_return_and_expression_should_never_wrap\n' + ' .but_this_can\n' + ' throw between_throw_and_expression_should_never_wrap\n' + ' .but_this_can\n' + ' if (wraps_can_occur &&\n' + ' inside_an_if_block) that_is_\n' + ' .okay();\n' + ' object_literal = {\n' + ' propertx: first_token +\n' + ' 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap +\n' + ' but_this_can,\n' + ' propertz: first_token_should_never_wrap +\n' + ' !but_this_can,\n' + ' proper: "first_token_should_never_wrap" +\n' + ' "but_this_can"\n' + ' }\n' + '}') #============================================================ # line wrapping 45 self.reset_options() self.options.preserve_newlines = false self.options.wrap_line_length = 45 test_fragment( '' + wrap_input_1 + '', # -- output -- 'foo.bar().baz().cucumber((f && "sass") || (\n' + ' leans && mean));\n' + 'Test_very_long_variable_name_this_should_never_wrap\n' + ' .but_this_can\n' + 'return between_return_and_expression_should_never_wrap\n' + ' .but_this_can\n' + 'throw between_throw_and_expression_should_never_wrap\n' + ' .but_this_can\n' + 'if (wraps_can_occur && inside_an_if_block)\n' + ' that_is_.okay();\n' + 'object_literal = {\n' + ' propertx: first_token +\n' + ' 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap +\n' + ' but_this_can,\n' + ' propertz: first_token_should_never_wrap +\n' + ' !but_this_can,\n' + ' proper: "first_token_should_never_wrap" +\n' + ' "but_this_can"\n' + '}') test_fragment( '' + wrap_input_2 + '', # -- output -- '{\n' + ' foo.bar().baz().cucumber((f && "sass") ||\n' + ' (leans && mean));\n' + ' Test_very_long_variable_name_this_should_never_wrap\n' + ' .but_this_can\n' + ' return between_return_and_expression_should_never_wrap\n' + ' .but_this_can\n' + ' throw between_throw_and_expression_should_never_wrap\n' + ' .but_this_can\n' + ' if (wraps_can_occur &&\n' + ' inside_an_if_block) that_is_.okay();\n' + ' object_literal = {\n' + ' propertx: first_token +\n' + ' 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap +\n' + ' but_this_can,\n' + ' propertz: first_token_should_never_wrap +\n' + ' !but_this_can,\n' + ' proper: "first_token_should_never_wrap" +\n' + ' "but_this_can"\n' + ' }\n' + '}') #============================================================ # line wrapping 0 self.reset_options() self.options.preserve_newlines = true self.options.wrap_line_length = 0 test_fragment( '' + wrap_input_1 + '', # -- output -- 'foo.bar().baz().cucumber((f && "sass") || (leans && mean));\n' + 'Test_very_long_variable_name_this_should_never_wrap\n' + ' .but_this_can\n' + 'return between_return_and_expression_should_never_wrap.but_this_can\n' + 'throw between_throw_and_expression_should_never_wrap.but_this_can\n' + 'if (wraps_can_occur && inside_an_if_block) that_is_\n' + ' .okay();\n' + 'object_literal = {\n' + ' propertx: first_token + 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap + but_this_can,\n' + ' propertz: first_token_should_never_wrap + !but_this_can,\n' + ' proper: "first_token_should_never_wrap" + "but_this_can"\n' + '}') test_fragment( '' + wrap_input_2 + '', # -- output -- '{\n' + ' foo.bar().baz().cucumber((f && "sass") || (leans && mean));\n' + ' Test_very_long_variable_name_this_should_never_wrap\n' + ' .but_this_can\n' + ' return between_return_and_expression_should_never_wrap.but_this_can\n' + ' throw between_throw_and_expression_should_never_wrap.but_this_can\n' + ' if (wraps_can_occur && inside_an_if_block) that_is_\n' + ' .okay();\n' + ' object_literal = {\n' + ' propertx: first_token + 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap + but_this_can,\n' + ' propertz: first_token_should_never_wrap + !but_this_can,\n' + ' proper: "first_token_should_never_wrap" + "but_this_can"\n' + ' }\n' + '}') #============================================================ # line wrapping 70 self.reset_options() self.options.preserve_newlines = true self.options.wrap_line_length = 70 test_fragment( '' + wrap_input_1 + '', # -- output -- 'foo.bar().baz().cucumber((f && "sass") || (leans && mean));\n' + 'Test_very_long_variable_name_this_should_never_wrap\n' + ' .but_this_can\n' + 'return between_return_and_expression_should_never_wrap.but_this_can\n' + 'throw between_throw_and_expression_should_never_wrap.but_this_can\n' + 'if (wraps_can_occur && inside_an_if_block) that_is_\n' + ' .okay();\n' + 'object_literal = {\n' + ' propertx: first_token + 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap + but_this_can,\n' + ' propertz: first_token_should_never_wrap + !but_this_can,\n' + ' proper: "first_token_should_never_wrap" + "but_this_can"\n' + '}') test_fragment( '' + wrap_input_2 + '', # -- output -- '{\n' + ' foo.bar().baz().cucumber((f && "sass") || (leans && mean));\n' + ' Test_very_long_variable_name_this_should_never_wrap\n' + ' .but_this_can\n' + ' return between_return_and_expression_should_never_wrap\n' + ' .but_this_can\n' + ' throw between_throw_and_expression_should_never_wrap.but_this_can\n' + ' if (wraps_can_occur && inside_an_if_block) that_is_\n' + ' .okay();\n' + ' object_literal = {\n' + ' propertx: first_token + 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap + but_this_can,\n' + ' propertz: first_token_should_never_wrap + !but_this_can,\n' + ' proper: "first_token_should_never_wrap" + "but_this_can"\n' + ' }\n' + '}') #============================================================ # line wrapping 40 self.reset_options() self.options.preserve_newlines = true self.options.wrap_line_length = 40 test_fragment( '' + wrap_input_1 + '', # -- output -- 'foo.bar().baz().cucumber((f &&\n' + ' "sass") || (leans && mean));\n' + 'Test_very_long_variable_name_this_should_never_wrap\n' + ' .but_this_can\n' + 'return between_return_and_expression_should_never_wrap\n' + ' .but_this_can\n' + 'throw between_throw_and_expression_should_never_wrap\n' + ' .but_this_can\n' + 'if (wraps_can_occur &&\n' + ' inside_an_if_block) that_is_\n' + ' .okay();\n' + 'object_literal = {\n' + ' propertx: first_token +\n' + ' 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap +\n' + ' but_this_can,\n' + ' propertz: first_token_should_never_wrap +\n' + ' !but_this_can,\n' + ' proper: "first_token_should_never_wrap" +\n' + ' "but_this_can"\n' + '}') test_fragment( '' + wrap_input_2 + '', # -- output -- '{\n' + ' foo.bar().baz().cucumber((f &&\n' + ' "sass") || (leans &&\n' + ' mean));\n' + ' Test_very_long_variable_name_this_should_never_wrap\n' + ' .but_this_can\n' + ' return between_return_and_expression_should_never_wrap\n' + ' .but_this_can\n' + ' throw between_throw_and_expression_should_never_wrap\n' + ' .but_this_can\n' + ' if (wraps_can_occur &&\n' + ' inside_an_if_block) that_is_\n' + ' .okay();\n' + ' object_literal = {\n' + ' propertx: first_token +\n' + ' 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap +\n' + ' but_this_can,\n' + ' propertz: first_token_should_never_wrap +\n' + ' !but_this_can,\n' + ' proper: "first_token_should_never_wrap" +\n' + ' "but_this_can"\n' + ' }\n' + '}') #============================================================ # line wrapping 41 self.reset_options() self.options.preserve_newlines = true self.options.wrap_line_length = 41 test_fragment( '' + wrap_input_1 + '', # -- output -- 'foo.bar().baz().cucumber((f && "sass") ||\n' + ' (leans && mean));\n' + 'Test_very_long_variable_name_this_should_never_wrap\n' + ' .but_this_can\n' + 'return between_return_and_expression_should_never_wrap\n' + ' .but_this_can\n' + 'throw between_throw_and_expression_should_never_wrap\n' + ' .but_this_can\n' + 'if (wraps_can_occur &&\n' + ' inside_an_if_block) that_is_\n' + ' .okay();\n' + 'object_literal = {\n' + ' propertx: first_token +\n' + ' 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap +\n' + ' but_this_can,\n' + ' propertz: first_token_should_never_wrap +\n' + ' !but_this_can,\n' + ' proper: "first_token_should_never_wrap" +\n' + ' "but_this_can"\n' + '}') test_fragment( '' + wrap_input_2 + '', # -- output -- '{\n' + ' foo.bar().baz().cucumber((f &&\n' + ' "sass") || (leans &&\n' + ' mean));\n' + ' Test_very_long_variable_name_this_should_never_wrap\n' + ' .but_this_can\n' + ' return between_return_and_expression_should_never_wrap\n' + ' .but_this_can\n' + ' throw between_throw_and_expression_should_never_wrap\n' + ' .but_this_can\n' + ' if (wraps_can_occur &&\n' + ' inside_an_if_block) that_is_\n' + ' .okay();\n' + ' object_literal = {\n' + ' propertx: first_token +\n' + ' 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap +\n' + ' but_this_can,\n' + ' propertz: first_token_should_never_wrap +\n' + ' !but_this_can,\n' + ' proper: "first_token_should_never_wrap" +\n' + ' "but_this_can"\n' + ' }\n' + '}') #============================================================ # line wrapping 45 self.reset_options() self.options.preserve_newlines = true self.options.wrap_line_length = 45 test_fragment( '' + wrap_input_1 + '', # -- output -- 'foo.bar().baz().cucumber((f && "sass") || (\n' + ' leans && mean));\n' + 'Test_very_long_variable_name_this_should_never_wrap\n' + ' .but_this_can\n' + 'return between_return_and_expression_should_never_wrap\n' + ' .but_this_can\n' + 'throw between_throw_and_expression_should_never_wrap\n' + ' .but_this_can\n' + 'if (wraps_can_occur && inside_an_if_block)\n' + ' that_is_\n' + ' .okay();\n' + 'object_literal = {\n' + ' propertx: first_token +\n' + ' 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap +\n' + ' but_this_can,\n' + ' propertz: first_token_should_never_wrap +\n' + ' !but_this_can,\n' + ' proper: "first_token_should_never_wrap" +\n' + ' "but_this_can"\n' + '}') test_fragment( '' + wrap_input_2 + '', # -- output -- '{\n' + ' foo.bar().baz().cucumber((f && "sass") ||\n' + ' (leans && mean));\n' + ' Test_very_long_variable_name_this_should_never_wrap\n' + ' .but_this_can\n' + ' return between_return_and_expression_should_never_wrap\n' + ' .but_this_can\n' + ' throw between_throw_and_expression_should_never_wrap\n' + ' .but_this_can\n' + ' if (wraps_can_occur &&\n' + ' inside_an_if_block) that_is_\n' + ' .okay();\n' + ' object_literal = {\n' + ' propertx: first_token +\n' + ' 12345678.99999E-6,\n' + ' property: first_token_should_never_wrap +\n' + ' but_this_can,\n' + ' propertz: first_token_should_never_wrap +\n' + ' !but_this_can,\n' + ' proper: "first_token_should_never_wrap" +\n' + ' "but_this_can"\n' + ' }\n' + '}') #============================================================ # general preserve_newlines tests preserve limit self.reset_options() self.options.preserve_newlines = true self.options.max_preserve_newlines = 8 bt( 'a = 1;\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + 'b = 2;', # -- output -- 'a = 1;\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + '\n' + 'b = 2;') #============================================================ # more random test self.reset_options() bt('return function();') bt('var a = function();') bt('var a = 5 + function();') # actionscript import bt('import foo.*;') # actionscript bt('function f(a: a, b: b)') bt( 'function a(a) {} function b(b) {} function c(c) {}', # -- output -- 'function a(a) {}\n' + '\n' + 'function b(b) {}\n' + '\n' + 'function c(c) {}') bt('foo(a, function() {})') bt('foo(a, /regex/)') bt( '/* foo */\n' + '"x"') test_fragment( 'roo = {\n' + ' /*\n' + ' ****\n' + ' FOO\n' + ' ****\n' + ' */\n' + ' BAR: 0\n' + '};') test_fragment( 'if (zz) {\n' + ' // ....\n' + '}\n' + '(function') bt( 'a = //comment\n' + ' /regex/;') bt('var a = new function();') bt('new function') bt( 'if (a)\n' + '{\n' + 'b;\n' + '}\n' + 'else\n' + '{\n' + 'c;\n' + '}', # -- output -- 'if (a) {\n' + ' b;\n' + '} else {\n' + ' c;\n' + '}') bt('fn`tagged`') bt('fn()`tagged`') bt('fn`${algo} ${`6string`}`') bt('fn`${fn2()} more text ${`${`more text`}`} banana ${fn3`test`} ${fn4()`moretest banana2`}`') bt('`untagged`+`untagged`', '`untagged` + `untagged`') bt('fun() `taggedd`') bt('fn[0]`tagged`', 'fn[0] `tagged`') #============================================================ # operator_position option - ensure no newlines if preserve_newlines is false - (preserve_newlines = "false") self.reset_options() self.options.preserve_newlines = false bt( 'var res = a + b - c / d * e % f;\n' + 'var res = g & h | i ^ j |> console.log;\n' + 'var res = (k && l || m) ? n ?? nn : o;\n' + 'var res = p >> q << r >>> s;\n' + 'var res = t === u !== v != w == x >= y <= z > aa < ab;\n' + 'res ??= a;\n' + 'res ||= b;\n' + 'res &&= c;\n' + 'ac + -ad') bt( 'var res = a + b\n' + '- c /\n' + 'd * e\n' + '%\n' + 'f;\n' + ' var res = g & h\n' + '| i ^\n' + 'j\n' + '|> console.log;\n' + 'var res = (k &&\n' + 'l\n' + '|| m) ?\n' + 'n\n' + '?? nn\n' + ': o\n' + ';\n' + 'var res = p\n' + '>> q <<\n' + 'r\n' + '>>> s;\n' + 'var res\n' + ' = t\n' + '\n' + ' === u !== v\n' + ' !=\n' + 'w\n' + '== x >=\n' + 'y <= z > aa <\n' + 'ab;\n' + 'res??=a;res||=b;res&&=c;\n' + 'ac +\n' + '-ad', # -- output -- 'var res = a + b - c / d * e % f;\n' + 'var res = g & h | i ^ j |> console.log;\n' + 'var res = (k && l || m) ? n ?? nn : o;\n' + 'var res = p >> q << r >>> s;\n' + 'var res = t === u !== v != w == x >= y <= z > aa < ab;\n' + 'res ??= a;\n' + 'res ||= b;\n' + 'res &&= c;\n' + 'ac + -ad') # operator_position option - ensure no newlines if preserve_newlines is false - (operator_position = ""before-newline"", preserve_newlines = "false") self.reset_options() self.options.operator_position = 'before-newline' self.options.preserve_newlines = false bt( 'var res = a + b - c / d * e % f;\n' + 'var res = g & h | i ^ j |> console.log;\n' + 'var res = (k && l || m) ? n ?? nn : o;\n' + 'var res = p >> q << r >>> s;\n' + 'var res = t === u !== v != w == x >= y <= z > aa < ab;\n' + 'res ??= a;\n' + 'res ||= b;\n' + 'res &&= c;\n' + 'ac + -ad') bt( 'var res = a + b\n' + '- c /\n' + 'd * e\n' + '%\n' + 'f;\n' + ' var res = g & h\n' + '| i ^\n' + 'j\n' + '|> console.log;\n' + 'var res = (k &&\n' + 'l\n' + '|| m) ?\n' + 'n\n' + '?? nn\n' + ': o\n' + ';\n' + 'var res = p\n' + '>> q <<\n' + 'r\n' + '>>> s;\n' + 'var res\n' + ' = t\n' + '\n' + ' === u !== v\n' + ' !=\n' + 'w\n' + '== x >=\n' + 'y <= z > aa <\n' + 'ab;\n' + 'res??=a;res||=b;res&&=c;\n' + 'ac +\n' + '-ad', # -- output -- 'var res = a + b - c / d * e % f;\n' + 'var res = g & h | i ^ j |> console.log;\n' + 'var res = (k && l || m) ? n ?? nn : o;\n' + 'var res = p >> q << r >>> s;\n' + 'var res = t === u !== v != w == x >= y <= z > aa < ab;\n' + 'res ??= a;\n' + 'res ||= b;\n' + 'res &&= c;\n' + 'ac + -ad') # operator_position option - ensure no newlines if preserve_newlines is false - (operator_position = ""after-newline"", preserve_newlines = "false") self.reset_options() self.options.operator_position = 'after-newline' self.options.preserve_newlines = false bt( 'var res = a + b - c / d * e % f;\n' + 'var res = g & h | i ^ j |> console.log;\n' + 'var res = (k && l || m) ? n ?? nn : o;\n' + 'var res = p >> q << r >>> s;\n' + 'var res = t === u !== v != w == x >= y <= z > aa < ab;\n' + 'res ??= a;\n' + 'res ||= b;\n' + 'res &&= c;\n' + 'ac + -ad') bt( 'var res = a + b\n' + '- c /\n' + 'd * e\n' + '%\n' + 'f;\n' + ' var res = g & h\n' + '| i ^\n' + 'j\n' + '|> console.log;\n' + 'var res = (k &&\n' + 'l\n' + '|| m) ?\n' + 'n\n' + '?? nn\n' + ': o\n' + ';\n' + 'var res = p\n' + '>> q <<\n' + 'r\n' + '>>> s;\n' + 'var res\n' + ' = t\n' + '\n' + ' === u !== v\n' + ' !=\n' + 'w\n' + '== x >=\n' + 'y <= z > aa <\n' + 'ab;\n' + 'res??=a;res||=b;res&&=c;\n' + 'ac +\n' + '-ad', # -- output -- 'var res = a + b - c / d * e % f;\n' + 'var res = g & h | i ^ j |> console.log;\n' + 'var res = (k && l || m) ? n ?? nn : o;\n' + 'var res = p >> q << r >>> s;\n' + 'var res = t === u !== v != w == x >= y <= z > aa < ab;\n' + 'res ??= a;\n' + 'res ||= b;\n' + 'res &&= c;\n' + 'ac + -ad') # operator_position option - ensure no newlines if preserve_newlines is false - (operator_position = ""preserve-newline"", preserve_newlines = "false") self.reset_options() self.options.operator_position = 'preserve-newline' self.options.preserve_newlines = false bt( 'var res = a + b - c / d * e % f;\n' + 'var res = g & h | i ^ j |> console.log;\n' + 'var res = (k && l || m) ? n ?? nn : o;\n' + 'var res = p >> q << r >>> s;\n' + 'var res = t === u !== v != w == x >= y <= z > aa < ab;\n' + 'res ??= a;\n' + 'res ||= b;\n' + 'res &&= c;\n' + 'ac + -ad') bt( 'var res = a + b\n' + '- c /\n' + 'd * e\n' + '%\n' + 'f;\n' + ' var res = g & h\n' + '| i ^\n' + 'j\n' + '|> console.log;\n' + 'var res = (k &&\n' + 'l\n' + '|| m) ?\n' + 'n\n' + '?? nn\n' + ': o\n' + ';\n' + 'var res = p\n' + '>> q <<\n' + 'r\n' + '>>> s;\n' + 'var res\n' + ' = t\n' + '\n' + ' === u !== v\n' + ' !=\n' + 'w\n' + '== x >=\n' + 'y <= z > aa <\n' + 'ab;\n' + 'res??=a;res||=b;res&&=c;\n' + 'ac +\n' + '-ad', # -- output -- 'var res = a + b - c / d * e % f;\n' + 'var res = g & h | i ^ j |> console.log;\n' + 'var res = (k && l || m) ? n ?? nn : o;\n' + 'var res = p >> q << r >>> s;\n' + 'var res = t === u !== v != w == x >= y <= z > aa < ab;\n' + 'res ??= a;\n' + 'res ||= b;\n' + 'res &&= c;\n' + 'ac + -ad') #============================================================ # operator_position option - set to "before-newline" (default value) - () self.reset_options() # comprehensive, various newlines bt( 'var res = a + b\n' + '- c /\n' + 'd * e\n' + '%\n' + 'f;\n' + ' var res = g & h\n' + '| i ^\n' + 'j\n' + '|> console.log;\n' + 'var res = (k &&\n' + 'l\n' + '|| m) ?\n' + 'n\n' + '?? nn\n' + ': o\n' + ';\n' + 'var res = p\n' + '>> q <<\n' + 'r\n' + '>>> s;\n' + 'var res\n' + ' = t\n' + '\n' + ' === u !== v\n' + ' !=\n' + 'w\n' + '== x >=\n' + 'y <= z > aa <\n' + 'ab;\n' + 'res??=a;res||=b;res&&=c;\n' + 'ac +\n' + '-ad', # -- output -- 'var res = a + b -\n' + ' c /\n' + ' d * e %\n' + ' f;\n' + 'var res = g & h |\n' + ' i ^\n' + ' j |>\n' + ' console.log;\n' + 'var res = (k &&\n' + ' l ||\n' + ' m) ?\n' + ' n ??\n' + ' nn :\n' + ' o;\n' + 'var res = p >>\n' + ' q <<\n' + ' r >>>\n' + ' s;\n' + 'var res = t\n' + '\n' + ' ===\n' + ' u !== v !=\n' + ' w ==\n' + ' x >=\n' + ' y <= z > aa <\n' + ' ab;\n' + 'res ??= a;\n' + 'res ||= b;\n' + 'res &&= c;\n' + 'ac +\n' + ' -ad') # colon special case bt( 'var a = {\n' + ' b\n' + ': bval,\n' + ' c:\n' + 'cval\n' + ' ,d: dval\n' + '};\n' + 'var e = f ? g\n' + ': h;\n' + 'var i = j ? k :\n' + 'l;', # -- output -- 'var a = {\n' + ' b: bval,\n' + ' c: cval,\n' + ' d: dval\n' + '};\n' + 'var e = f ? g :\n' + ' h;\n' + 'var i = j ? k :\n' + ' l;') # catch-all, includes brackets and other various code bt( 'var d = 1;\n' + 'if (a === b\n' + ' && c) {\n' + ' d = (c * everything\n' + ' / something_else) %\n' + ' b;\n' + ' e\n' + ' += d;\n' + '\n' + '} else if (!(complex && simple) ||\n' + ' (emotion && emotion.name === "happy")) {\n' + ' cryTearsOfJoy(many ||\n' + ' anOcean\n' + ' || aRiver);\n' + '}', # -- output -- 'var d = 1;\n' + 'if (a === b &&\n' + ' c) {\n' + ' d = (c * everything /\n' + ' something_else) %\n' + ' b;\n' + ' e\n' + ' += d;\n' + '\n' + '} else if (!(complex && simple) ||\n' + ' (emotion && emotion.name === "happy")) {\n' + ' cryTearsOfJoy(many ||\n' + ' anOcean ||\n' + ' aRiver);\n' + '}') # operator_position option - set to "before-newline" (default value) - (operator_position = ""before-newline"") self.reset_options() self.options.operator_position = 'before-newline' # comprehensive, various newlines bt( 'var res = a + b\n' + '- c /\n' + 'd * e\n' + '%\n' + 'f;\n' + ' var res = g & h\n' + '| i ^\n' + 'j\n' + '|> console.log;\n' + 'var res = (k &&\n' + 'l\n' + '|| m) ?\n' + 'n\n' + '?? nn\n' + ': o\n' + ';\n' + 'var res = p\n' + '>> q <<\n' + 'r\n' + '>>> s;\n' + 'var res\n' + ' = t\n' + '\n' + ' === u !== v\n' + ' !=\n' + 'w\n' + '== x >=\n' + 'y <= z > aa <\n' + 'ab;\n' + 'res??=a;res||=b;res&&=c;\n' + 'ac +\n' + '-ad', # -- output -- 'var res = a + b -\n' + ' c /\n' + ' d * e %\n' + ' f;\n' + 'var res = g & h |\n' + ' i ^\n' + ' j |>\n' + ' console.log;\n' + 'var res = (k &&\n' + ' l ||\n' + ' m) ?\n' + ' n ??\n' + ' nn :\n' + ' o;\n' + 'var res = p >>\n' + ' q <<\n' + ' r >>>\n' + ' s;\n' + 'var res = t\n' + '\n' + ' ===\n' + ' u !== v !=\n' + ' w ==\n' + ' x >=\n' + ' y <= z > aa <\n' + ' ab;\n' + 'res ??= a;\n' + 'res ||= b;\n' + 'res &&= c;\n' + 'ac +\n' + ' -ad') # colon special case bt( 'var a = {\n' + ' b\n' + ': bval,\n' + ' c:\n' + 'cval\n' + ' ,d: dval\n' + '};\n' + 'var e = f ? g\n' + ': h;\n' + 'var i = j ? k :\n' + 'l;', # -- output -- 'var a = {\n' + ' b: bval,\n' + ' c: cval,\n' + ' d: dval\n' + '};\n' + 'var e = f ? g :\n' + ' h;\n' + 'var i = j ? k :\n' + ' l;') # catch-all, includes brackets and other various code bt( 'var d = 1;\n' + 'if (a === b\n' + ' && c) {\n' + ' d = (c * everything\n' + ' / something_else) %\n' + ' b;\n' + ' e\n' + ' += d;\n' + '\n' + '} else if (!(complex && simple) ||\n' + ' (emotion && emotion.name === "happy")) {\n' + ' cryTearsOfJoy(many ||\n' + ' anOcean\n' + ' || aRiver);\n' + '}', # -- output -- 'var d = 1;\n' + 'if (a === b &&\n' + ' c) {\n' + ' d = (c * everything /\n' + ' something_else) %\n' + ' b;\n' + ' e\n' + ' += d;\n' + '\n' + '} else if (!(complex && simple) ||\n' + ' (emotion && emotion.name === "happy")) {\n' + ' cryTearsOfJoy(many ||\n' + ' anOcean ||\n' + ' aRiver);\n' + '}') #============================================================ # operator_position option - set to "after_newline" self.reset_options() self.options.operator_position = 'after-newline' # comprehensive, various newlines bt( 'var res = a + b\n' + '- c /\n' + 'd * e\n' + '%\n' + 'f;\n' + ' var res = g & h\n' + '| i ^\n' + 'j\n' + '|> console.log;\n' + 'var res = (k &&\n' + 'l\n' + '|| m) ?\n' + 'n\n' + '?? nn\n' + ': o\n' + ';\n' + 'var res = p\n' + '>> q <<\n' + 'r\n' + '>>> s;\n' + 'var res\n' + ' = t\n' + '\n' + ' === u !== v\n' + ' !=\n' + 'w\n' + '== x >=\n' + 'y <= z > aa <\n' + 'ab;\n' + 'res??=a;res||=b;res&&=c;\n' + 'ac +\n' + '-ad', # -- output -- 'var res = a + b\n' + ' - c\n' + ' / d * e\n' + ' % f;\n' + 'var res = g & h\n' + ' | i\n' + ' ^ j\n' + ' |> console.log;\n' + 'var res = (k\n' + ' && l\n' + ' || m)\n' + ' ? n\n' + ' ?? nn\n' + ' : o;\n' + 'var res = p\n' + ' >> q\n' + ' << r\n' + ' >>> s;\n' + 'var res = t\n' + '\n' + ' === u !== v\n' + ' != w\n' + ' == x\n' + ' >= y <= z > aa\n' + ' < ab;\n' + 'res ??= a;\n' + 'res ||= b;\n' + 'res &&= c;\n' + 'ac\n' + ' + -ad') # colon special case bt( 'var a = {\n' + ' b\n' + ': bval,\n' + ' c:\n' + 'cval\n' + ' ,d: dval\n' + '};\n' + 'var e = f ? g\n' + ': h;\n' + 'var i = j ? k :\n' + 'l;', # -- output -- 'var a = {\n' + ' b: bval,\n' + ' c: cval,\n' + ' d: dval\n' + '};\n' + 'var e = f ? g\n' + ' : h;\n' + 'var i = j ? k\n' + ' : l;') # catch-all, includes brackets and other various code bt( 'var d = 1;\n' + 'if (a === b\n' + ' && c) {\n' + ' d = (c * everything\n' + ' / something_else) %\n' + ' b;\n' + ' e\n' + ' += d;\n' + '\n' + '} else if (!(complex && simple) ||\n' + ' (emotion && emotion.name === "happy")) {\n' + ' cryTearsOfJoy(many ||\n' + ' anOcean\n' + ' || aRiver);\n' + '}', # -- output -- 'var d = 1;\n' + 'if (a === b\n' + ' && c) {\n' + ' d = (c * everything\n' + ' / something_else)\n' + ' % b;\n' + ' e\n' + ' += d;\n' + '\n' + '} else if (!(complex && simple)\n' + ' || (emotion && emotion.name === "happy")) {\n' + ' cryTearsOfJoy(many\n' + ' || anOcean\n' + ' || aRiver);\n' + '}') #============================================================ # operator_position option - set to "preserve-newline" self.reset_options() self.options.operator_position = 'preserve-newline' # comprehensive, various newlines bt( 'var res = a + b\n' + '- c /\n' + 'd * e\n' + '%\n' + 'f;\n' + ' var res = g & h\n' + '| i ^\n' + 'j\n' + '|> console.log;\n' + 'var res = (k &&\n' + 'l\n' + '|| m) ?\n' + 'n\n' + '?? nn\n' + ': o\n' + ';\n' + 'var res = p\n' + '>> q <<\n' + 'r\n' + '>>> s;\n' + 'var res\n' + ' = t\n' + '\n' + ' === u !== v\n' + ' !=\n' + 'w\n' + '== x >=\n' + 'y <= z > aa <\n' + 'ab;\n' + 'res??=a;res||=b;res&&=c;\n' + 'ac +\n' + '-ad', # -- output -- 'var res = a + b\n' + ' - c /\n' + ' d * e\n' + ' %\n' + ' f;\n' + 'var res = g & h\n' + ' | i ^\n' + ' j\n' + ' |> console.log;\n' + 'var res = (k &&\n' + ' l\n' + ' || m) ?\n' + ' n\n' + ' ?? nn\n' + ' : o;\n' + 'var res = p\n' + ' >> q <<\n' + ' r\n' + ' >>> s;\n' + 'var res = t\n' + '\n' + ' === u !== v\n' + ' !=\n' + ' w\n' + ' == x >=\n' + ' y <= z > aa <\n' + ' ab;\n' + 'res ??= a;\n' + 'res ||= b;\n' + 'res &&= c;\n' + 'ac +\n' + ' -ad') # colon special case bt( 'var a = {\n' + ' b\n' + ': bval,\n' + ' c:\n' + 'cval\n' + ' ,d: dval\n' + '};\n' + 'var e = f ? g\n' + ': h;\n' + 'var i = j ? k :\n' + 'l;', # -- output -- 'var a = {\n' + ' b: bval,\n' + ' c: cval,\n' + ' d: dval\n' + '};\n' + 'var e = f ? g\n' + ' : h;\n' + 'var i = j ? k :\n' + ' l;') # catch-all, includes brackets and other various code bt( 'var d = 1;\n' + 'if (a === b\n' + ' && c) {\n' + ' d = (c * everything\n' + ' / something_else) %\n' + ' b;\n' + ' e\n' + ' += d;\n' + '\n' + '} else if (!(complex && simple) ||\n' + ' (emotion && emotion.name === "happy")) {\n' + ' cryTearsOfJoy(many ||\n' + ' anOcean\n' + ' || aRiver);\n' + '}') #============================================================ # Yield tests self.reset_options() bt('yield /foo\\//;') bt('result = yield pgClient.query_(queryString);') bt('yield [1, 2]') bt('yield function() {};') bt('yield* bar();') # yield should have no space between yield and star bt('yield * bar();', 'yield* bar();') # yield should have space between star and generator bt('yield *bar();', 'yield* bar();') #============================================================ # Async / await tests self.reset_options() bt('async function foo() {}') bt('let w = async function foo() {}') bt( 'async function foo() {}\n' + 'var x = await foo();') # async function as an input to another function bt('wrapper(async function foo() {})') # await on inline anonymous function. should have a space after await bt( 'async function() {\n' + ' var w = await(async function() {\n' + ' return await foo();\n' + ' })();\n' + '}', # -- output -- 'async function() {\n' + ' var w = await (async function() {\n' + ' return await foo();\n' + ' })();\n' + '}') # Regression test #1228 bt('const module = await import("...")') # Regression test #1658 bt('.') # ensure that this doesn't break anyone with the async library bt('async.map(function(t) {})') # async on arrow function. should have a space after async bt( 'async() => {}', # -- output -- 'async () => {}') # async on arrow function. should have a space after async bt( 'async() => {\n' + ' return 5;\n' + '}', # -- output -- 'async () => {\n' + ' return 5;\n' + '}') # async on arrow function returning expression. should have a space after async bt( 'async() => 5;', # -- output -- 'async () => 5;') # async on arrow function returning object literal. should have a space after async bt( 'async(x) => ({\n' + ' foo: "5"\n' + '})', # -- output -- 'async (x) => ({\n' + ' foo: "5"\n' + '})') bt( 'async (x) => {\n' + ' return x * 2;\n' + '}') bt('async () => 5;') bt('async x => x * 2;') bt( 'async function() {\n' + ' const obj = {\n' + ' a: 1,\n' + ' b: await fn(),\n' + ' c: 2\n' + ' };\n' + '}') bt( 'const a = 1,\n' + ' b = a ? await foo() : b,\n' + ' c = await foo(),\n' + ' d = 3,\n' + ' e = (await foo()),\n' + ' f = 4;') bt( 'a = {\n' + ' myVar: async function() {\n' + ' return a;\n' + ' },\n' + ' myOtherVar: async function() {\n' + ' yield b;\n' + ' }\n' + '}') bt( 'a = {\n' + ' myVar: async () => {\n' + ' return a;\n' + ' },\n' + ' myOtherVar: async async () => {\n' + ' yield b;\n' + ' }\n' + '}') #============================================================ # e4x - Test that e4x literals passed through when e4x-option is enabled self.reset_options() self.options.e4x = true bt( 'xml=\n' + ' foox;', # -- output -- 'xml = \n' + ' foox;') bt('') bt('') bt('') bt('') bt('') # Handles inline expressions bt( 'xml=<{a} b="c">\n' + ' foox;', # -- output -- 'xml = <{a} b="c">\n' + ' foox;') bt( 'xml=<{a} b="c">\n' + ' \n' + ' foox;', # -- output -- 'xml = <{a} b="c">\n' + ' \n' + ' foox;') # xml literals with special characters in elem names - see http://www.w3.org/TR/REC-xml/#NT-NameChar bt('xml = <_:.valid.xml- _:.valid.xml-="123"/>;') # xml literals with attributes without equal sign bt('xml = ;') # Handles CDATA bt( 'xml=\n' + ' foox/]]>;', # -- output -- 'xml = \n' + ' foox/]]>;') bt('xml=;', 'xml = ;') bt('xml=;', 'xml = ;') # JSX - working jsx from http://prettydiff.com/unit_tests/beautification_javascript_jsx.txt bt( 'var ListItem = React.createClass({\n' + ' render: function() {\n' + ' return (\n' + '
  • \n' + ' \n' + ' this.props.item.name\n' + ' \n' + '
  • \n' + ' );\n' + ' }\n' + '});') bt( 'var List = React.createClass({\n' + ' renderList: function() {\n' + ' return this.props.items.map(function(item) {\n' + ' return ;\n' + ' });\n' + ' },\n' + '\n' + ' render: function() {\n' + ' return
      \n' + ' this.renderList()\n' + '
    \n' + ' }\n' + '});') bt( 'var Mist = React.createClass({\n' + ' renderList: function() {\n' + ' return this.props.items.map(function(item) {\n' + ' return {item}} key={item.id} />;\n' + ' });\n' + ' }\n' + '});') bt( '// JSX\n' + 'var box = \n' + ' {shouldShowAnswer(user) ?\n' + ' no : \n' + ' Text Content\n' + ' }\n' + ' ;\n' + 'var a = function() {\n' + ' return asdf;\n' + '};\n' + '\n' + 'var HelloMessage = React.createClass({\n' + ' render: function() {\n' + ' return
    Hello {this.props.name}
    ;\n' + ' }\n' + '});\n' + 'React.render(, mountNode);') bt( 'var Timer = React.createClass({\n' + ' getInitialState: function() {\n' + ' return {\n' + ' secondsElapsed: 0\n' + ' };\n' + ' },\n' + ' tick: function() {\n' + ' this.setState({\n' + ' secondsElapsed: this.state.secondsElapsed + 1\n' + ' });\n' + ' },\n' + ' componentDidMount: function() {\n' + ' this.interval = setInterval(this.tick, 1000);\n' + ' },\n' + ' componentWillUnmount: function() {\n' + ' clearInterval(this.interval);\n' + ' },\n' + ' render: function() {\n' + ' return (\n' + '
    Seconds Elapsed: {this.state.secondsElapsed}
    \n' + ' );\n' + ' }\n' + '});\n' + 'React.render(, mountNode);') bt( 'var TodoList = React.createClass({\n' + ' render: function() {\n' + ' var createItem = function(itemText) {\n' + ' return
  • {itemText}
  • ;\n' + ' };\n' + ' return
      {this.props.items.map(createItem)}
    ;\n' + ' }\n' + '});') bt( 'var TodoApp = React.createClass({\n' + ' getInitialState: function() {\n' + ' return {\n' + ' items: [],\n' + ' text: \'\'\n' + ' };\n' + ' },\n' + ' onChange: function(e) {\n' + ' this.setState({\n' + ' text: e.target.value\n' + ' });\n' + ' },\n' + ' handleSubmit: function(e) {\n' + ' e.preventDefault();\n' + ' var nextItems = this.state.items.concat([this.state.text]);\n' + ' var nextText = \'\';\n' + ' this.setState({\n' + ' items: nextItems,\n' + ' text: nextText\n' + ' });\n' + ' },\n' + ' render: function() {\n' + ' return (\n' + '
    \n' + '

    TODO

    \n' + ' \n' + '
    \n' + ' \n' + ' \n' + '
    \n' + '
    \n' + ' );\n' + ' }\n' + '});\n' + 'React.render(, mountNode);') bt( 'var converter = new Showdown.converter();\n' + 'var MarkdownEditor = React.createClass({\n' + ' getInitialState: function() {\n' + ' return {value: \'Type some *markdown* here!\'};\n' + ' },\n' + ' handleChange: function() {\n' + ' this.setState({value: this.refs.textarea.getDOMNode().value});\n' + ' },\n' + ' render: function() {\n' + ' return (\n' + '
    \n' + '

    Input

    \n' + ' \n' + '

    Output

    \n' + ' \n' + '
    \n' + ' );\n' + ' }\n' + '});\n' + 'React.render(, mountNode);', # -- output -- 'var converter = new Showdown.converter();\n' + 'var MarkdownEditor = React.createClass({\n' + ' getInitialState: function() {\n' + ' return {\n' + ' value: \'Type some *markdown* here!\'\n' + ' };\n' + ' },\n' + ' handleChange: function() {\n' + ' this.setState({\n' + ' value: this.refs.textarea.getDOMNode().value\n' + ' });\n' + ' },\n' + ' render: function() {\n' + ' return (\n' + '
    \n' + '

    Input

    \n' + ' \n' + '

    Output

    \n' + ' \n' + '
    \n' + ' );\n' + ' }\n' + '});\n' + 'React.render(, mountNode);') # JSX - Not quite correct jsx formatting that still works bt( 'var content = (\n' + ' \n' + ' );\n' + 'var qwer = A dropdown list Do Something Do Something Fun! Do Something Else ;\n' + 'render(dropdown);', # -- output -- 'var content = (\n' + ' \n' + ');\n' + 'var qwer = A dropdown list Do Something Do Something Fun! Do Something Else ;\n' + 'render(dropdown);') # Handles messed up tags, as long as it isn't the same name # as the root tag. Also handles tags of same name as root tag # as long as nesting matches. bt( 'xml=;', # -- output -- 'xml = ;') # If xml is not terminated, the remainder of the file is treated # as part of the xml-literal (passed through unaltered) test_fragment( 'xml=\n' + 'c\n' + 'c\n' + ' c\n' + '

    \n' + ' );\n' + ' }\n' + '});') bt( 'let a = React.createClass({\n' + ' render() {\n' + ' return (\n' + '

    \n' + ' c\n' + '

    \n' + ' );\n' + ' }\n' + '});') bt( 'let a = React.createClass({\n' + ' render() {\n' + ' return (\n' + '

    \n' + ' c\n' + '

    \n' + ' );\n' + ' }\n' + '});') bt( 'let a = React.createClass({\n' + ' render() {\n' + ' return (\n' + ' <{e} className = {d}>\n' + ' c\n' + ' \n' + ' );\n' + ' }\n' + '});') # Issue #914 - Multiline attribute in root tag bt( 'return (\n' + '
    {\n' + ' e.preventDefault()\n' + ' onClick()\n' + ' }}>\n' + ' {children}\n' + ' \n' + ');') bt( 'return (\n' + ' <{\n' + ' a + b\n' + ' } href="#"\n' + ' onClick={e => {\n' + ' e.preventDefault()\n' + ' onClick()\n' + ' }}>\n' + ' {children}\n' + ' \n' + ');') bt( 'return (\n' + ' <{\n' + ' a + b\n' + ' } href="#"\n' + ' onClick={e => {\n' + ' e.preventDefault()\n' + ' onClick()\n' + ' }}>\n' + ' {children}\n' + ' \n' + ' );', # -- output -- 'return (\n' + ' <{\n' + ' a + b\n' + ' } href="#"\n' + ' onClick={e => {\n' + ' e.preventDefault()\n' + ' onClick()\n' + ' }}>\n' + ' {children}\n' + ' \n' + ');') bt( 'class Columns extends React.Component {\n' + ' render() {\n' + ' return (\n' + ' <>\n' + ' Hello\n' + ' World\n' + ' \n' + ' );\n' + ' }\n' + '}') #============================================================ # self.reset_options() #============================================================ # e4x disabled self.reset_options() self.options.e4x = false bt( 'xml=\n' + ' foox;', # -- output -- 'xml = < a b = "c" > < d / > < e >\n' + ' foo < /e>x ;') #============================================================ # Multiple braces self.reset_options() bt( '{{}/z/}', # -- output -- '{\n' + ' {}\n' + ' /z/\n' + '}') #============================================================ # Space before conditional - (space_before_conditional = "false") self.reset_options() self.options.space_before_conditional = false bt('if(a) b()') bt('while(a) b()') bt( 'do\n' + ' c();\n' + 'while(a) b()') bt('switch(a) b()') bt( 'if(a)\n' + 'b();', # -- output -- 'if(a)\n' + ' b();') bt( 'while(a)\n' + 'b();', # -- output -- 'while(a)\n' + ' b();') bt( 'do\n' + 'c();\n' + 'while(a);', # -- output -- 'do\n' + ' c();\n' + 'while(a);') bt( 'switch(a)\n' + 'b()', # -- output -- 'switch(a)\n' + ' b()') bt('return [];') bt('return ();') # Space before conditional - (space_before_conditional = "true") self.reset_options() self.options.space_before_conditional = true bt('if (a) b()') bt('while (a) b()') bt( 'do\n' + ' c();\n' + 'while (a) b()') bt('switch (a) b()') bt( 'if(a)\n' + 'b();', # -- output -- 'if (a)\n' + ' b();') bt( 'while(a)\n' + 'b();', # -- output -- 'while (a)\n' + ' b();') bt( 'do\n' + 'c();\n' + 'while(a);', # -- output -- 'do\n' + ' c();\n' + 'while (a);') bt( 'switch(a)\n' + 'b()', # -- output -- 'switch (a)\n' + ' b()') bt('return [];') bt('return ();') #============================================================ # Beautify preserve formatting self.reset_options() bt( '/* beautify preserve:start */\n' + '/* beautify preserve:end */') bt( '/* beautify preserve:start */\n' + ' var a = 1;\n' + '/* beautify preserve:end */') bt( 'var a = 1;\n' + '/* beautify preserve:start */\n' + ' var a = 1;\n' + '/* beautify preserve:end */') bt('/* beautify preserve:start */ {asdklgh;y;;{}dd2d}/* beautify preserve:end */') bt( 'var a = 1;\n' + '/* beautify preserve:start */\n' + ' var a = 1;\n' + '/* beautify preserve:end */', # -- output -- 'var a = 1;\n' + '/* beautify preserve:start */\n' + ' var a = 1;\n' + '/* beautify preserve:end */') bt( 'var a = 1;\n' + ' /* beautify preserve:start */\n' + ' var a = 1;\n' + '/* beautify preserve:end */', # -- output -- 'var a = 1;\n' + '/* beautify preserve:start */\n' + ' var a = 1;\n' + '/* beautify preserve:end */') bt( 'var a = {\n' + ' /* beautify preserve:start */\n' + ' one : 1\n' + ' two : 2,\n' + ' three : 3,\n' + ' ten : 10\n' + ' /* beautify preserve:end */\n' + '};') bt( 'var a = {\n' + '/* beautify preserve:start */\n' + ' one : 1,\n' + ' two : 2,\n' + ' three : 3,\n' + ' ten : 10\n' + '/* beautify preserve:end */\n' + '};', # -- output -- 'var a = {\n' + ' /* beautify preserve:start */\n' + ' one : 1,\n' + ' two : 2,\n' + ' three : 3,\n' + ' ten : 10\n' + '/* beautify preserve:end */\n' + '};') # one space before and after required, only single spaces inside. bt( 'var a = {\n' + '/* beautify preserve:start */\n' + ' one : 1,\n' + ' two : 2,\n' + ' three : 3,\n' + ' ten : 10\n' + '};', # -- output -- 'var a = {\n' + ' /* beautify preserve:start */\n' + ' one: 1,\n' + ' two: 2,\n' + ' three: 3,\n' + ' ten: 10\n' + '};') bt( 'var a = {\n' + '/*beautify preserve:start*/\n' + ' one : 1,\n' + ' two : 2,\n' + ' three : 3,\n' + ' ten : 10\n' + '};', # -- output -- 'var a = {\n' + ' /*beautify preserve:start*/\n' + ' one: 1,\n' + ' two: 2,\n' + ' three: 3,\n' + ' ten: 10\n' + '};') bt( 'var a = {\n' + '/*beautify preserve:start*/\n' + ' one : 1,\n' + ' two : 2,\n' + ' three : 3,\n' + ' ten : 10\n' + '};', # -- output -- 'var a = {\n' + ' /*beautify preserve:start*/\n' + ' one: 1,\n' + ' two: 2,\n' + ' three: 3,\n' + ' ten: 10\n' + '};') # Directive: ignore bt( '/* beautify ignore:start */\n' + '/* beautify ignore:end */') bt( '/* beautify ignore:start */\n' + ' var a,,,{ 1;\n' + ' /* beautify ignore:end */') bt( 'var a = 1;\n' + '/* beautify ignore:start */\n' + ' var a = 1;\n' + '/* beautify ignore:end */') # ignore starts _after_ the start comment, ends after the end comment bt('/* beautify ignore:start */ {asdklgh;y;+++;dd2d}/* beautify ignore:end */') bt('/* beautify ignore:start */ {asdklgh;y;+++;dd2d} /* beautify ignore:end */') bt( 'var a = 1;\n' + '/* beautify ignore:start */\n' + ' var a,,,{ 1;\n' + '/*beautify ignore:end*/', # -- output -- 'var a = 1;\n' + '/* beautify ignore:start */\n' + ' var a,,,{ 1;\n' + '/*beautify ignore:end*/') bt( 'var a = 1;\n' + ' /* beautify ignore:start */\n' + ' var a,,,{ 1;\n' + '/* beautify ignore:end */', # -- output -- 'var a = 1;\n' + '/* beautify ignore:start */\n' + ' var a,,,{ 1;\n' + '/* beautify ignore:end */') bt( 'var a = {\n' + ' /* beautify ignore:start */\n' + ' one : 1\n' + ' two : 2,\n' + ' three : {\n' + ' ten : 10\n' + ' /* beautify ignore:end */\n' + '};') bt( 'var a = {\n' + '/* beautify ignore:start */\n' + ' one : 1\n' + ' two : 2,\n' + ' three : {\n' + ' ten : 10\n' + '/* beautify ignore:end */\n' + '};', # -- output -- 'var a = {\n' + ' /* beautify ignore:start */\n' + ' one : 1\n' + ' two : 2,\n' + ' three : {\n' + ' ten : 10\n' + '/* beautify ignore:end */\n' + '};') # Directives - multiple and interacting bt( 'var a = {\n' + '/* beautify preserve:start */\n' + '/* beautify preserve:start */\n' + ' one : 1,\n' + ' /* beautify preserve:end */\n' + ' two : 2,\n' + ' three : 3,\n' + '/* beautify preserve:start */\n' + ' ten : 10\n' + '/* beautify preserve:end */\n' + '};', # -- output -- 'var a = {\n' + ' /* beautify preserve:start */\n' + '/* beautify preserve:start */\n' + ' one : 1,\n' + ' /* beautify preserve:end */\n' + ' two: 2,\n' + ' three: 3,\n' + ' /* beautify preserve:start */\n' + ' ten : 10\n' + '/* beautify preserve:end */\n' + '};') bt( 'var a = {\n' + '/* beautify ignore:start */\n' + ' one : 1\n' + ' /* beautify ignore:end */\n' + ' two : 2,\n' + '/* beautify ignore:start */\n' + ' three : {\n' + ' ten : 10\n' + '/* beautify ignore:end */\n' + '};', # -- output -- 'var a = {\n' + ' /* beautify ignore:start */\n' + ' one : 1\n' + ' /* beautify ignore:end */\n' + ' two: 2,\n' + ' /* beautify ignore:start */\n' + ' three : {\n' + ' ten : 10\n' + '/* beautify ignore:end */\n' + '};') # Starts can occur together, ignore:end must occur alone. bt( 'var a = {\n' + '/* beautify ignore:start */\n' + ' one : 1\n' + ' NOTE: ignore end block does not support starting other directives\n' + ' This does not match the ending the ignore...\n' + ' /* beautify ignore:end preserve:start */\n' + ' two : 2,\n' + '/* beautify ignore:start */\n' + ' three : {\n' + ' ten : 10\n' + ' ==The next comment ends the starting ignore==\n' + '/* beautify ignore:end */\n' + '};', # -- output -- 'var a = {\n' + ' /* beautify ignore:start */\n' + ' one : 1\n' + ' NOTE: ignore end block does not support starting other directives\n' + ' This does not match the ending the ignore...\n' + ' /* beautify ignore:end preserve:start */\n' + ' two : 2,\n' + '/* beautify ignore:start */\n' + ' three : {\n' + ' ten : 10\n' + ' ==The next comment ends the starting ignore==\n' + '/* beautify ignore:end */\n' + '};') bt( 'var a = {\n' + '/* beautify ignore:start preserve:start */\n' + ' one : {\n' + ' /* beautify ignore:end */\n' + ' two : 2,\n' + ' /* beautify ignore:start */\n' + ' three : {\n' + '/* beautify ignore:end */\n' + ' ten : 10\n' + ' // This is all preserved\n' + '};', # -- output -- 'var a = {\n' + ' /* beautify ignore:start preserve:start */\n' + ' one : {\n' + ' /* beautify ignore:end */\n' + ' two : 2,\n' + ' /* beautify ignore:start */\n' + ' three : {\n' + '/* beautify ignore:end */\n' + ' ten : 10\n' + ' // This is all preserved\n' + '};') bt( 'var a = {\n' + '/* beautify ignore:start preserve:start */\n' + ' one : {\n' + ' /* beautify ignore:end */\n' + ' two : 2,\n' + ' /* beautify ignore:start */\n' + ' three : {\n' + '/* beautify ignore:end */\n' + ' ten : 10,\n' + '/* beautify preserve:end */\n' + ' eleven: 11\n' + '};', # -- output -- 'var a = {\n' + ' /* beautify ignore:start preserve:start */\n' + ' one : {\n' + ' /* beautify ignore:end */\n' + ' two : 2,\n' + ' /* beautify ignore:start */\n' + ' three : {\n' + '/* beautify ignore:end */\n' + ' ten : 10,\n' + '/* beautify preserve:end */\n' + ' eleven: 11\n' + '};') #============================================================ # Comments and tests self.reset_options() # #913 bt( 'class test {\n' + ' method1() {\n' + ' let resp = null;\n' + ' }\n' + ' /**\n' + ' * @param {String} id\n' + ' */\n' + ' method2(id) {\n' + ' let resp2 = null;\n' + ' }\n' + '}') # #1090 bt( 'for (var i = 0; i < 20; ++i) // loop\n' + ' if (i % 3) {\n' + ' console.log(i);\n' + ' }\n' + 'console.log("done");') # #1043 bt( 'var o = {\n' + ' k: 0\n' + '}\n' + '// ...\n' + 'foo(o)') # #713 and #964 bt( 'Meteor.call("foo", bar, function(err, result) {\n' + ' Session.set("baz", result.lorem)\n' + '})\n' + '//blah blah') # #815 bt( 'foo()\n' + '// this is a comment\n' + 'bar()\n' + '\n' + 'const foo = 5\n' + '// comment\n' + 'bar()') # This shows current behavior. Note #1069 is not addressed yet. bt( 'if (modulus === 2) {\n' + ' // i might be odd here\n' + ' i += (i & 1);\n' + ' // now i is guaranteed to be even\n' + ' // this block is obviously about the statement above\n' + '\n' + ' // #1069 This should attach to the block below\n' + ' // this comment is about the block after it.\n' + '} else {\n' + ' // rounding up using integer arithmetic only\n' + ' if (i % modulus)\n' + ' i += modulus - (i % modulus);\n' + ' // now i is divisible by modulus\n' + ' // behavior of comments should be different for single statements vs block statements/expressions\n' + '}\n' + '\n' + 'if (modulus === 2)\n' + ' // i might be odd here\n' + ' i += (i & 1);\n' + '// now i is guaranteed to be even\n' + '// non-braced comments unindent immediately\n' + '\n' + '// this comment is about the block after it.\n' + 'else\n' + ' // rounding up using integer arithmetic only\n' + ' if (i % modulus)\n' + ' i += modulus - (i % modulus);\n' + '// behavior of comments should be different for single statements vs block statements/expressions') #============================================================ # minimal template handling - () self.reset_options() self.options.templating = ['django', 'erb', 'handlebars', 'php'] bt('var a = ;', 'var a = ;') bt( 'a = abc");\n' + '}\n' + '?>;') test_fragment( '\n' + 'test.method();') bt( 'abc;\n' + '.test();\n' + '" "') bt( ';\n' + 'test.method();') bt('"";') # minimal template handling - () self.reset_options() self.options.templating = ['django', 'erb', 'handlebars', 'php'] bt('var a = ;', 'var a = ;') bt( 'a = abc");\n' + '}\n' + '?>;') test_fragment( '\n' + 'test.method();') bt( 'abc;\n' + '.test();\n' + '" "') bt( ';\n' + 'test.method();') bt('"";') # minimal template handling - () self.reset_options() self.options.templating = ['django', 'erb', 'handlebars', 'php'] bt('var a = <%$view["name"]; %>;', 'var a = <%$view["name"]; %>;') bt( 'a = abc<%\n' + 'for($i = 1; $i <= 100; $i++;) {\n' + ' #count to 100!\n' + ' echo($i . "
    ");\n' + '}\n' + '%>;') test_fragment( '<% %>\n' + 'test.met<% someValue %>hod();') bt( '<% "A" %>abc<% "D" %>;\n' + '<% "B" %>.test();\n' + '" <% "C" \'D\' %> "') bt( '<%\n' + 'echo "A";\n' + '%>;\n' + 'test.method();') bt('"<%";if(0){}"%>";') # minimal template handling - () self.reset_options() self.options.templating = ['django', 'erb', 'handlebars', 'php'] bt('var a = <%=$view["name"]; %>;', 'var a = <%=$view["name"]; %>;') bt( 'a = abc<%=\n' + 'for($i = 1; $i <= 100; $i++;) {\n' + ' #count to 100!\n' + ' echo($i . "
    ");\n' + '}\n' + '%>;') test_fragment( '<%= %>\n' + 'test.met<%= someValue %>hod();') bt( '<%= "A" %>abc<%= "D" %>;\n' + '<%= "B" %>.test();\n' + '" <%= "C" \'D\' %> "') bt( '<%=\n' + 'echo "A";\n' + '%>;\n' + 'test.method();') bt('"<%=";if(0){}"%>";') # minimal template handling - () self.reset_options() self.options.templating = ['django', 'erb', 'handlebars', 'php'] bt('var a = {{$view["name"]; }};', 'var a = {{$view["name"]; }};') bt( 'a = abc{{\n' + 'for($i = 1; $i <= 100; $i++;) {\n' + ' #count to 100!\n' + ' echo($i . "
    ");\n' + '}\n' + '}};') test_fragment( '{{ }}\n' + 'test.met{{ someValue }}hod();') bt( '{{ "A" }}abc{{ "D" }};\n' + '{{ "B" }}.test();\n' + '" {{ "C" \'D\' }} "') bt( '{{\n' + 'echo "A";\n' + '}};\n' + 'test.method();') bt('"{{";if(0){}"}}";') # minimal template handling - () self.reset_options() self.options.templating = ['django', 'erb', 'handlebars', 'php'] bt('var a = {#$view["name"]; #};', 'var a = {#$view["name"]; #};') bt( 'a = abc{#\n' + 'for($i = 1; $i <= 100; $i++;) {\n' + ' #count to 100!\n' + ' echo($i . "
    ");\n' + '}\n' + '#};') test_fragment( '{# #}\n' + 'test.met{# someValue #}hod();') bt( '{# "A" #}abc{# "D" #};\n' + '{# "B" #}.test();\n' + '" {# "C" \'D\' #} "') bt( '{#\n' + 'echo "A";\n' + '#};\n' + 'test.method();') bt('"{#";if(0){}"#}";') # minimal template handling - () self.reset_options() self.options.templating = ['django', 'erb', 'handlebars', 'php'] bt('var a = {%$view["name"]; %};', 'var a = {%$view["name"]; %};') bt( 'a = abc{%\n' + 'for($i = 1; $i <= 100; $i++;) {\n' + ' #count to 100!\n' + ' echo($i . "
    ");\n' + '}\n' + '%};') test_fragment( '{% %}\n' + 'test.met{% someValue %}hod();') bt( '{% "A" %}abc{% "D" %};\n' + '{% "B" %}.test();\n' + '" {% "C" \'D\' %} "') bt( '{%\n' + 'echo "A";\n' + '%};\n' + 'test.method();') bt('"{%";if(0){}"%}";') # minimal template handling - () self.reset_options() self.options.templating = ['django', 'erb', 'handlebars', 'php'] bt('var a = {{$view["name"]; }};', 'var a = {{$view["name"]; }};') bt( 'a = abc{{\n' + 'for($i = 1; $i <= 100; $i++;) {\n' + ' #count to 100!\n' + ' echo($i . "
    ");\n' + '}\n' + '}};') test_fragment( '{{ }}\n' + 'test.met{{ someValue }}hod();') bt( '{{ "A" }}abc{{ "D" }};\n' + '{{ "B" }}.test();\n' + '" {{ "C" \'D\' }} "') bt( '{{\n' + 'echo "A";\n' + '}};\n' + 'test.method();') bt('"{{";if(0){}"}}";') # minimal template handling - () self.reset_options() self.options.templating = ['django', 'erb', 'handlebars', 'php'] bt('var a = {{{$view["name"]; }}};', 'var a = {{{$view["name"]; }}};') bt( 'a = abc{{{\n' + 'for($i = 1; $i <= 100; $i++;) {\n' + ' #count to 100!\n' + ' echo($i . "
    ");\n' + '}\n' + '}}};') test_fragment( '{{{ }}}\n' + 'test.met{{{ someValue }}}hod();') bt( '{{{ "A" }}}abc{{{ "D" }}};\n' + '{{{ "B" }}}.test();\n' + '" {{{ "C" \'D\' }}} "') bt( '{{{\n' + 'echo "A";\n' + '}}};\n' + 'test.method();') bt('"{{{";if(0){}"}}}";') # minimal template handling - () self.reset_options() self.options.templating = ['django', 'erb', 'handlebars', 'php'] bt('var a = {{^$view["name"]; }};', 'var a = {{^$view["name"]; }};') bt( 'a = abc{{^\n' + 'for($i = 1; $i <= 100; $i++;) {\n' + ' #count to 100!\n' + ' echo($i . "
    ");\n' + '}\n' + '}};') test_fragment( '{{^ }}\n' + 'test.met{{^ someValue }}hod();') bt( '{{^ "A" }}abc{{^ "D" }};\n' + '{{^ "B" }}.test();\n' + '" {{^ "C" \'D\' }} "') bt( '{{^\n' + 'echo "A";\n' + '}};\n' + 'test.method();') bt('"{{^";if(0){}"}}";') # minimal template handling - () self.reset_options() self.options.templating = ['django', 'erb', 'handlebars', 'php'] bt('var a = {{#$view["name"]; }};', 'var a = {{#$view["name"]; }};') bt( 'a = abc{{#\n' + 'for($i = 1; $i <= 100; $i++;) {\n' + ' #count to 100!\n' + ' echo($i . "
    ");\n' + '}\n' + '}};') test_fragment( '{{# }}\n' + 'test.met{{# someValue }}hod();') bt( '{{# "A" }}abc{{# "D" }};\n' + '{{# "B" }}.test();\n' + '" {{# "C" \'D\' }} "') bt( '{{#\n' + 'echo "A";\n' + '}};\n' + 'test.method();') bt('"{{#";if(0){}"}}";') # minimal template handling - () self.reset_options() self.options.templating = ['django', 'erb', 'handlebars', 'php'] bt('var a = {{!$view["name"]; }};', 'var a = {{!$view["name"]; }};') bt( 'a = abc{{!\n' + 'for($i = 1; $i <= 100; $i++;) {\n' + ' #count to 100!\n' + ' echo($i . "
    ");\n' + '}\n' + '}};') test_fragment( '{{! }}\n' + 'test.met{{! someValue }}hod();') bt( '{{! "A" }}abc{{! "D" }};\n' + '{{! "B" }}.test();\n' + '" {{! "C" \'D\' }} "') bt( '{{!\n' + 'echo "A";\n' + '}};\n' + 'test.method();') bt('"{{!";if(0){}"}}";') # minimal template handling - () self.reset_options() self.options.templating = ['django', 'erb', 'handlebars', 'php'] bt('var a = {{!--$view["name"]; --}};', 'var a = {{!--$view["name"]; --}};') bt( 'a = abc{{!--\n' + 'for($i = 1; $i <= 100; $i++;) {\n' + ' #count to 100!\n' + ' echo($i . "
    ");\n' + '}\n' + '--}};') test_fragment( '{{!-- --}}\n' + 'test.met{{!-- someValue --}}hod();') bt( '{{!-- "A" --}}abc{{!-- "D" --}};\n' + '{{!-- "B" --}}.test();\n' + '" {{!-- "C" \'D\' --}} "') bt( '{{!--\n' + 'echo "A";\n' + '--}};\n' + 'test.method();') bt('"{{!--";if(0){}"--}}";') #============================================================ # Templating disabled - ensure formatting - () self.reset_options() self.options.templating = ['auto'] bt( '"";', # -- output -- '"";') bt( '"";', # -- output -- '"";') bt( '"";', # -- output -- '"<%";\n' + 'if (0) {}\n' + '"%>";') bt( '"<%";if(0){}', # -- output -- '"<%";\n' + 'if (0) {}') # Templating disabled - ensure formatting - () self.reset_options() self.options.templating = ['auto'] bt( '"<%=";if(0){}"%>";', # -- output -- '"<%=";\n' + 'if (0) {}\n' + '"%>";') bt( '"<%=";if(0){}', # -- output -- '"<%=";\n' + 'if (0) {}') # Templating disabled - ensure formatting - () self.reset_options() self.options.templating = ['auto'] bt( '"{{";if(0){}"}}";', # -- output -- '"{{";\n' + 'if (0) {}\n' + '"}}";') bt( '"{{";if(0){}', # -- output -- '"{{";\n' + 'if (0) {}') # Templating disabled - ensure formatting - () self.reset_options() self.options.templating = ['auto'] bt( '"{#";if(0){}"#}";', # -- output -- '"{#";\n' + 'if (0) {}\n' + '"#}";') bt( '"{#";if(0){}', # -- output -- '"{#";\n' + 'if (0) {}') # Templating disabled - ensure formatting - () self.reset_options() self.options.templating = ['auto'] bt( '"{%";if(0){}"%}";', # -- output -- '"{%";\n' + 'if (0) {}\n' + '"%}";') bt( '"{%";if(0){}', # -- output -- '"{%";\n' + 'if (0) {}') # Templating disabled - ensure formatting - () self.reset_options() self.options.templating = ['auto'] bt( '"{{";if(0){}"}}";', # -- output -- '"{{";\n' + 'if (0) {}\n' + '"}}";') bt( '"{{";if(0){}', # -- output -- '"{{";\n' + 'if (0) {}') # Templating disabled - ensure formatting - () self.reset_options() self.options.templating = ['auto'] bt( '"{{{";if(0){}"}}}";', # -- output -- '"{{{";\n' + 'if (0) {}\n' + '"}}}";') bt( '"{{{";if(0){}', # -- output -- '"{{{";\n' + 'if (0) {}') # Templating disabled - ensure formatting - () self.reset_options() self.options.templating = ['auto'] bt( '"{{^";if(0){}"}}";', # -- output -- '"{{^";\n' + 'if (0) {}\n' + '"}}";') bt( '"{{^";if(0){}', # -- output -- '"{{^";\n' + 'if (0) {}') # Templating disabled - ensure formatting - () self.reset_options() self.options.templating = ['auto'] bt( '"{{#";if(0){}"}}";', # -- output -- '"{{#";\n' + 'if (0) {}\n' + '"}}";') bt( '"{{#";if(0){}', # -- output -- '"{{#";\n' + 'if (0) {}') # Templating disabled - ensure formatting - () self.reset_options() self.options.templating = ['auto'] bt( '"{{!";if(0){}"}}";', # -- output -- '"{{!";\n' + 'if (0) {}\n' + '"}}";') bt( '"{{!";if(0){}', # -- output -- '"{{!";\n' + 'if (0) {}') # Templating disabled - ensure formatting - () self.reset_options() self.options.templating = ['auto'] bt( '"{{!--";if(0){}"--}}";', # -- output -- '"{{!--";\n' + 'if (0) {}\n' + '"--}}";') bt( '"{{!--";if(0){}', # -- output -- '"{{!--";\n' + 'if (0) {}') #============================================================ # jslint and space after anon function - (jslint_happy = "true", space_after_anon_function = "true") self.reset_options() self.options.jslint_happy = true self.options.space_after_anon_function = true bt( 'a=typeof(x)', # -- output -- 'a = typeof (x)') bt( 'x();\n' + '\n' + 'function(){}', # -- output -- 'x();\n' + '\n' + 'function () {}') bt( 'x();\n' + '\n' + 'function y(){}', # -- output -- 'x();\n' + '\n' + 'function y() {}') bt( 'x();\n' + '\n' + 'var x = {\n' + 'x: function(){}\n' + '}', # -- output -- 'x();\n' + '\n' + 'var x = {\n' + ' x: function () {}\n' + '}') bt( 'x();\n' + '\n' + 'var x = {\n' + 'x: function y(){}\n' + '}', # -- output -- 'x();\n' + '\n' + 'var x = {\n' + ' x: function y() {}\n' + '}') bt( 'function () {\n' + ' var a, b, c, d, e = [],\n' + ' f;\n' + '}') bt( 'switch(x) {case 0: case 1: a(); break; default: break}', # -- output -- 'switch (x) {\n' + 'case 0:\n' + 'case 1:\n' + ' a();\n' + ' break;\n' + 'default:\n' + ' break\n' + '}') bt( 'switch(x){case -1:break;case !y:break;}', # -- output -- 'switch (x) {\n' + 'case -1:\n' + ' break;\n' + 'case !y:\n' + ' break;\n' + '}') # Issue #1357 bt( 'switch(x) {case 0: case 1:{a(); break;} default: break}', # -- output -- 'switch (x) {\n' + 'case 0:\n' + 'case 1: {\n' + ' a();\n' + ' break;\n' + '}\n' + 'default:\n' + ' break\n' + '}') # Issue #1357 bt( 'switch(x){case -1:break;case !y:{break;}}', # -- output -- 'switch (x) {\n' + 'case -1:\n' + ' break;\n' + 'case !y: {\n' + ' break;\n' + '}\n' + '}') # Issue #1622 - basic class with function definitions bt( 'class blah {\n' + ' constructor() {\n' + ' this.doStuff()\n' + ' }\n' + ' doStuff() {\n' + ' console.log("stuff")\n' + ' }\n' + '}') # Issue #1622 - class with extends and function definitions bt( 'class blah extends something {\n' + ' constructor() {\n' + ' this.zz = 2 + 2;\n' + ' }\n' + ' someOtherFunction() {\n' + 'this.y = 1;\n' + ' }\n' + '}', # -- output -- 'class blah extends something {\n' + ' constructor() {\n' + ' this.zz = 2 + 2;\n' + ' }\n' + ' someOtherFunction() {\n' + ' this.y = 1;\n' + ' }\n' + '}') # Issue #1622 - class/extends as a property bt( 'var a.class = {\n' + ' ...abc(),\n' + '}\n' + 'b.extends({\n' + ' bb.s(),\n' + '})', # -- output -- 'var a.class = {\n' + ' ...abc(),\n' + '}\n' + 'b.extends({\n' + ' bb.s(),\n' + '})') # typical greasemonkey start test_fragment( '// comment 2\n' + '(function ()') bt( 'var a2, b2, c2, d2 = 0, c = function() {}, d = \'\';', # -- output -- 'var a2, b2, c2, d2 = 0,\n' + ' c = function () {},\n' + ' d = \'\';') bt( 'var a2, b2, c2, d2 = 0, c = function yoohoo() {}, d = \'\';', # -- output -- 'var a2, b2, c2, d2 = 0,\n' + ' c = function yoohoo() {},\n' + ' d = \'\';') bt( 'var a2, b2, c2, d2 = 0, c = function() {},\n' + 'd = \'\';', # -- output -- 'var a2, b2, c2, d2 = 0,\n' + ' c = function () {},\n' + ' d = \'\';') bt( 'var o2=$.extend(a);function(){alert(x);}', # -- output -- 'var o2 = $.extend(a);\n' + '\n' + 'function () {\n' + ' alert(x);\n' + '}') bt( 'var o2=$.extend(a);function yoohoo(){alert(x);}', # -- output -- 'var o2 = $.extend(a);\n' + '\n' + 'function yoohoo() {\n' + ' alert(x);\n' + '}') bt( 'function*() {\n' + ' yield 1;\n' + '}', # -- output -- 'function* () {\n' + ' yield 1;\n' + '}') bt( 'function* yoohoo() {\n' + ' yield 1;\n' + '}') bt( 'function* x() {\n' + ' yield 1;\n' + '}') bt( 'async x() {\n' + ' yield 1;\n' + '}') bt( 'var a={data(){},\n' + 'data2(){}}', # -- output -- 'var a = {\n' + ' data() {},\n' + ' data2() {}\n' + '}') bt( 'new Vue({\n' + 'data(){},\n' + 'data2(){}, a:1})', # -- output -- 'new Vue({\n' + ' data() {},\n' + ' data2() {},\n' + ' a: 1\n' + '})') bt( 'export default {data(){},\n' + 'data2(){},\n' + 'a:1}', # -- output -- 'export default {\n' + ' data() {},\n' + ' data2() {},\n' + ' a: 1\n' + '}') bt( 'var a={*data(){},*data2(){}}', # -- output -- 'var a = {\n' + ' * data() {},\n' + ' * data2() {}\n' + '}') bt( 'new Vue({\n' + '*data(){},*data2(){}, a:1})', # -- output -- 'new Vue({\n' + ' * data() {},\n' + ' * data2() {},\n' + ' a: 1\n' + '})') bt( 'export default {*data(){},*data2(){},\n' + 'a:1}', # -- output -- 'export default {\n' + ' * data() {},\n' + ' * data2() {},\n' + ' a: 1\n' + '}') # jslint and space after anon function - (jslint_happy = "true", space_after_anon_function = "false") self.reset_options() self.options.jslint_happy = true self.options.space_after_anon_function = false bt( 'a=typeof(x)', # -- output -- 'a = typeof (x)') bt( 'x();\n' + '\n' + 'function(){}', # -- output -- 'x();\n' + '\n' + 'function () {}') bt( 'x();\n' + '\n' + 'function y(){}', # -- output -- 'x();\n' + '\n' + 'function y() {}') bt( 'x();\n' + '\n' + 'var x = {\n' + 'x: function(){}\n' + '}', # -- output -- 'x();\n' + '\n' + 'var x = {\n' + ' x: function () {}\n' + '}') bt( 'x();\n' + '\n' + 'var x = {\n' + 'x: function y(){}\n' + '}', # -- output -- 'x();\n' + '\n' + 'var x = {\n' + ' x: function y() {}\n' + '}') bt( 'function () {\n' + ' var a, b, c, d, e = [],\n' + ' f;\n' + '}') bt( 'switch(x) {case 0: case 1: a(); break; default: break}', # -- output -- 'switch (x) {\n' + 'case 0:\n' + 'case 1:\n' + ' a();\n' + ' break;\n' + 'default:\n' + ' break\n' + '}') bt( 'switch(x){case -1:break;case !y:break;}', # -- output -- 'switch (x) {\n' + 'case -1:\n' + ' break;\n' + 'case !y:\n' + ' break;\n' + '}') # Issue #1357 bt( 'switch(x) {case 0: case 1:{a(); break;} default: break}', # -- output -- 'switch (x) {\n' + 'case 0:\n' + 'case 1: {\n' + ' a();\n' + ' break;\n' + '}\n' + 'default:\n' + ' break\n' + '}') # Issue #1357 bt( 'switch(x){case -1:break;case !y:{break;}}', # -- output -- 'switch (x) {\n' + 'case -1:\n' + ' break;\n' + 'case !y: {\n' + ' break;\n' + '}\n' + '}') # Issue #1622 - basic class with function definitions bt( 'class blah {\n' + ' constructor() {\n' + ' this.doStuff()\n' + ' }\n' + ' doStuff() {\n' + ' console.log("stuff")\n' + ' }\n' + '}') # Issue #1622 - class with extends and function definitions bt( 'class blah extends something {\n' + ' constructor() {\n' + ' this.zz = 2 + 2;\n' + ' }\n' + ' someOtherFunction() {\n' + 'this.y = 1;\n' + ' }\n' + '}', # -- output -- 'class blah extends something {\n' + ' constructor() {\n' + ' this.zz = 2 + 2;\n' + ' }\n' + ' someOtherFunction() {\n' + ' this.y = 1;\n' + ' }\n' + '}') # Issue #1622 - class/extends as a property bt( 'var a.class = {\n' + ' ...abc(),\n' + '}\n' + 'b.extends({\n' + ' bb.s(),\n' + '})', # -- output -- 'var a.class = {\n' + ' ...abc(),\n' + '}\n' + 'b.extends({\n' + ' bb.s(),\n' + '})') # typical greasemonkey start test_fragment( '// comment 2\n' + '(function ()') bt( 'var a2, b2, c2, d2 = 0, c = function() {}, d = \'\';', # -- output -- 'var a2, b2, c2, d2 = 0,\n' + ' c = function () {},\n' + ' d = \'\';') bt( 'var a2, b2, c2, d2 = 0, c = function yoohoo() {}, d = \'\';', # -- output -- 'var a2, b2, c2, d2 = 0,\n' + ' c = function yoohoo() {},\n' + ' d = \'\';') bt( 'var a2, b2, c2, d2 = 0, c = function() {},\n' + 'd = \'\';', # -- output -- 'var a2, b2, c2, d2 = 0,\n' + ' c = function () {},\n' + ' d = \'\';') bt( 'var o2=$.extend(a);function(){alert(x);}', # -- output -- 'var o2 = $.extend(a);\n' + '\n' + 'function () {\n' + ' alert(x);\n' + '}') bt( 'var o2=$.extend(a);function yoohoo(){alert(x);}', # -- output -- 'var o2 = $.extend(a);\n' + '\n' + 'function yoohoo() {\n' + ' alert(x);\n' + '}') bt( 'function*() {\n' + ' yield 1;\n' + '}', # -- output -- 'function* () {\n' + ' yield 1;\n' + '}') bt( 'function* yoohoo() {\n' + ' yield 1;\n' + '}') bt( 'function* x() {\n' + ' yield 1;\n' + '}') bt( 'async x() {\n' + ' yield 1;\n' + '}') bt( 'var a={data(){},\n' + 'data2(){}}', # -- output -- 'var a = {\n' + ' data() {},\n' + ' data2() {}\n' + '}') bt( 'new Vue({\n' + 'data(){},\n' + 'data2(){}, a:1})', # -- output -- 'new Vue({\n' + ' data() {},\n' + ' data2() {},\n' + ' a: 1\n' + '})') bt( 'export default {data(){},\n' + 'data2(){},\n' + 'a:1}', # -- output -- 'export default {\n' + ' data() {},\n' + ' data2() {},\n' + ' a: 1\n' + '}') bt( 'var a={*data(){},*data2(){}}', # -- output -- 'var a = {\n' + ' * data() {},\n' + ' * data2() {}\n' + '}') bt( 'new Vue({\n' + '*data(){},*data2(){}, a:1})', # -- output -- 'new Vue({\n' + ' * data() {},\n' + ' * data2() {},\n' + ' a: 1\n' + '})') bt( 'export default {*data(){},*data2(){},\n' + 'a:1}', # -- output -- 'export default {\n' + ' * data() {},\n' + ' * data2() {},\n' + ' a: 1\n' + '}') # jslint and space after anon function - (jslint_happy = "false", space_after_anon_function = "true") self.reset_options() self.options.jslint_happy = false self.options.space_after_anon_function = true bt( 'a=typeof(x)', # -- output -- 'a = typeof (x)') bt( 'x();\n' + '\n' + 'function(){}', # -- output -- 'x();\n' + '\n' + 'function () {}') bt( 'x();\n' + '\n' + 'function y(){}', # -- output -- 'x();\n' + '\n' + 'function y() {}') bt( 'x();\n' + '\n' + 'var x = {\n' + 'x: function(){}\n' + '}', # -- output -- 'x();\n' + '\n' + 'var x = {\n' + ' x: function () {}\n' + '}') bt( 'x();\n' + '\n' + 'var x = {\n' + 'x: function y(){}\n' + '}', # -- output -- 'x();\n' + '\n' + 'var x = {\n' + ' x: function y() {}\n' + '}') bt( 'function () {\n' + ' var a, b, c, d, e = [],\n' + ' f;\n' + '}') bt( 'switch(x) {case 0: case 1: a(); break; default: break}', # -- output -- 'switch (x) {\n' + ' case 0:\n' + ' case 1:\n' + ' a();\n' + ' break;\n' + ' default:\n' + ' break\n' + '}') bt( 'switch(x){case -1:break;case !y:break;}', # -- output -- 'switch (x) {\n' + ' case -1:\n' + ' break;\n' + ' case !y:\n' + ' break;\n' + '}') # Issue #1357 bt( 'switch(x) {case 0: case 1:{a(); break;} default: break}', # -- output -- 'switch (x) {\n' + ' case 0:\n' + ' case 1: {\n' + ' a();\n' + ' break;\n' + ' }\n' + ' default:\n' + ' break\n' + '}') # Issue #1357 bt( 'switch(x){case -1:break;case !y:{break;}}', # -- output -- 'switch (x) {\n' + ' case -1:\n' + ' break;\n' + ' case !y: {\n' + ' break;\n' + ' }\n' + '}') # Issue #1622 - basic class with function definitions bt( 'class blah {\n' + ' constructor() {\n' + ' this.doStuff()\n' + ' }\n' + ' doStuff() {\n' + ' console.log("stuff")\n' + ' }\n' + '}') # Issue #1622 - class with extends and function definitions bt( 'class blah extends something {\n' + ' constructor() {\n' + ' this.zz = 2 + 2;\n' + ' }\n' + ' someOtherFunction() {\n' + 'this.y = 1;\n' + ' }\n' + '}', # -- output -- 'class blah extends something {\n' + ' constructor() {\n' + ' this.zz = 2 + 2;\n' + ' }\n' + ' someOtherFunction() {\n' + ' this.y = 1;\n' + ' }\n' + '}') # Issue #1622 - class/extends as a property bt( 'var a.class = {\n' + ' ...abc(),\n' + '}\n' + 'b.extends({\n' + ' bb.s(),\n' + '})', # -- output -- 'var a.class = {\n' + ' ...abc(),\n' + '}\n' + 'b.extends({\n' + ' bb.s(),\n' + '})') # typical greasemonkey start test_fragment( '// comment 2\n' + '(function ()') bt( 'var a2, b2, c2, d2 = 0, c = function() {}, d = \'\';', # -- output -- 'var a2, b2, c2, d2 = 0,\n' + ' c = function () {},\n' + ' d = \'\';') bt( 'var a2, b2, c2, d2 = 0, c = function yoohoo() {}, d = \'\';', # -- output -- 'var a2, b2, c2, d2 = 0,\n' + ' c = function yoohoo() {},\n' + ' d = \'\';') bt( 'var a2, b2, c2, d2 = 0, c = function() {},\n' + 'd = \'\';', # -- output -- 'var a2, b2, c2, d2 = 0,\n' + ' c = function () {},\n' + ' d = \'\';') bt( 'var o2=$.extend(a);function(){alert(x);}', # -- output -- 'var o2 = $.extend(a);\n' + '\n' + 'function () {\n' + ' alert(x);\n' + '}') bt( 'var o2=$.extend(a);function yoohoo(){alert(x);}', # -- output -- 'var o2 = $.extend(a);\n' + '\n' + 'function yoohoo() {\n' + ' alert(x);\n' + '}') bt( 'function*() {\n' + ' yield 1;\n' + '}', # -- output -- 'function* () {\n' + ' yield 1;\n' + '}') bt( 'function* yoohoo() {\n' + ' yield 1;\n' + '}') bt( 'function* x() {\n' + ' yield 1;\n' + '}') bt( 'async x() {\n' + ' yield 1;\n' + '}') bt( 'var a={data(){},\n' + 'data2(){}}', # -- output -- 'var a = {\n' + ' data() {},\n' + ' data2() {}\n' + '}') bt( 'new Vue({\n' + 'data(){},\n' + 'data2(){}, a:1})', # -- output -- 'new Vue({\n' + ' data() {},\n' + ' data2() {},\n' + ' a: 1\n' + '})') bt( 'export default {data(){},\n' + 'data2(){},\n' + 'a:1}', # -- output -- 'export default {\n' + ' data() {},\n' + ' data2() {},\n' + ' a: 1\n' + '}') bt( 'var a={*data(){},*data2(){}}', # -- output -- 'var a = {\n' + ' * data() {},\n' + ' * data2() {}\n' + '}') bt( 'new Vue({\n' + '*data(){},*data2(){}, a:1})', # -- output -- 'new Vue({\n' + ' * data() {},\n' + ' * data2() {},\n' + ' a: 1\n' + '})') bt( 'export default {*data(){},*data2(){},\n' + 'a:1}', # -- output -- 'export default {\n' + ' * data() {},\n' + ' * data2() {},\n' + ' a: 1\n' + '}') # jslint and space after anon function - (jslint_happy = "false", space_after_anon_function = "false") self.reset_options() self.options.jslint_happy = false self.options.space_after_anon_function = false bt( 'a=typeof(x)', # -- output -- 'a = typeof(x)') bt( 'x();\n' + '\n' + 'function(){}', # -- output -- 'x();\n' + '\n' + 'function() {}') bt( 'x();\n' + '\n' + 'function y(){}', # -- output -- 'x();\n' + '\n' + 'function y() {}') bt( 'x();\n' + '\n' + 'var x = {\n' + 'x: function(){}\n' + '}', # -- output -- 'x();\n' + '\n' + 'var x = {\n' + ' x: function() {}\n' + '}') bt( 'x();\n' + '\n' + 'var x = {\n' + 'x: function y(){}\n' + '}', # -- output -- 'x();\n' + '\n' + 'var x = {\n' + ' x: function y() {}\n' + '}') bt( 'function () {\n' + ' var a, b, c, d, e = [],\n' + ' f;\n' + '}', # -- output -- 'function() {\n' + ' var a, b, c, d, e = [],\n' + ' f;\n' + '}') bt( 'switch(x) {case 0: case 1: a(); break; default: break}', # -- output -- 'switch (x) {\n' + ' case 0:\n' + ' case 1:\n' + ' a();\n' + ' break;\n' + ' default:\n' + ' break\n' + '}') bt( 'switch(x){case -1:break;case !y:break;}', # -- output -- 'switch (x) {\n' + ' case -1:\n' + ' break;\n' + ' case !y:\n' + ' break;\n' + '}') # Issue #1357 bt( 'switch(x) {case 0: case 1:{a(); break;} default: break}', # -- output -- 'switch (x) {\n' + ' case 0:\n' + ' case 1: {\n' + ' a();\n' + ' break;\n' + ' }\n' + ' default:\n' + ' break\n' + '}') # Issue #1357 bt( 'switch(x){case -1:break;case !y:{break;}}', # -- output -- 'switch (x) {\n' + ' case -1:\n' + ' break;\n' + ' case !y: {\n' + ' break;\n' + ' }\n' + '}') # Issue #1622 - basic class with function definitions bt( 'class blah {\n' + ' constructor() {\n' + ' this.doStuff()\n' + ' }\n' + ' doStuff() {\n' + ' console.log("stuff")\n' + ' }\n' + '}') # Issue #1622 - class with extends and function definitions bt( 'class blah extends something {\n' + ' constructor() {\n' + ' this.zz = 2 + 2;\n' + ' }\n' + ' someOtherFunction() {\n' + 'this.y = 1;\n' + ' }\n' + '}', # -- output -- 'class blah extends something {\n' + ' constructor() {\n' + ' this.zz = 2 + 2;\n' + ' }\n' + ' someOtherFunction() {\n' + ' this.y = 1;\n' + ' }\n' + '}') # Issue #1622 - class/extends as a property bt( 'var a.class = {\n' + ' ...abc(),\n' + '}\n' + 'b.extends({\n' + ' bb.s(),\n' + '})', # -- output -- 'var a.class = {\n' + ' ...abc(),\n' + '}\n' + 'b.extends({\n' + ' bb.s(),\n' + '})') # typical greasemonkey start test_fragment( '// comment 2\n' + '(function()') bt( 'var a2, b2, c2, d2 = 0, c = function() {}, d = \'\';', # -- output -- 'var a2, b2, c2, d2 = 0,\n' + ' c = function() {},\n' + ' d = \'\';') bt( 'var a2, b2, c2, d2 = 0, c = function yoohoo() {}, d = \'\';', # -- output -- 'var a2, b2, c2, d2 = 0,\n' + ' c = function yoohoo() {},\n' + ' d = \'\';') bt( 'var a2, b2, c2, d2 = 0, c = function() {},\n' + 'd = \'\';', # -- output -- 'var a2, b2, c2, d2 = 0,\n' + ' c = function() {},\n' + ' d = \'\';') bt( 'var o2=$.extend(a);function(){alert(x);}', # -- output -- 'var o2 = $.extend(a);\n' + '\n' + 'function() {\n' + ' alert(x);\n' + '}') bt( 'var o2=$.extend(a);function yoohoo(){alert(x);}', # -- output -- 'var o2 = $.extend(a);\n' + '\n' + 'function yoohoo() {\n' + ' alert(x);\n' + '}') bt( 'function*() {\n' + ' yield 1;\n' + '}') bt( 'function* yoohoo() {\n' + ' yield 1;\n' + '}') bt( 'function* x() {\n' + ' yield 1;\n' + '}') bt( 'async x() {\n' + ' yield 1;\n' + '}') bt( 'var a={data(){},\n' + 'data2(){}}', # -- output -- 'var a = {\n' + ' data() {},\n' + ' data2() {}\n' + '}') bt( 'new Vue({\n' + 'data(){},\n' + 'data2(){}, a:1})', # -- output -- 'new Vue({\n' + ' data() {},\n' + ' data2() {},\n' + ' a: 1\n' + '})') bt( 'export default {data(){},\n' + 'data2(){},\n' + 'a:1}', # -- output -- 'export default {\n' + ' data() {},\n' + ' data2() {},\n' + ' a: 1\n' + '}') bt( 'var a={*data(){},*data2(){}}', # -- output -- 'var a = {\n' + ' * data() {},\n' + ' * data2() {}\n' + '}') bt( 'new Vue({\n' + '*data(){},*data2(){}, a:1})', # -- output -- 'new Vue({\n' + ' * data() {},\n' + ' * data2() {},\n' + ' a: 1\n' + '})') bt( 'export default {*data(){},*data2(){},\n' + 'a:1}', # -- output -- 'export default {\n' + ' * data() {},\n' + ' * data2() {},\n' + ' a: 1\n' + '}') # jslint and space after anon function - (space_after_named_function = "true") self.reset_options() self.options.space_after_named_function = true bt( 'a=typeof(x)', # -- output -- 'a = typeof(x)') bt( 'x();\n' + '\n' + 'function(){}', # -- output -- 'x();\n' + '\n' + 'function() {}') bt( 'x();\n' + '\n' + 'function y(){}', # -- output -- 'x();\n' + '\n' + 'function y () {}') bt( 'x();\n' + '\n' + 'var x = {\n' + 'x: function(){}\n' + '}', # -- output -- 'x();\n' + '\n' + 'var x = {\n' + ' x: function() {}\n' + '}') bt( 'x();\n' + '\n' + 'var x = {\n' + 'x: function y(){}\n' + '}', # -- output -- 'x();\n' + '\n' + 'var x = {\n' + ' x: function y () {}\n' + '}') bt( 'function () {\n' + ' var a, b, c, d, e = [],\n' + ' f;\n' + '}', # -- output -- 'function() {\n' + ' var a, b, c, d, e = [],\n' + ' f;\n' + '}') bt( 'switch(x) {case 0: case 1: a(); break; default: break}', # -- output -- 'switch (x) {\n' + ' case 0:\n' + ' case 1:\n' + ' a();\n' + ' break;\n' + ' default:\n' + ' break\n' + '}') bt( 'switch(x){case -1:break;case !y:break;}', # -- output -- 'switch (x) {\n' + ' case -1:\n' + ' break;\n' + ' case !y:\n' + ' break;\n' + '}') # Issue #1357 bt( 'switch(x) {case 0: case 1:{a(); break;} default: break}', # -- output -- 'switch (x) {\n' + ' case 0:\n' + ' case 1: {\n' + ' a();\n' + ' break;\n' + ' }\n' + ' default:\n' + ' break\n' + '}') # Issue #1357 bt( 'switch(x){case -1:break;case !y:{break;}}', # -- output -- 'switch (x) {\n' + ' case -1:\n' + ' break;\n' + ' case !y: {\n' + ' break;\n' + ' }\n' + '}') # Issue #1622 - basic class with function definitions bt( 'class blah {\n' + ' constructor() {\n' + ' this.doStuff()\n' + ' }\n' + ' doStuff() {\n' + ' console.log("stuff")\n' + ' }\n' + '}', # -- output -- 'class blah {\n' + ' constructor () {\n' + ' this.doStuff()\n' + ' }\n' + ' doStuff () {\n' + ' console.log("stuff")\n' + ' }\n' + '}') # Issue #1622 - class with extends and function definitions bt( 'class blah extends something {\n' + ' constructor() {\n' + ' this.zz = 2 + 2;\n' + ' }\n' + ' someOtherFunction() {\n' + 'this.y = 1;\n' + ' }\n' + '}', # -- output -- 'class blah extends something {\n' + ' constructor () {\n' + ' this.zz = 2 + 2;\n' + ' }\n' + ' someOtherFunction () {\n' + ' this.y = 1;\n' + ' }\n' + '}') # Issue #1622 - class/extends as a property bt( 'var a.class = {\n' + ' ...abc(),\n' + '}\n' + 'b.extends({\n' + ' bb.s(),\n' + '})', # -- output -- 'var a.class = {\n' + ' ...abc(),\n' + '}\n' + 'b.extends({\n' + ' bb.s(),\n' + '})') # typical greasemonkey start test_fragment( '// comment 2\n' + '(function()') bt( 'var a2, b2, c2, d2 = 0, c = function() {}, d = \'\';', # -- output -- 'var a2, b2, c2, d2 = 0,\n' + ' c = function() {},\n' + ' d = \'\';') bt( 'var a2, b2, c2, d2 = 0, c = function yoohoo() {}, d = \'\';', # -- output -- 'var a2, b2, c2, d2 = 0,\n' + ' c = function yoohoo () {},\n' + ' d = \'\';') bt( 'var a2, b2, c2, d2 = 0, c = function() {},\n' + 'd = \'\';', # -- output -- 'var a2, b2, c2, d2 = 0,\n' + ' c = function() {},\n' + ' d = \'\';') bt( 'var o2=$.extend(a);function(){alert(x);}', # -- output -- 'var o2 = $.extend(a);\n' + '\n' + 'function() {\n' + ' alert(x);\n' + '}') bt( 'var o2=$.extend(a);function yoohoo(){alert(x);}', # -- output -- 'var o2 = $.extend(a);\n' + '\n' + 'function yoohoo () {\n' + ' alert(x);\n' + '}') bt( 'function*() {\n' + ' yield 1;\n' + '}') bt( 'function* yoohoo() {\n' + ' yield 1;\n' + '}', # -- output -- 'function* yoohoo () {\n' + ' yield 1;\n' + '}') bt( 'function* x() {\n' + ' yield 1;\n' + '}', # -- output -- 'function* x () {\n' + ' yield 1;\n' + '}') bt( 'async x() {\n' + ' yield 1;\n' + '}', # -- output -- 'async x () {\n' + ' yield 1;\n' + '}') bt( 'var a={data(){},\n' + 'data2(){}}', # -- output -- 'var a = {\n' + ' data () {},\n' + ' data2 () {}\n' + '}') bt( 'new Vue({\n' + 'data(){},\n' + 'data2(){}, a:1})', # -- output -- 'new Vue({\n' + ' data () {},\n' + ' data2 () {},\n' + ' a: 1\n' + '})') bt( 'export default {data(){},\n' + 'data2(){},\n' + 'a:1}', # -- output -- 'export default {\n' + ' data () {},\n' + ' data2 () {},\n' + ' a: 1\n' + '}') bt( 'var a={*data(){},*data2(){}}', # -- output -- 'var a = {\n' + ' * data () {},\n' + ' * data2 () {}\n' + '}') bt( 'new Vue({\n' + '*data(){},*data2(){}, a:1})', # -- output -- 'new Vue({\n' + ' * data () {},\n' + ' * data2 () {},\n' + ' a: 1\n' + '})') bt( 'export default {*data(){},*data2(){},\n' + 'a:1}', # -- output -- 'export default {\n' + ' * data () {},\n' + ' * data2 () {},\n' + ' a: 1\n' + '}') #============================================================ # Regression tests self.reset_options() # Issue 241 bt( 'obj\n' + ' .last({\n' + ' foo: 1,\n' + ' bar: 2\n' + ' });\n' + 'var test = 1;') # Issue #1852 - semicolon followed by block statement bt( '(function() {\n' + ' some_code_here();\n' + ' {\n' + ' /* IE11 let bug bypass */\n' + ' let index;\n' + ' for (index in a) {\n' + ' a[index];\n' + ' }\n' + ' }\n' + '})();') # Issue #1852 - semicolon followed by block statement 2 bt( 'let x = { A: 1 }; { console.log("hello"); }', # -- output -- 'let x = {\n' + ' A: 1\n' + '};\n' + '{\n' + ' console.log("hello");\n' + '}') # Issue #772 bt( 'this.initAttributes([\n' + '"name",\n' + '["parent", null, "parentName"],\n' + '"length",\n' + '["id", this.name],\n' + ']);', # -- output -- 'this.initAttributes([\n' + ' "name",\n' + ' ["parent", null, "parentName"],\n' + ' "length",\n' + ' ["id", this.name],\n' + ']);') # Issue #1663 bt( '{\n' + ' /* howdy\n' + ' \n' + ' */\n' + '}') # #1095 - Return without semicolon followed by prefix on a new line bt( 'function x(){\n' + 'return\n' + '++a\n' + '}\n' + '\n' + 'while(true) {\n' + 'return\n' + '--b\n' + '}', # -- output -- 'function x() {\n' + ' return\n' + ' ++a\n' + '}\n' + '\n' + 'while (true) {\n' + ' return\n' + ' --b\n' + '}') # #1095 bt( 'function test(){\n' + 'if(x) return\n' + '++x\n' + 'var y= 1;\n' + '}\n' + 'function t1(){\n' + 'if(cc) return;\n' + 'else return\n' + '--cc\n' + '}', # -- output -- 'function test() {\n' + ' if (x) return\n' + ' ++x\n' + ' var y = 1;\n' + '}\n' + '\n' + 'function t1() {\n' + ' if (cc) return;\n' + ' else return\n' + ' --cc\n' + '}') # #1095 - Return with semicolon followed by a prefix on a new line bt( 'function x(){\n' + 'return; ++a\n' + '}\n' + '\n' + 'while(true){return; --b\n' + '}', # -- output -- 'function x() {\n' + ' return;\n' + ' ++a\n' + '}\n' + '\n' + 'while (true) {\n' + ' return;\n' + ' --b\n' + '}') # #1838 - handle class and interface word as an object property bt( '{\n' + ' class: {\n' + ' a: 1,\n' + ' b: 2,\n' + ' c: 3,\n' + ' }\n' + ' interface: {\n' + ' a: 1,\n' + ' b: 2,\n' + ' c: 3,\n' + ' }\n' + '}') # #1838 - handle class word as an object property but with space after colon bt( '{\n' + ' class : { a: 1,\n' + 'b: 2,c : 3\n' + ' }\n' + '}', # -- output -- '{\n' + ' class: {\n' + ' a: 1,\n' + ' b: 2,\n' + ' c: 3\n' + ' }\n' + '}') # #1838 - handle class word as an object property but without spaces bt( '{class:{a:1,b:2,c:3,}}', # -- output -- '{\n' + ' class: {\n' + ' a: 1,\n' + ' b: 2,\n' + ' c: 3,\n' + ' }\n' + '}') # #1838 - handle class word as a nested object property bt( '{x:{a:1,class:2,c:3,}}', # -- output -- '{\n' + ' x: {\n' + ' a: 1,\n' + ' class: 2,\n' + ' c: 3,\n' + ' }\n' + '}') bt( 'obj\n' + ' .last(a, function() {\n' + ' var test;\n' + ' });\n' + 'var test = 1;') bt( 'obj.first()\n' + ' .second()\n' + ' .last(function(err, response) {\n' + ' console.log(err);\n' + ' });') # Issue 268 and 275 bt( 'obj.last(a, function() {\n' + ' var test;\n' + '});\n' + 'var test = 1;') bt( 'obj.last(a,\n' + ' function() {\n' + ' var test;\n' + ' });\n' + 'var test = 1;') bt( '(function() {if (!window.FOO) window.FOO || (window.FOO = function() {var b = {bar: "zort"};});})();', # -- output -- '(function() {\n' + ' if (!window.FOO) window.FOO || (window.FOO = function() {\n' + ' var b = {\n' + ' bar: "zort"\n' + ' };\n' + ' });\n' + '})();') # Issue 281 bt( 'define(["dojo/_base/declare", "my/Employee", "dijit/form/Button",\n' + ' "dojo/_base/lang", "dojo/Deferred"\n' + '], function(declare, Employee, Button, lang, Deferred) {\n' + ' return declare(Employee, {\n' + ' constructor: function() {\n' + ' new Button({\n' + ' onClick: lang.hitch(this, function() {\n' + ' new Deferred().then(lang.hitch(this, function() {\n' + ' this.salary * 0.25;\n' + ' }));\n' + ' })\n' + ' });\n' + ' }\n' + ' });\n' + '});') bt( 'define(["dojo/_base/declare", "my/Employee", "dijit/form/Button",\n' + ' "dojo/_base/lang", "dojo/Deferred"\n' + ' ],\n' + ' function(declare, Employee, Button, lang, Deferred) {\n' + ' return declare(Employee, {\n' + ' constructor: function() {\n' + ' new Button({\n' + ' onClick: lang.hitch(this, function() {\n' + ' new Deferred().then(lang.hitch(this, function() {\n' + ' this.salary * 0.25;\n' + ' }));\n' + ' })\n' + ' });\n' + ' }\n' + ' });\n' + ' });') # Issue 459 bt( '(function() {\n' + ' return {\n' + ' foo: function() {\n' + ' return "bar";\n' + ' },\n' + ' bar: ["bar"]\n' + ' };\n' + '}());') # Issue 505 - strings should end at newline unless continued by backslash bt( 'var name = "a;\n' + 'name = "b";') bt( 'var name = "a;\\\n' + ' name = b";') # Issue 514 - some operators require spaces to distinguish them bt('var c = "_ACTION_TO_NATIVEAPI_" + ++g++ + +new Date;') bt('var c = "_ACTION_TO_NATIVEAPI_" - --g-- - -new Date;') # Issue 440 - reserved words can be used as object property names bt( 'a = {\n' + ' function: {},\n' + ' "function": {},\n' + ' throw: {},\n' + ' "throw": {},\n' + ' var: {},\n' + ' "var": {},\n' + ' set: {},\n' + ' "set": {},\n' + ' get: {},\n' + ' "get": {},\n' + ' if: {},\n' + ' "if": {},\n' + ' then: {},\n' + ' "then": {},\n' + ' else: {},\n' + ' "else": {},\n' + ' yay: {}\n' + '};') # Issue 331 - if-else with braces edge case bt( 'if(x){a();}else{b();}if(y){c();}', # -- output -- 'if (x) {\n' + ' a();\n' + '} else {\n' + ' b();\n' + '}\n' + 'if (y) {\n' + ' c();\n' + '}') # Issue #1683 - switch-case wrong indentation bt( 'switch (x) { case 0: if (y == z) { a(); } else { b(); } case 1: c(); }', # -- output -- 'switch (x) {\n' + ' case 0:\n' + ' if (y == z) {\n' + ' a();\n' + ' } else {\n' + ' b();\n' + ' }\n' + ' case 1:\n' + ' c();\n' + '}') # Issue 485 - ensure function declarations behave the same in arrays as elsewhere bt( 'var v = ["a",\n' + ' function() {\n' + ' return;\n' + ' }, {\n' + ' id: 1\n' + ' }\n' + '];') bt( 'var v = ["a", function() {\n' + ' return;\n' + '}, {\n' + ' id: 1\n' + '}];') # Issue 382 - initial totally cursory support for es6 module export bt( 'module "Even" {\n' + ' import odd from "Odd";\n' + ' export function sum(x, y) {\n' + ' return x + y;\n' + ' }\n' + ' export var pi = 3.141593;\n' + ' export default moduleName;\n' + '}') bt( 'module "Even" {\n' + ' export default function div(x, y) {}\n' + '}') # Issue 889 - export default { ... } bt( 'export default {\n' + ' func1() {},\n' + ' func2() {}\n' + ' func3() {}\n' + '}') bt( 'export default {\n' + ' a() {\n' + ' return 1;\n' + ' },\n' + ' b() {\n' + ' return 2;\n' + ' },\n' + ' c() {\n' + ' return 3;\n' + ' }\n' + '}') # Issue 508 bt('set["name"]') bt('get["name"]') test_fragment( 'a = {\n' + ' set b(x) {},\n' + ' c: 1,\n' + ' d: function() {}\n' + '};') test_fragment( 'a = {\n' + ' get b() {\n' + ' retun 0;\n' + ' },\n' + ' c: 1,\n' + ' d: function() {}\n' + '};') # Issue 298 - do not under indent if/while/for condtionals experesions bt( '\'use strict\';\n' + 'if ([].some(function() {\n' + ' return false;\n' + ' })) {\n' + ' console.log("hello");\n' + '}') # Issue 298 - do not under indent if/while/for condtionals experesions bt( '\'use strict\';\n' + 'if ([].some(function() {\n' + ' return false;\n' + ' })) {\n' + ' console.log("hello");\n' + '}') # Issue 552 - Typescript? Okay... we didn't break it before, so try not to break it now. bt( 'class Test {\n' + ' blah: string[];\n' + ' foo(): number {\n' + ' return 0;\n' + ' }\n' + ' bar(): number {\n' + ' return 0;\n' + ' }\n' + '}') # Issue 1544 - Typescript declare formatting (no newline). bt( 'declare const require: any;\n' + 'declare function greet(greeting: string): void;\n' + 'declare var foo: number;\n' + 'declare namespace myLib {\n' + ' function makeGreeting(s: string): string;\n' + ' let numberOfGreetings: number;\n' + '}\n' + 'declare let test: any;') bt( 'interface Test {\n' + ' blah: string[];\n' + ' foo(): number {\n' + ' return 0;\n' + ' }\n' + ' bar(): number {\n' + ' return 0;\n' + ' }\n' + '}') # Issue 583 - Functions with comments after them should still indent correctly. bt( 'function exit(code) {\n' + ' setTimeout(function() {\n' + ' phantom.exit(code);\n' + ' }, 0);\n' + ' phantom.onError = function() {};\n' + '}\n' + '// Comment') # Issue 806 - newline arrow functions bt( 'a.b("c",\n' + ' () => d.e\n' + ')') # Issue 810 - es6 object literal detection bt( 'function badFormatting() {\n' + ' return {\n' + ' a,\n' + ' b: c,\n' + ' d: e,\n' + ' f: g,\n' + ' h,\n' + ' i,\n' + ' j: k\n' + ' }\n' + '}\n' + '\n' + 'function goodFormatting() {\n' + ' return {\n' + ' a: b,\n' + ' c,\n' + ' d: e,\n' + ' f: g,\n' + ' h,\n' + ' i,\n' + ' j: k\n' + ' }\n' + '}') # Issue 602 - ES6 object literal shorthand functions bt( 'return {\n' + ' fn1() {},\n' + ' fn2() {}\n' + '}') bt( 'throw {\n' + ' fn1() {},\n' + ' fn2() {}\n' + '}') bt( 'foo({\n' + ' fn1(a) {}\n' + ' fn2(a) {}\n' + '})') bt( 'foo("text", {\n' + ' fn1(a) {}\n' + ' fn2(a) {}\n' + '})') bt( 'oneArg = {\n' + ' fn1(a) {\n' + ' do();\n' + ' },\n' + ' fn2() {}\n' + '}') bt( 'multiArg = {\n' + ' fn1(a, b, c) {\n' + ' do();\n' + ' },\n' + ' fn2() {}\n' + '}') bt( 'noArgs = {\n' + ' fn1() {\n' + ' do();\n' + ' },\n' + ' fn2() {}\n' + '}') bt( 'emptyFn = {\n' + ' fn1() {},\n' + ' fn2() {}\n' + '}') bt( 'nested = {\n' + ' fns: {\n' + ' fn1() {},\n' + ' fn2() {}\n' + ' }\n' + '}') bt( 'array = [{\n' + ' fn1() {},\n' + ' prop: val,\n' + ' fn2() {}\n' + '}]') bt( 'expr = expr ? expr : {\n' + ' fn1() {},\n' + ' fn2() {}\n' + '}') bt( 'strange = valid + {\n' + ' fn1() {},\n' + ' fn2() {\n' + ' return 1;\n' + ' }\n' + '}.fn2()') # Issue 854 - Arrow function with statement block bt( 'test(() => {\n' + ' var a = {}\n' + '\n' + ' a.what = () => true ? 1 : 2\n' + '\n' + ' a.thing = () => {\n' + ' b();\n' + ' }\n' + '})') # Issue 1727 - Optional chaining bt('true?.1:.2', 'true ? .1 : .2') # Issue 406 - Multiline array bt( 'var tempName = [\n' + ' "temp",\n' + ' process.pid,\n' + ' (Math.random() * 0x1000000000).toString(36),\n' + ' new Date().getTime()\n' + '].join("-");') # Issue 1801 - Optional chaining w/ obj?.[expr] syntax bt( 'let nestedProp = obj?.["prop" + "Name"];\n' + 'let arrayItem = arr?.[42];') # Issue 1374 - Parameters starting with ! or [ merged into single line bt( 'fn(\n' + ' 1,\n' + ' !1,\n' + ' 1,\n' + ' [1]\n' + ')') # Issue 1288 - Negative numbers remove newlines in array bt( 'var array = [\n' + ' -1,\n' + ' 0,\n' + ' "a",\n' + ' -2,\n' + ' 1,\n' + ' -3,\n' + '];') # Issue 1229 - Negated expressions in array bt( 'a = [\n' + ' true && 1,\n' + ' true && 1,\n' + ' true && 1\n' + ']\n' + 'a = [\n' + ' !true && 1,\n' + ' !true && 1,\n' + ' !true && 1\n' + ']') # Issue #996 - Input ends with backslash throws exception test_fragment( 'sd = 1;\n' + '/') # Issue #1079 - unbraced if with comments should still look right bt( 'if (console.log)\n' + ' for (var i = 0; i < 20; ++i)\n' + ' if (i % 3)\n' + ' console.log(i);\n' + '// all done\n' + 'console.log("done");') # Issue #1085 - function should not have blank line in a number of cases bt( 'var transformer =\n' + ' options.transformer ||\n' + ' globalSettings.transformer ||\n' + ' function(x) {\n' + ' return x;\n' + ' };') # Issue #1794 - support nullish-coalescing bt('a = b ?? c') # Issue #569 - function should not have blank line in a number of cases bt( '(function(global) {\n' + ' "use strict";\n' + '\n' + ' /* jshint ignore:start */\n' + ' include "somefile.js"\n' + ' /* jshint ignore:end */\n' + '}(this));') bt( 'function bindAuthEvent(eventName) {\n' + ' self.auth.on(eventName, function(event, meta) {\n' + ' self.emit(eventName, event, meta);\n' + ' });\n' + '}\n' + '["logged_in", "logged_out", "signed_up", "updated_user"].forEach(bindAuthEvent);\n' + '\n' + 'function bindBrowserEvent(eventName) {\n' + ' browser.on(eventName, function(event, meta) {\n' + ' self.emit(eventName, event, meta);\n' + ' });\n' + '}\n' + '["navigating"].forEach(bindBrowserEvent);') # Issue #892 - new line between chained methods bt( 'foo\n' + ' .who()\n' + '\n' + ' .knows()\n' + ' // comment\n' + ' .nothing() // comment\n' + '\n' + ' .more()') # Issue #1107 - Missing space between words for label bt( 'function f(a) {c: do if (x) {} else if (y) {} while(0); return 0;}', # -- output -- 'function f(a) {\n' + ' c: do\n' + ' if (x) {} else if (y) {}\n' + ' while (0);\n' + ' return 0;\n' + '}') bt( 'function f(a) {c: if (x) {} else if (y) {} return 0;}', # -- output -- 'function f(a) {\n' + ' c: if (x) {} else if (y) {}\n' + ' return 0;\n' + '}') #============================================================ # Test non-positionable-ops self.reset_options() bt('a += 2;') bt('a -= 2;') bt('a *= 2;') bt('a /= 2;') bt('a %= 2;') bt('a &= 2;') bt('a ^= 2;') bt('a |= 2;') bt('a **= 2;') bt('a <<= 2;') bt('a >>= 2;') #============================================================ # self.reset_options() # exponent literals bt('a = 1e10') bt('a = 1.3e10') bt('a = 1.3e-10') bt('a = -12345.3e-10') bt('a = .12345e-10') bt('a = 06789e-10') bt('a = e - 10') bt('a = 1.3e+10') bt('a = 1.e-7') bt('a = -12345.3e+10') bt('a = .12345e+10') bt('a = 06789e+10') bt('a = e + 10') bt('a=0e-12345.3e-10', 'a = 0e-12345 .3e-10') bt('a=0.e-12345.3e-10', 'a = 0.e-12345 .3e-10') bt('a=0x.e-12345.3e-10', 'a = 0x.e - 12345.3e-10') bt('a=0x0.e-12345.3e-10', 'a = 0x0.e - 12345.3e-10') bt('a=0x0.0e-12345.3e-10', 'a = 0x0 .0e-12345 .3e-10') bt('a=0g-12345.3e-10', 'a = 0 g - 12345.3e-10') bt('a=0.g-12345.3e-10', 'a = 0. g - 12345.3e-10') bt('a=0x.g-12345.3e-10', 'a = 0x.g - 12345.3e-10') bt('a=0x0.g-12345.3e-10', 'a = 0x0.g - 12345.3e-10') bt('a=0x0.0g-12345.3e-10', 'a = 0x0 .0 g - 12345.3e-10') # exponent literals with underscore bt('a = 1_1e10') bt('a = 1_.3e10') bt('a = 1_1.3e10') bt('a = 1__1.3e10') bt('a = 1._3e10') bt('a = 1.3_e10') bt('a = 1.3e_10') bt('a = 1.3e1_0') bt('a = 1.3e10_') # Decimal literals bt('a = 0123456789;') bt('a = 9876543210;') bt('a = 5647308291;') bt('a=030e-5', 'a = 030e-5') bt('a=00+4', 'a = 00 + 4') bt('a=32+4', 'a = 32 + 4') bt('a=0.6g+4', 'a = 0.6 g + 4') bt('a=01.10', 'a = 01.10') bt('a=a.10', 'a = a .10') bt('a=00B0x0', 'a = 00 B0x0') bt('a=00B0xb0', 'a = 00 B0xb0') bt('a=00B0x0b0', 'a = 00 B0x0b0') bt('a=0090x0', 'a = 0090 x0') bt('a=0g0b0o0', 'a = 0 g0b0o0') # Decimal literals with underscore bt('a = 0_123456789') bt('a = 0__123456789') bt('a = 0__') bt('a = 0_1_2_3') bt('a = 0_1_2_3_') # Hexadecimal literals bt('a = 0x0123456789abcdef;') bt('a = 0X0123456789ABCDEF;') bt('a = 0xFeDcBa9876543210;') bt('a=0x30e-5', 'a = 0x30e - 5') bt('a=0xF0+4', 'a = 0xF0 + 4') bt('a=0Xff+4', 'a = 0Xff + 4') bt('a=0Xffg+4', 'a = 0Xff g + 4') bt('a=0x01.10', 'a = 0x01 .10') bt('a = 0xb0ce;') bt('a = 0x0b0;') bt('a=0x0B0x0', 'a = 0x0B0 x0') bt('a=0x0B0xb0', 'a = 0x0B0 xb0') bt('a=0x0B0x0b0', 'a = 0x0B0 x0b0') bt('a=0X090x0', 'a = 0X090 x0') bt('a=0Xg0b0o0', 'a = 0X g0b0o0') # Hexadecimal literals with underscore bt('a = 0x0_123456789abcdef') bt('a = 0x0__0123456789abcdef') bt('a = 0x_0123456789abcdef') bt('a = 0x__') bt('a = 0x0_1_a_3') bt('a = 0x_1_2_F_') # Octal literals bt('a = 0o01234567;') bt('a = 0O01234567;') bt('a = 0o34120675;') bt('a=0o30e-5', 'a = 0o30 e - 5') bt('a=0o70+4', 'a = 0o70 + 4') bt('a=0O77+4', 'a = 0O77 + 4') bt('a=0O778+4', 'a = 0O77 8 + 4') bt('a=0O77a+4', 'a = 0O77 a + 4') bt('a=0o01.10', 'a = 0o01 .10') bt('a=0o0B0x0', 'a = 0o0 B0x0') bt('a=0o0B0xb0', 'a = 0o0 B0xb0') bt('a=0o0B0x0b0', 'a = 0o0 B0x0b0') bt('a=0O090x0', 'a = 0O0 90 x0') bt('a=0Og0b0o0', 'a = 0O g0b0o0') # Octal literals with underscore bt('a = 0o0_1234567') bt('a = 0o0__1234567') bt('a = 0o_01234567') bt('a = 0o__') bt('a = 0o0_1_2_3') bt('a = 0o_1_2_3_') # Binary literals bt('a = 0b010011;') bt('a = 0B010011;') bt('a = 0b01001100001111;') bt('a=0b10e-5', 'a = 0b10 e - 5') bt('a=0b10+4', 'a = 0b10 + 4') bt('a=0B11+4', 'a = 0B11 + 4') bt('a=0B112+4', 'a = 0B11 2 + 4') bt('a=0B11a+4', 'a = 0B11 a + 4') bt('a=0b01.10', 'a = 0b01 .10') bt('a=0b0B0x0', 'a = 0b0 B0x0') bt('a=0b0B0xb0', 'a = 0b0 B0xb0') bt('a=0b0B0x0b0', 'a = 0b0 B0x0b0') bt('a=0B090x0', 'a = 0B0 90 x0') bt('a=0Bg0b0o0', 'a = 0B g0b0o0') # Binary literals with underscore bt('a = 0b0_10011') bt('a = 0b0__10011') bt('a = 0b_010011') bt('a = 0b__') bt('a = 0b0_1_1_1') bt('a = 0b_1_0_1_') bt('a = 0B010_0_11;') bt('a = 0b01_0011_0000_1111;') # BigInt literals bt('a = 1n;') bt('a = 1234567890123456789n;') bt('a = -1234567890123456789n;') bt('a = 1234567890123456789 N;') bt('a=0b10e-5n', 'a = 0b10 e - 5n') bt('a=.0n', 'a = .0 n') bt('a=1.0n', 'a = 1.0 n') bt('a=1e0n', 'a = 1e0 n') bt('a=0n11a+4', 'a = 0n 11 a + 4') # BigInt literals with underscore bt('a = 0_123456789n') bt('a = 0__123456789n') bt('a = 0__n') bt('a = 0_1_2_3n') bt('a = 0_1_2_3_n') # BigInt hexadecimal literals bt('a = 0x0123456789abcdefn;') bt('a = 0X0123456789ABCDEFn;') bt('a = 0xFeDcBa9876543210n;') bt('a=0x30en-5', 'a = 0x30en - 5') bt('a=0xF0n+4', 'a = 0xF0n + 4') bt('a=0Xffn+4', 'a = 0Xffn + 4') bt('a=0Xffng+4', 'a = 0Xffn g + 4') bt('a=0x01n.10', 'a = 0x01n .10') bt('a = 0xb0cen;') bt('a = 0x0b0n;') bt('a=0x0B0nx0', 'a = 0x0B0n x0') bt('a=0x0B0nxb0', 'a = 0x0B0n xb0') bt('a=0x0B0nx0b0', 'a = 0x0B0n x0b0') bt('a=0X090nx0', 'a = 0X090n x0') # BigInt hexadecimal literals with underscore bt('a = 0x0_123456789abcdefn') bt('a = 0x0__0123456789abcdefn') bt('a = 0x_0123456789abcdefn') bt('a = 0x__n') bt('a = 0x0_1_a_3n') bt('a = 0x_1_2_F_n') # BigInt octal literals bt('a = 0o01234567n;') bt('a = 0O01234567n;') bt('a = 0o34120675n;') bt('a=0o30ne-5', 'a = 0o30n e - 5') bt('a=0o70n+4', 'a = 0o70n + 4') bt('a=0O77n+4', 'a = 0O77n + 4') bt('a=0O77n8+4', 'a = 0O77n 8 + 4') bt('a=0O77na+4', 'a = 0O77n a + 4') bt('a=0o01n.10', 'a = 0o01n .10') bt('a=0o0nB0x0', 'a = 0o0n B0x0') bt('a=0o0nB0xb0', 'a = 0o0n B0xb0') bt('a=0o0nB0x0b0', 'a = 0o0n B0x0b0') bt('a=0O0n90x0', 'a = 0O0n 90 x0') # BigInt octal literals with underscore bt('a = 0o0_1234567n') bt('a = 0o0__1234567n') bt('a = 0o_01234567n') bt('a = 0o__n') bt('a = 0o0_1_2_3n') bt('a = 0o_1_2_3_n') # BigInt binary literals bt('a = 0b010011n;') bt('a = 0B010011n;') bt('a = 0b01001100001111n;') bt('a=0b10ne-5', 'a = 0b10n e - 5') bt('a=0b10n+4', 'a = 0b10n + 4') bt('a=0B11n+4', 'a = 0B11n + 4') bt('a=0B11n2+4', 'a = 0B11n 2 + 4') bt('a=0B11na+4', 'a = 0B11n a + 4') bt('a=0b01n.10', 'a = 0b01n .10') bt('a=0b0nB0x0', 'a = 0b0n B0x0') bt('a=0b0nB0xb0', 'a = 0b0n B0xb0') bt('a=0b0nB0x0b0', 'a = 0b0n B0x0b0') bt('a=0B0n90x0', 'a = 0B0n 90 x0') # BigInt binary literals with underscore bt('a = 0b0_10011n') bt('a = 0b0__10011n') bt('a = 0b_010011') bt('a = 0b__n') bt('a = 0b0_1_1_1n') bt('a = 0b_1_0_1_n') bt('a = 0B010_0_11n;') bt('a = 0b01_0011_0000_1111n;') #============================================================ # brace_style ,preserve-inline tests - (brace_style = ""collapse,preserve-inline"") self.reset_options() self.options.brace_style = 'collapse,preserve-inline' bt('import { asdf } from "asdf";') bt('import { get } from "asdf";') bt('function inLine() { console.log("oh em gee"); }') bt('if (cancer) { console.log("Im sorry but you only have so long to live..."); }') bt('if (ding) { console.log("dong"); } else { console.log("dang"); }') bt( 'function kindaComplex() {\n' + ' var a = 2;\n' + ' var obj = {};\n' + ' var obj2 = { a: "a", b: "b" };\n' + ' var obj3 = {\n' + ' c: "c",\n' + ' d: "d",\n' + ' e: "e"\n' + ' };\n' + '}') bt( 'function complex() {\n' + ' console.log("wowe");\n' + ' (function() { var a = 2; var b = 3; })();\n' + ' $.each(arr, function(el, idx) { return el; });\n' + ' var obj = {\n' + ' a: function() { console.log("test"); },\n' + ' b() {\n' + ' console.log("test2");\n' + ' }\n' + ' };\n' + '}', # -- output -- 'function complex() {\n' + ' console.log("wowe");\n' + ' (function() { var a = 2; var b = 3; })();\n' + ' $.each(arr, function(el, idx) { return el; });\n' + ' var obj = {\n' + ' a: function() { console.log("test"); },\n' + ' b() {\n' + ' console.log("test2");\n' + ' }\n' + ' };\n' + '}') # brace_style ,preserve-inline tests - (brace_style = ""expand,preserve-inline"") self.reset_options() self.options.brace_style = 'expand,preserve-inline' bt('import { asdf } from "asdf";') bt('import { get } from "asdf";') bt('function inLine() { console.log("oh em gee"); }') bt('if (cancer) { console.log("Im sorry but you only have so long to live..."); }') bt( 'if (ding) { console.log("dong"); } else { console.log("dang"); }', # -- output -- 'if (ding) { console.log("dong"); }\n' + 'else { console.log("dang"); }') bt( 'function kindaComplex() {\n' + ' var a = 2;\n' + ' var obj = {};\n' + ' var obj2 = { a: "a", b: "b" };\n' + ' var obj3 = {\n' + ' c: "c",\n' + ' d: "d",\n' + ' e: "e"\n' + ' };\n' + '}', # -- output -- 'function kindaComplex()\n' + '{\n' + ' var a = 2;\n' + ' var obj = {};\n' + ' var obj2 = { a: "a", b: "b" };\n' + ' var obj3 = {\n' + ' c: "c",\n' + ' d: "d",\n' + ' e: "e"\n' + ' };\n' + '}') bt( 'function complex() {\n' + ' console.log("wowe");\n' + ' (function() { var a = 2; var b = 3; })();\n' + ' $.each(arr, function(el, idx) { return el; });\n' + ' var obj = {\n' + ' a: function() { console.log("test"); },\n' + ' b() {\n' + ' console.log("test2");\n' + ' }\n' + ' };\n' + '}', # -- output -- 'function complex()\n' + '{\n' + ' console.log("wowe");\n' + ' (function() { var a = 2; var b = 3; })();\n' + ' $.each(arr, function(el, idx) { return el; });\n' + ' var obj = {\n' + ' a: function() { console.log("test"); },\n' + ' b()\n' + ' {\n' + ' console.log("test2");\n' + ' }\n' + ' };\n' + '}') # brace_style ,preserve-inline tests - (brace_style = ""end-expand,preserve-inline"") self.reset_options() self.options.brace_style = 'end-expand,preserve-inline' bt('import { asdf } from "asdf";') bt('import { get } from "asdf";') bt('function inLine() { console.log("oh em gee"); }') bt('if (cancer) { console.log("Im sorry but you only have so long to live..."); }') bt( 'if (ding) { console.log("dong"); } else { console.log("dang"); }', # -- output -- 'if (ding) { console.log("dong"); }\n' + 'else { console.log("dang"); }') bt( 'function kindaComplex() {\n' + ' var a = 2;\n' + ' var obj = {};\n' + ' var obj2 = { a: "a", b: "b" };\n' + ' var obj3 = {\n' + ' c: "c",\n' + ' d: "d",\n' + ' e: "e"\n' + ' };\n' + '}') bt( 'function complex() {\n' + ' console.log("wowe");\n' + ' (function() { var a = 2; var b = 3; })();\n' + ' $.each(arr, function(el, idx) { return el; });\n' + ' var obj = {\n' + ' a: function() { console.log("test"); },\n' + ' b() {\n' + ' console.log("test2");\n' + ' }\n' + ' };\n' + '}', # -- output -- 'function complex() {\n' + ' console.log("wowe");\n' + ' (function() { var a = 2; var b = 3; })();\n' + ' $.each(arr, function(el, idx) { return el; });\n' + ' var obj = {\n' + ' a: function() { console.log("test"); },\n' + ' b() {\n' + ' console.log("test2");\n' + ' }\n' + ' };\n' + '}') # brace_style ,preserve-inline tests - (brace_style = ""none,preserve-inline"") self.reset_options() self.options.brace_style = 'none,preserve-inline' bt('import { asdf } from "asdf";') bt('import { get } from "asdf";') bt('function inLine() { console.log("oh em gee"); }') bt('if (cancer) { console.log("Im sorry but you only have so long to live..."); }') bt('if (ding) { console.log("dong"); } else { console.log("dang"); }') bt( 'function kindaComplex() {\n' + ' var a = 2;\n' + ' var obj = {};\n' + ' var obj2 = { a: "a", b: "b" };\n' + ' var obj3 = {\n' + ' c: "c",\n' + ' d: "d",\n' + ' e: "e"\n' + ' };\n' + '}') bt( 'function complex() {\n' + ' console.log("wowe");\n' + ' (function() { var a = 2; var b = 3; })();\n' + ' $.each(arr, function(el, idx) { return el; });\n' + ' var obj = {\n' + ' a: function() { console.log("test"); },\n' + ' b() {\n' + ' console.log("test2");\n' + ' }\n' + ' };\n' + '}', # -- output -- 'function complex() {\n' + ' console.log("wowe");\n' + ' (function() { var a = 2; var b = 3; })();\n' + ' $.each(arr, function(el, idx) { return el; });\n' + ' var obj = {\n' + ' a: function() { console.log("test"); },\n' + ' b() {\n' + ' console.log("test2");\n' + ' }\n' + ' };\n' + '}') # brace_style ,preserve-inline tests - (brace_style = ""collapse-preserve-inline"") self.reset_options() self.options.brace_style = 'collapse-preserve-inline' bt('import { asdf } from "asdf";') bt('import { get } from "asdf";') bt('function inLine() { console.log("oh em gee"); }') bt('if (cancer) { console.log("Im sorry but you only have so long to live..."); }') bt('if (ding) { console.log("dong"); } else { console.log("dang"); }') bt( 'function kindaComplex() {\n' + ' var a = 2;\n' + ' var obj = {};\n' + ' var obj2 = { a: "a", b: "b" };\n' + ' var obj3 = {\n' + ' c: "c",\n' + ' d: "d",\n' + ' e: "e"\n' + ' };\n' + '}') bt( 'function complex() {\n' + ' console.log("wowe");\n' + ' (function() { var a = 2; var b = 3; })();\n' + ' $.each(arr, function(el, idx) { return el; });\n' + ' var obj = {\n' + ' a: function() { console.log("test"); },\n' + ' b() {\n' + ' console.log("test2");\n' + ' }\n' + ' };\n' + '}', # -- output -- 'function complex() {\n' + ' console.log("wowe");\n' + ' (function() { var a = 2; var b = 3; })();\n' + ' $.each(arr, function(el, idx) { return el; });\n' + ' var obj = {\n' + ' a: function() { console.log("test"); },\n' + ' b() {\n' + ' console.log("test2");\n' + ' }\n' + ' };\n' + '}') #============================================================ # Destructured and related self.reset_options() self.options.brace_style = 'collapse,preserve-inline' # Issue 382 - import destructured bt( 'module "Even" {\n' + ' import { odd, oddly } from "Odd";\n' + '}') bt( 'import defaultMember from "module-name";\n' + 'import * as name from "module-name";\n' + 'import { member } from "module-name";\n' + 'import { member as alias } from "module-name";\n' + 'import { member1, member2 } from "module-name";\n' + 'import { member1, member2 as alias2 } from "module-name";\n' + 'import defaultMember, { member, member2 } from "module-name";\n' + 'import defaultMember, * as name from "module-name";\n' + 'import "module-name";\n' + 'import("module-name")') # Issue #1393 - dynamic import() bt( 'if (from < to) {\n' + ' import(`dynamic${library}`);\n' + '} else {\n' + ' import("otherdynamic");\n' + '}') # Issue #1197 - dynamic import() arrow syntax bt('frontend = Async(() => import("../frontend").then(m => m.default ))', 'frontend = Async(() => import("../frontend").then(m => m.default))') # Issue #1978 - import.meta syntax support bt('let x = import.meta', 'let x = import.meta') # Issue 858 - from is a keyword only after import bt( 'if (from < to) {\n' + ' from++;\n' + '} else {\n' + ' from--;\n' + '}') # Issue 511 - destrutured bt( 'var { b, c } = require("../stores");\n' + 'var { ProjectStore } = require("../stores");\n' + '\n' + 'function takeThing({ prop }) {\n' + ' console.log("inner prop", prop)\n' + '}') # Issue 315 - Short objects bt('var a = { b: { c: { d: e } } };') bt( 'var a = {\n' + ' b: {\n' + ' c: { d: e }\n' + ' c3: { d: e }\n' + ' },\n' + ' b2: { c: { d: e } }\n' + '};') # Issue 370 - Short objects in array bt( 'var methods = [\n' + ' { name: "to" },\n' + ' { name: "step" },\n' + ' { name: "move" },\n' + ' { name: "min" },\n' + ' { name: "max" }\n' + '];') # Issue 838 - Short objects in array bt( 'function(url, callback) {\n' + ' var script = document.createElement("script")\n' + ' if (true) script.onreadystatechange = function() {\n' + ' foo();\n' + ' }\n' + ' else script.onload = callback;\n' + '}') # Issue 578 - Odd indenting after function bt( 'function bindAuthEvent(eventName) {\n' + ' self.auth.on(eventName, function(event, meta) {\n' + ' self.emit(eventName, event, meta);\n' + ' });\n' + '}\n' + '["logged_in", "logged_out", "signed_up", "updated_user"].forEach(bindAuthEvent);') # Issue #487 - some short expressions examples bt( 'if (a == 1) { a++; }\n' + 'a = { a: a };\n' + 'UserDB.findOne({ username: "xyz" }, function(err, user) {});\n' + 'import { fs } from "fs";') # Issue #982 - Fixed return expression collapse-preserve-inline bt( 'function foo(arg) {\n' + ' if (!arg) { a(); }\n' + ' if (!arg) { return false; }\n' + ' if (!arg) { throw "inline"; }\n' + ' return true;\n' + '}') # Issue #338 - Short expressions bt( 'if (someCondition) { return something; }\n' + 'if (someCondition) {\n' + ' return something;\n' + '}\n' + 'if (someCondition) { break; }\n' + 'if (someCondition) {\n' + ' return something;\n' + '}') # Issue #1283 - Javascript ++ Operator get wrong indent bt( '{this.foo++\n' + 'bar}', # -- output -- '{\n' + ' this.foo++\n' + ' bar\n' + '}') # Issue #1283 - Javascript ++ Operator get wrong indent (2) bt( 'axios.interceptors.request.use(\n' + ' config => {\n' + ' // loading\n' + ' window.store.loading++\n' + ' let extraParams = {}\n' + ' }\n' + ')') # Issue ##1846 - in keyword in class method causes indentation problem bt( 'class {\n' + ' get a() {\n' + '\n' + '\n' + ' }\n' + '\n' + '\n' + ' in() {\n' + '\n' + '\n' + ' }\n' + '\n' + '\n' + ' b() {\n' + '\n' + '\n' + ' }\n' + '}', # -- output -- 'class {\n' + ' get a() {\n' + '\n' + '\n' + ' }\n' + '\n' + '\n' + ' in() {\n' + '\n' + '\n' + ' }\n' + '\n' + '\n' + ' b() {\n' + '\n' + '\n' + ' }\n' + '}') # Related to Issue ##1846 - Do not indent 'in' keyword if not a class method bt( 'function test() {\n' + 'for x in nums {}\n' + '"make" in car\n' + '3 in number;\n' + '}', # -- output -- 'function test() {\n' + ' for x in nums {}\n' + ' "make" in car\n' + ' 3 in number;\n' + '}') # Related to Issue ##1846 - of keyword in class method causes indentation problem bt( 'class {\n' + ' get a() {\n' + '\n' + '\n' + ' }\n' + '\n' + '\n' + ' of() {\n' + '\n' + '\n' + ' }\n' + '\n' + '\n' + ' b() {\n' + '\n' + '\n' + ' }\n' + '}', # -- output -- 'class {\n' + ' get a() {\n' + '\n' + '\n' + ' }\n' + '\n' + '\n' + ' of() {\n' + '\n' + '\n' + ' }\n' + '\n' + '\n' + ' b() {\n' + '\n' + '\n' + ' }\n' + '}') # Issue #1950: Do not remove whitespace after number - test scenario: number before a dot bt('1000000000000001000 .toFixed(0)!==1000000000000001024', '1000000000000001000 .toFixed(0) !== 1000000000000001024') # Issue #1950: Do not remove whitespace after number - test scenario: variable ends with a number before a dot bt('a.b21 . performAction()', 'a.b21.performAction()') #============================================================ # keep_array_indentation false self.reset_options() self.options.keep_array_indentation = false bt( 'a = ["a", "b", "c",\n' + ' "d", "e", "f"]', # -- output -- 'a = ["a", "b", "c",\n' + ' "d", "e", "f"\n' + ']') bt( 'a = ["a", "b", "c",\n' + ' "d", "e", "f",\n' + ' "g", "h", "i"]', # -- output -- 'a = ["a", "b", "c",\n' + ' "d", "e", "f",\n' + ' "g", "h", "i"\n' + ']') bt( 'a = ["a", "b", "c",\n' + ' "d", "e", "f",\n' + ' "g", "h", "i"]', # -- output -- 'a = ["a", "b", "c",\n' + ' "d", "e", "f",\n' + ' "g", "h", "i"\n' + ']') bt( 'var x = [{}\n' + ']', # -- output -- 'var x = [{}]') bt( 'var x = [{foo:bar}\n' + ']', # -- output -- 'var x = [{\n' + ' foo: bar\n' + '}]') bt( 'a = ["something",\n' + ' "completely",\n' + ' "different"];\n' + 'if (x);', # -- output -- 'a = ["something",\n' + ' "completely",\n' + ' "different"\n' + '];\n' + 'if (x);') bt('a = ["a","b","c"]', 'a = ["a", "b", "c"]') bt('a = ["a", "b","c"]', 'a = ["a", "b", "c"]') bt( 'x = [{"a":0}]', # -- output -- 'x = [{\n' + ' "a": 0\n' + '}]') bt( '{a([[a1]], {b;});}', # -- output -- '{\n' + ' a([\n' + ' [a1]\n' + ' ], {\n' + ' b;\n' + ' });\n' + '}') bt( 'a ();\n' + ' [\n' + ' ["sdfsdfsd"],\n' + ' ["sdfsdfsdf"]\n' + ' ].toString();', # -- output -- 'a();\n' + '[\n' + ' ["sdfsdfsd"],\n' + ' ["sdfsdfsdf"]\n' + '].toString();') bt( 'a ();\n' + 'a = [\n' + ' ["sdfsdfsd"],\n' + ' ["sdfsdfsdf"]\n' + ' ].toString();', # -- output -- 'a();\n' + 'a = [\n' + ' ["sdfsdfsd"],\n' + ' ["sdfsdfsdf"]\n' + '].toString();') bt( 'function() {\n' + ' Foo([\n' + ' ["sdfsdfsd"],\n' + ' ["sdfsdfsdf"]\n' + ' ]);\n' + '}', # -- output -- 'function() {\n' + ' Foo([\n' + ' ["sdfsdfsd"],\n' + ' ["sdfsdfsdf"]\n' + ' ]);\n' + '}') bt( 'function foo() {\n' + ' return [\n' + ' "one",\n' + ' "two"\n' + ' ];\n' + '}', # -- output -- 'function foo() {\n' + ' return [\n' + ' "one",\n' + ' "two"\n' + ' ];\n' + '}') bt( 'function foo() {\n' + ' return [\n' + ' {\n' + ' one: "x",\n' + ' two: [\n' + ' {\n' + ' id: "a",\n' + ' name: "apple"\n' + ' }, {\n' + ' id: "b",\n' + ' name: "banana"\n' + ' }\n' + ' ]\n' + ' }\n' + ' ];\n' + '}', # -- output -- 'function foo() {\n' + ' return [{\n' + ' one: "x",\n' + ' two: [{\n' + ' id: "a",\n' + ' name: "apple"\n' + ' }, {\n' + ' id: "b",\n' + ' name: "banana"\n' + ' }]\n' + ' }];\n' + '}') bt( 'function foo() {\n' + ' return [\n' + ' {\n' + ' one: "x",\n' + ' two: [\n' + ' {\n' + ' id: "a",\n' + ' name: "apple"\n' + ' }, {\n' + ' id: "b",\n' + ' name: "banana"\n' + ' }\n' + ' ]\n' + ' }\n' + ' ];\n' + '}', # -- output -- 'function foo() {\n' + ' return [{\n' + ' one: "x",\n' + ' two: [{\n' + ' id: "a",\n' + ' name: "apple"\n' + ' }, {\n' + ' id: "b",\n' + ' name: "banana"\n' + ' }]\n' + ' }];\n' + '}') #============================================================ # keep_array_indentation true self.reset_options() self.options.keep_array_indentation = true bt( 'a = ["a", "b", "c",\n' + ' "d", "e", "f"]', # -- output -- 'a = ["a", "b", "c",\n' + ' "d", "e", "f"]') bt( 'a = ["a", "b", "c",\n' + ' "d", "e", "f",\n' + ' "g", "h", "i"]', # -- output -- 'a = ["a", "b", "c",\n' + ' "d", "e", "f",\n' + ' "g", "h", "i"]') bt( 'a = ["a", "b", "c",\n' + ' "d", "e", "f",\n' + ' "g", "h", "i"]', # -- output -- 'a = ["a", "b", "c",\n' + ' "d", "e", "f",\n' + ' "g", "h", "i"]') bt( 'var x = [{}\n' + ']', # -- output -- 'var x = [{}\n' + ']') bt( 'var x = [{foo:bar}\n' + ']', # -- output -- 'var x = [{\n' + ' foo: bar\n' + ' }\n' + ']') bt( 'a = ["something",\n' + ' "completely",\n' + ' "different"];\n' + 'if (x);', # -- output -- 'a = ["something",\n' + ' "completely",\n' + ' "different"];\n' + 'if (x);') bt('a = ["a","b","c"]', 'a = ["a", "b", "c"]') bt('a = ["a", "b","c"]', 'a = ["a", "b", "c"]') bt( 'x = [{"a":0}]', # -- output -- 'x = [{\n' + ' "a": 0\n' + '}]') bt( '{a([[a1]], {b;});}', # -- output -- '{\n' + ' a([[a1]], {\n' + ' b;\n' + ' });\n' + '}') bt( 'a ();\n' + ' [\n' + ' ["sdfsdfsd"],\n' + ' ["sdfsdfsdf"]\n' + ' ].toString();', # -- output -- 'a();\n' + ' [\n' + ' ["sdfsdfsd"],\n' + ' ["sdfsdfsdf"]\n' + ' ].toString();') bt( 'a ();\n' + 'a = [\n' + ' ["sdfsdfsd"],\n' + ' ["sdfsdfsdf"]\n' + ' ].toString();', # -- output -- 'a();\n' + 'a = [\n' + ' ["sdfsdfsd"],\n' + ' ["sdfsdfsdf"]\n' + ' ].toString();') bt( 'function() {\n' + ' Foo([\n' + ' ["sdfsdfsd"],\n' + ' ["sdfsdfsdf"]\n' + ' ]);\n' + '}', # -- output -- 'function() {\n' + ' Foo([\n' + ' ["sdfsdfsd"],\n' + ' ["sdfsdfsdf"]\n' + ' ]);\n' + '}') bt( 'function foo() {\n' + ' return [\n' + ' "one",\n' + ' "two"\n' + ' ];\n' + '}', # -- output -- 'function foo() {\n' + ' return [\n' + ' "one",\n' + ' "two"\n' + ' ];\n' + '}') bt( 'function foo() {\n' + ' return [\n' + ' {\n' + ' one: "x",\n' + ' two: [\n' + ' {\n' + ' id: "a",\n' + ' name: "apple"\n' + ' }, {\n' + ' id: "b",\n' + ' name: "banana"\n' + ' }\n' + ' ]\n' + ' }\n' + ' ];\n' + '}', # -- output -- 'function foo() {\n' + ' return [\n' + ' {\n' + ' one: "x",\n' + ' two: [\n' + ' {\n' + ' id: "a",\n' + ' name: "apple"\n' + ' }, {\n' + ' id: "b",\n' + ' name: "banana"\n' + ' }\n' + ' ]\n' + ' }\n' + ' ];\n' + '}') #============================================================ # indent_empty_lines true self.reset_options() self.options.indent_empty_lines = true test_fragment( 'var a = 1;\n' + '\n' + 'var b = 1;') test_fragment( 'var a = 1;\n' + ' \n' + 'var b = 1;', # -- output -- 'var a = 1;\n' + '\n' + 'var b = 1;') test_fragment( '{\n' + ' var a = 1;\n' + ' \n' + ' var b = 1;\n' + '\n' + '}', # -- output -- '{\n' + ' var a = 1;\n' + ' \n' + ' var b = 1;\n' + ' \n' + '}') test_fragment( '{\n' + '\n' + ' var a = 1;\n' + '\n' + '\n' + '\n' + ' var b = 1;\n' + '\n' + '}', # -- output -- '{\n' + ' \n' + ' var a = 1;\n' + ' \n' + ' \n' + ' \n' + ' var b = 1;\n' + ' \n' + '}') test_fragment( '{\n' + '\n' + ' var a = 1;\n' + '\n' + 'function A() {\n' + '\n' + '}\n' + '\n' + ' var b = 1;\n' + '\n' + '}', # -- output -- '{\n' + ' \n' + ' var a = 1;\n' + ' \n' + ' function A() {\n' + ' \n' + ' }\n' + ' \n' + ' var b = 1;\n' + ' \n' + '}') #============================================================ # indent_empty_lines false self.reset_options() self.options.indent_empty_lines = false test_fragment( 'var a = 1;\n' + '\n' + 'var b = 1;') test_fragment( 'var a = 1;\n' + ' \n' + 'var b = 1;', # -- output -- 'var a = 1;\n' + '\n' + 'var b = 1;') test_fragment( '{\n' + ' var a = 1;\n' + ' \n' + ' var b = 1;\n' + '\n' + '}', # -- output -- '{\n' + ' var a = 1;\n' + '\n' + ' var b = 1;\n' + '\n' + '}') test_fragment( '{\n' + '\n' + ' var a = 1;\n' + '\n' + '\n' + '\n' + ' var b = 1;\n' + '\n' + '}') test_fragment( '{\n' + '\n' + ' var a = 1;\n' + '\n' + 'function A() {\n' + '\n' + '}\n' + '\n' + ' var b = 1;\n' + '\n' + '}', # -- output -- '{\n' + '\n' + ' var a = 1;\n' + '\n' + ' function A() {\n' + '\n' + ' }\n' + '\n' + ' var b = 1;\n' + '\n' + '}') #============================================================ # Record data type self.reset_options() # regular record with primitive bt( 'a = #{ b:"c", d:1, e:true };', # -- output -- 'a = #{\n' + ' b: "c",\n' + ' d: 1,\n' + ' e: true\n' + '};') # nested record bt( 'a = #{b:#{ c:1,d:2,}, e:"f"};', # -- output -- 'a = #{\n' + ' b: #{\n' + ' c: 1,\n' + ' d: 2,\n' + ' },\n' + ' e: "f"\n' + '};') # # not directly followed by { is not handled as record bt( 'a = # {\n' + ' b: 1,\n' + ' d: true\n' + '};') # example of already valid and beautified record bt( 'a = #{\n' + ' b: 1,\n' + ' d: true\n' + '};') #============================================================ # Old tests self.reset_options() bt('') test_fragment(' return .5') test_fragment( ' return .5;\n' + ' a();') test_fragment( ' return .5;\n' + ' a();') test_fragment( ' return .5;\n' + ' a();') test_fragment(' < div') bt('a = 1', 'a = 1') bt('a=1', 'a = 1') bt('(3) / 2') bt('["a", "b"].join("")') bt( 'a();\n' + '\n' + 'b();') bt( 'var a = 1 var b = 2', # -- output -- 'var a = 1\n' + 'var b = 2') bt( 'var a=1, b=c[d], e=6;', # -- output -- 'var a = 1,\n' + ' b = c[d],\n' + ' e = 6;') bt( 'var a,\n' + ' b,\n' + ' c;') bt( 'let a = 1 let b = 2', # -- output -- 'let a = 1\n' + 'let b = 2') bt( 'let a=1, b=c[d], e=6;', # -- output -- 'let a = 1,\n' + ' b = c[d],\n' + ' e = 6;') bt( 'let a,\n' + ' b,\n' + ' c;') bt( 'const a = 1 const b = 2', # -- output -- 'const a = 1\n' + 'const b = 2') bt( 'const a=1, b=c[d], e=6;', # -- output -- 'const a = 1,\n' + ' b = c[d],\n' + ' e = 6;') bt( 'const a,\n' + ' b,\n' + ' c;') bt('a = " 12345 "') bt('a = \' 12345 \'') bt('if (a == 1) b = 2;') bt( 'if(1){2}else{3}', # -- output -- 'if (1) {\n' + ' 2\n' + '} else {\n' + ' 3\n' + '}') bt('if(1||2);', 'if (1 || 2);') bt('(a==1)||(b==2)', '(a == 1) || (b == 2)') bt( 'var a = 1 if (2) 3;', # -- output -- 'var a = 1\n' + 'if (2) 3;') bt('a = a + 1') bt('a = a == 1') bt('/12345[^678]*9+/.match(a)') bt('a /= 5') bt('a = 0.5 * 3') bt('a *= 10.55') bt('a < .5') bt('a <= .5') bt('a<.5', 'a < .5') bt('a<=.5', 'a <= .5') bt('a = [1, 2, 3, 4]') bt('F*(g/=f)*g+b', 'F * (g /= f) * g + b') bt( 'a.b({c:d})', # -- output -- 'a.b({\n' + ' c: d\n' + '})') bt( 'a.b\n' + '(\n' + '{\n' + 'c:\n' + 'd\n' + '}\n' + ')', # -- output -- 'a.b({\n' + ' c: d\n' + '})') bt( 'a.b({c:"d"})', # -- output -- 'a.b({\n' + ' c: "d"\n' + '})') bt( 'a.b\n' + '(\n' + '{\n' + 'c:\n' + '"d"\n' + '}\n' + ')', # -- output -- 'a.b({\n' + ' c: "d"\n' + '})') bt('a=!b', 'a = !b') bt('a=!!b', 'a = !!b') bt('a?b:c', 'a ? b : c') bt('a?1:2', 'a ? 1 : 2') bt('a?(b):c', 'a ? (b) : c') bt( 'x={a:1,b:w=="foo"?x:y,c:z}', # -- output -- 'x = {\n' + ' a: 1,\n' + ' b: w == "foo" ? x : y,\n' + ' c: z\n' + '}') bt('x=a?b?c?d:e:f:g;', 'x = a ? b ? c ? d : e : f : g;') bt( 'x=a?b?c?d:{e1:1,e2:2}:f:g;', # -- output -- 'x = a ? b ? c ? d : {\n' + ' e1: 1,\n' + ' e2: 2\n' + '} : f : g;') bt('function void(void) {}') bt('if(!a)foo();', 'if (!a) foo();') bt('a=~a', 'a = ~a') bt( 'a;/*comment*/b;', # -- output -- 'a; /*comment*/\n' + 'b;') bt( 'a;/* comment */b;', # -- output -- 'a; /* comment */\n' + 'b;') # simple comments don't get touched at all test_fragment( 'a;/*\n' + 'comment\n' + '*/b;', # -- output -- 'a;\n' + '/*\n' + 'comment\n' + '*/\n' + 'b;') bt( 'a;/**\n' + '* javadoc\n' + '*/b;', # -- output -- 'a;\n' + '/**\n' + ' * javadoc\n' + ' */\n' + 'b;') test_fragment( 'a;/**\n' + '\n' + 'no javadoc\n' + '*/b;', # -- output -- 'a;\n' + '/**\n' + '\n' + 'no javadoc\n' + '*/\n' + 'b;') # comment blocks detected and reindented even w/o javadoc starter bt( 'a;/*\n' + '* javadoc\n' + '*/b;', # -- output -- 'a;\n' + '/*\n' + ' * javadoc\n' + ' */\n' + 'b;') bt('if(a)break;', 'if (a) break;') bt( 'if(a){break}', # -- output -- 'if (a) {\n' + ' break\n' + '}') bt('if((a))foo();', 'if ((a)) foo();') bt('for(var i=0;;) a', 'for (var i = 0;;) a') bt( 'for(var i=0;;)\n' + 'a', # -- output -- 'for (var i = 0;;)\n' + ' a') bt('a++;') bt('for(;;i++)a()', 'for (;; i++) a()') bt( 'for(;;i++)\n' + 'a()', # -- output -- 'for (;; i++)\n' + ' a()') bt('for(;;++i)a', 'for (;; ++i) a') bt('return(1)', 'return (1)') bt( 'try{a();}catch(b){c();}finally{d();}', # -- output -- 'try {\n' + ' a();\n' + '} catch (b) {\n' + ' c();\n' + '} finally {\n' + ' d();\n' + '}') # magic function call bt('(xx)()') # another magic function call bt('a[1]()') bt( 'if(a){b();}else if(c) foo();', # -- output -- 'if (a) {\n' + ' b();\n' + '} else if (c) foo();') bt( 'switch(x) {case 0: case 1: a(); break; default: break}', # -- output -- 'switch (x) {\n' + ' case 0:\n' + ' case 1:\n' + ' a();\n' + ' break;\n' + ' default:\n' + ' break\n' + '}') bt( 'switch(x) {default: case 1: a(); break; case 0: break}', # -- output -- 'switch (x) {\n' + ' default:\n' + ' case 1:\n' + ' a();\n' + ' break;\n' + ' case 0:\n' + ' break\n' + '}') bt( 'switch(x){case -1:break;case !y:break;}', # -- output -- 'switch (x) {\n' + ' case -1:\n' + ' break;\n' + ' case !y:\n' + ' break;\n' + '}') bt('a !== b') bt( 'if (a) b(); else c();', # -- output -- 'if (a) b();\n' + 'else c();') # typical greasemonkey start bt( '// comment\n' + '(function something() {})') # duplicating newlines bt( '{\n' + '\n' + ' x();\n' + '\n' + '}') bt('if (a in b) foo();') bt('if (a of b) foo();') bt('if (a of [1, 2, 3]) foo();') bt( 'if(X)if(Y)a();else b();else c();', # -- output -- 'if (X)\n' + ' if (Y) a();\n' + ' else b();\n' + 'else c();') bt( 'if (foo) bar();\n' + 'else break') bt('var a, b;') bt('var a = new function();') test_fragment('new function') bt('var a, b') bt( '{a:1, b:2}', # -- output -- '{\n' + ' a: 1,\n' + ' b: 2\n' + '}') bt( 'a={1:[-1],2:[+1]}', # -- output -- 'a = {\n' + ' 1: [-1],\n' + ' 2: [+1]\n' + '}') bt( 'var l = {\'a\':\'1\', \'b\':\'2\'}', # -- output -- 'var l = {\n' + ' \'a\': \'1\',\n' + ' \'b\': \'2\'\n' + '}') bt('if (template.user[n] in bk) foo();') bt('return 45') bt( 'return this.prevObject ||\n' + '\n' + ' this.constructor(null);') bt('If[1]') bt('Then[1]') bt('a = 1;// comment', 'a = 1; // comment') bt('a = 1; // comment') bt( 'a = 1;\n' + ' // comment', # -- output -- 'a = 1;\n' + '// comment') bt('a = [-1, -1, -1]') bt( '// a\n' + '// b\n' + '\n' + '\n' + '\n' + '// c\n' + '// d') bt( '// func-comment\n' + '\n' + 'function foo() {}\n' + '\n' + '// end-func-comment') # The exact formatting these should have is open for discussion, but they are at least reasonable bt( 'a = [ // comment\n' + ' -1, -1, -1\n' + ']') bt( 'var a = [ // comment\n' + ' -1, -1, -1\n' + ']') bt( 'a = [ // comment\n' + ' -1, // comment\n' + ' -1, -1\n' + ']') bt( 'var a = [ // comment\n' + ' -1, // comment\n' + ' -1, -1\n' + ']') bt( 'o = [{a:b},{c:d}]', # -- output -- 'o = [{\n' + ' a: b\n' + '}, {\n' + ' c: d\n' + '}]') # was: extra space appended bt( 'if (a) {\n' + ' do();\n' + '}') # if/else statement with empty body bt( 'if (a) {\n' + '// comment\n' + '}else{\n' + '// comment\n' + '}', # -- output -- 'if (a) {\n' + ' // comment\n' + '} else {\n' + ' // comment\n' + '}') # multiple comments indentation bt( 'if (a) {\n' + '// comment\n' + '// comment\n' + '}', # -- output -- 'if (a) {\n' + ' // comment\n' + ' // comment\n' + '}') bt( 'if (a) b() else c();', # -- output -- 'if (a) b()\n' + 'else c();') bt( 'if (a) b() else if c() d();', # -- output -- 'if (a) b()\n' + 'else if c() d();') bt('{}') bt( '{\n' + '\n' + '}') bt( 'do { a(); } while ( 1 );', # -- output -- 'do {\n' + ' a();\n' + '} while (1);') bt('do {} while (1);') bt( 'do {\n' + '} while (1);', # -- output -- 'do {} while (1);') bt( 'do {\n' + '\n' + '} while (1);') bt('var a = x(a, b, c)') bt( 'delete x if (a) b();', # -- output -- 'delete x\n' + 'if (a) b();') bt( 'delete x[x] if (a) b();', # -- output -- 'delete x[x]\n' + 'if (a) b();') bt('for(var a=1,b=2)d', 'for (var a = 1, b = 2) d') bt('for(var a=1,b=2,c=3) d', 'for (var a = 1, b = 2, c = 3) d') bt( 'for(var a=1,b=2,c=3;d<3;d++)\n' + 'e', # -- output -- 'for (var a = 1, b = 2, c = 3; d < 3; d++)\n' + ' e') bt( 'function x(){(a||b).c()}', # -- output -- 'function x() {\n' + ' (a || b).c()\n' + '}') bt( 'function x(){return - 1}', # -- output -- 'function x() {\n' + ' return -1\n' + '}') bt( 'function x(){return ! a}', # -- output -- 'function x() {\n' + ' return !a\n' + '}') bt('x => x') bt('(x) => x') bt( 'x => { x }', # -- output -- 'x => {\n' + ' x\n' + '}') bt( '(x) => { x }', # -- output -- '(x) => {\n' + ' x\n' + '}') # a common snippet in jQuery plugins bt( 'settings = $.extend({},defaults,settings);', # -- output -- 'settings = $.extend({}, defaults, settings);') bt('$http().then().finally().default()') bt( '$http()\n' + '.then()\n' + '.finally()\n' + '.default()', # -- output -- '$http()\n' + ' .then()\n' + ' .finally()\n' + ' .default()') bt('$http().when.in.new.catch().throw()') bt( '$http()\n' + '.when\n' + '.in\n' + '.new\n' + '.catch()\n' + '.throw()', # -- output -- '$http()\n' + ' .when\n' + ' .in\n' + ' .new\n' + ' .catch()\n' + ' .throw()') bt( '{xxx;}()', # -- output -- '{\n' + ' xxx;\n' + '}()') bt( 'a = \'a\'\n' + 'b = \'b\'') bt('a = /reg/exp') bt('a = /reg/') bt('/abc/.test()') bt('/abc/i.test()') bt( '{/abc/i.test()}', # -- output -- '{\n' + ' /abc/i.test()\n' + '}') bt('var x=(a)/a;', 'var x = (a) / a;') bt('x != -1') bt('for (; s-->0;)t', 'for (; s-- > 0;) t') bt('for (; s++>0;)u', 'for (; s++ > 0;) u') bt('a = s++>s--;', 'a = s++ > s--;') bt('a = s++>--s;', 'a = s++ > --s;') bt( '{x=#1=[]}', # -- output -- '{\n' + ' x = #1=[]\n' + '}') bt( '{a:#1={}}', # -- output -- '{\n' + ' a: #1={}\n' + '}') bt( '{a:#1#}', # -- output -- '{\n' + ' a: #1#\n' + '}') test_fragment('"incomplete-string') test_fragment('\'incomplete-string') test_fragment('/incomplete-regex') test_fragment('`incomplete-template-string') test_fragment( '{a:1},{a:2}', # -- output -- '{\n' + ' a: 1\n' + '}, {\n' + ' a: 2\n' + '}') test_fragment( 'var ary=[{a:1}, {a:2}];', # -- output -- 'var ary = [{\n' + ' a: 1\n' + '}, {\n' + ' a: 2\n' + '}];') # incomplete test_fragment( '{a:#1', # -- output -- '{\n' + ' a: #1') # incomplete test_fragment( '{a:#', # -- output -- '{\n' + ' a: #') # incomplete test_fragment( '}}}', # -- output -- '}\n' + '}\n' + '}') test_fragment( '') # incomplete regexp test_fragment('a=/regexp', 'a = /regexp') bt( '{a:#1=[],b:#1#,c:#999999#}', # -- output -- '{\n' + ' a: #1=[],\n' + ' b: #1#,\n' + ' c: #999999#\n' + '}') bt( 'do{x()}while(a>1)', # -- output -- 'do {\n' + ' x()\n' + '} while (a > 1)') bt( 'x(); /reg/exp.match(something)', # -- output -- 'x();\n' + '/reg/exp.match(something)') test_fragment( 'something();(', # -- output -- 'something();\n' + '(') test_fragment( '#!she/bangs, she bangs\n' + 'f=1', # -- output -- '#!she/bangs, she bangs\n' + '\n' + 'f = 1') test_fragment( '#!she/bangs, she bangs\n' + '\n' + 'f=1', # -- output -- '#!she/bangs, she bangs\n' + '\n' + 'f = 1') test_fragment( '#!she/bangs, she bangs\n' + '\n' + '/* comment */') test_fragment( '#!she/bangs, she bangs\n' + '\n' + '\n' + '/* comment */') test_fragment('#') test_fragment('#!') test_fragment('#include') test_fragment('#include "settings.jsxinc"') test_fragment( '#include "settings.jsxinc"\n' + '\n' + '\n' + '/* comment */') test_fragment( '#include "settings.jsxinc"\n' + '\n' + '\n' + '#include "settings.jsxinc"\n' + '\n' + '\n' + '/* comment */') bt('function namespace::something()') test_fragment( '') test_fragment( '', # -- output -- '') bt( '{foo();--bar;}', # -- output -- '{\n' + ' foo();\n' + ' --bar;\n' + '}') bt( '{foo();++bar;}', # -- output -- '{\n' + ' foo();\n' + ' ++bar;\n' + '}') bt( '{--bar;}', # -- output -- '{\n' + ' --bar;\n' + '}') bt( '{++bar;}', # -- output -- '{\n' + ' ++bar;\n' + '}') bt('if(true)++a;', 'if (true) ++a;') bt( 'if(true)\n' + '++a;', # -- output -- 'if (true)\n' + ' ++a;') bt('if(true)--a;', 'if (true) --a;') bt( 'if(true)\n' + '--a;', # -- output -- 'if (true)\n' + ' --a;') bt('elem[array]++;') bt('elem++ * elem[array]++;') bt('elem-- * -elem[array]++;') bt('elem-- + elem[array]++;') bt('elem-- - elem[array]++;') bt('elem-- - -elem[array]++;') bt('elem-- - +elem[array]++;') # Handling of newlines around unary ++ and -- operators bt( '{foo\n' + '++bar;}', # -- output -- '{\n' + ' foo\n' + ' ++bar;\n' + '}') bt( '{foo++\n' + 'bar;}', # -- output -- '{\n' + ' foo++\n' + ' bar;\n' + '}') # This is invalid, but harder to guard against. Issue #203. bt( '{foo\n' + '++\n' + 'bar;}', # -- output -- '{\n' + ' foo\n' + ' ++\n' + ' bar;\n' + '}') # regexps bt( 'a(/abc\\/\\/def/);b()', # -- output -- 'a(/abc\\/\\/def/);\n' + 'b()') bt( 'a(/a[b\\[\\]c]d/);b()', # -- output -- 'a(/a[b\\[\\]c]d/);\n' + 'b()') # incomplete char class test_fragment('a(/a[b\\[') # allow unescaped / in char classes bt( 'a(/[a/b]/);b()', # -- output -- 'a(/[a/b]/);\n' + 'b()') bt('typeof /foo\\//;') bt('throw /foo\\//;') bt('do /foo\\//;') bt('return /foo\\//;') bt( 'switch (a) {\n' + ' case /foo\\//:\n' + ' b\n' + '}') bt( 'if (a) /foo\\//\n' + 'else /foo\\//;') bt('if (foo) /regex/.test();') bt('for (index in [1, 2, 3]) /^test$/i.test(s)') bt( 'function foo() {\n' + ' return [\n' + ' "one",\n' + ' "two"\n' + ' ];\n' + '}') bt( 'a=[[1,2],[4,5],[7,8]]', # -- output -- 'a = [\n' + ' [1, 2],\n' + ' [4, 5],\n' + ' [7, 8]\n' + ']') bt( 'a=[[1,2],[4,5],function(){},[7,8]]', # -- output -- 'a = [\n' + ' [1, 2],\n' + ' [4, 5],\n' + ' function() {},\n' + ' [7, 8]\n' + ']') bt( 'a=[[1,2],[4,5],function(){},function(){},[7,8]]', # -- output -- 'a = [\n' + ' [1, 2],\n' + ' [4, 5],\n' + ' function() {},\n' + ' function() {},\n' + ' [7, 8]\n' + ']') bt( 'a=[[1,2],[4,5],function(){},[7,8]]', # -- output -- 'a = [\n' + ' [1, 2],\n' + ' [4, 5],\n' + ' function() {},\n' + ' [7, 8]\n' + ']') bt('a=[b,c,function(){},function(){},d]', 'a = [b, c, function() {}, function() {}, d]') bt( 'a=[b,c,\n' + 'function(){},function(){},d]', # -- output -- 'a = [b, c,\n' + ' function() {},\n' + ' function() {},\n' + ' d\n' + ']') bt('a=[a[1],b[4],c[d[7]]]', 'a = [a[1], b[4], c[d[7]]]') bt('[1,2,[3,4,[5,6],7],8]', '[1, 2, [3, 4, [5, 6], 7], 8]') bt( '[[["1","2"],["3","4"]],[["5","6","7"],["8","9","0"]],[["1","2","3"],["4","5","6","7"],["8","9","0"]]]', # -- output -- '[\n' + ' [\n' + ' ["1", "2"],\n' + ' ["3", "4"]\n' + ' ],\n' + ' [\n' + ' ["5", "6", "7"],\n' + ' ["8", "9", "0"]\n' + ' ],\n' + ' [\n' + ' ["1", "2", "3"],\n' + ' ["4", "5", "6", "7"],\n' + ' ["8", "9", "0"]\n' + ' ]\n' + ']') bt( '{[x()[0]];indent;}', # -- output -- '{\n' + ' [x()[0]];\n' + ' indent;\n' + '}') bt( '/*\n' + ' foo trailing space \n' + ' * bar trailing space \n' + '**/') bt( '{\n' + ' /*\n' + ' foo \n' + ' * bar \n' + ' */\n' + '}') bt('return ++i') bt( 'obj.num++\n' + 'foo()\n' + 'bar()\n' + '\n' + 'obj.num--\n' + 'foo()\n' + 'bar()') bt('return !!x') bt('return !x') bt('return [1,2]', 'return [1, 2]') bt('return;') bt( 'return\n' + 'func') bt('catch(e)', 'catch (e)') bt( 'var a=1,b={foo:2,bar:3},{baz:4,wham:5},c=4;', # -- output -- 'var a = 1,\n' + ' b = {\n' + ' foo: 2,\n' + ' bar: 3\n' + ' },\n' + ' {\n' + ' baz: 4,\n' + ' wham: 5\n' + ' }, c = 4;') bt( 'var a=1,b={foo:2,bar:3},{baz:4,wham:5},\n' + 'c=4;', # -- output -- 'var a = 1,\n' + ' b = {\n' + ' foo: 2,\n' + ' bar: 3\n' + ' },\n' + ' {\n' + ' baz: 4,\n' + ' wham: 5\n' + ' },\n' + ' c = 4;') # inline comment bt( 'function x(/*int*/ start, /*string*/ foo)', # -- output -- 'function x( /*int*/ start, /*string*/ foo)') # javadoc comment bt( '/**\n' + '* foo\n' + '*/', # -- output -- '/**\n' + ' * foo\n' + ' */') bt( '{\n' + '/**\n' + '* foo\n' + '*/\n' + '}', # -- output -- '{\n' + ' /**\n' + ' * foo\n' + ' */\n' + '}') # starless block comment bt( '/**\n' + 'foo\n' + '*/') bt( '/**\n' + 'foo\n' + '**/') bt( '/**\n' + 'foo\n' + 'bar\n' + '**/') bt( '/**\n' + 'foo\n' + '\n' + 'bar\n' + '**/') bt( '/**\n' + 'foo\n' + ' bar\n' + '**/') bt( '{\n' + '/**\n' + 'foo\n' + '*/\n' + '}', # -- output -- '{\n' + ' /**\n' + ' foo\n' + ' */\n' + '}') bt( '{\n' + '/**\n' + 'foo\n' + '**/\n' + '}', # -- output -- '{\n' + ' /**\n' + ' foo\n' + ' **/\n' + '}') bt( '{\n' + '/**\n' + 'foo\n' + 'bar\n' + '**/\n' + '}', # -- output -- '{\n' + ' /**\n' + ' foo\n' + ' bar\n' + ' **/\n' + '}') bt( '{\n' + '/**\n' + 'foo\n' + '\n' + 'bar\n' + '**/\n' + '}', # -- output -- '{\n' + ' /**\n' + ' foo\n' + '\n' + ' bar\n' + ' **/\n' + '}') bt( '{\n' + '/**\n' + 'foo\n' + ' bar\n' + '**/\n' + '}', # -- output -- '{\n' + ' /**\n' + ' foo\n' + ' bar\n' + ' **/\n' + '}') bt( '{\n' + ' /**\n' + ' foo\n' + 'bar\n' + ' **/\n' + '}') bt( 'var a,b,c=1,d,e,f=2;', # -- output -- 'var a, b, c = 1,\n' + ' d, e, f = 2;') bt( 'var a,b,c=[],d,e,f=2;', # -- output -- 'var a, b, c = [],\n' + ' d, e, f = 2;') bt( 'function() {\n' + ' var a, b, c, d, e = [],\n' + ' f;\n' + '}') bt( 'do/regexp/;\n' + 'while(1);', # -- output -- 'do /regexp/;\n' + 'while (1);') bt( 'var a = a,\n' + 'a;\n' + 'b = {\n' + 'b\n' + '}', # -- output -- 'var a = a,\n' + ' a;\n' + 'b = {\n' + ' b\n' + '}') bt( 'var a = a,\n' + ' /* c */\n' + ' b;') bt( 'var a = a,\n' + ' // c\n' + ' b;') # weird element referencing bt('foo.("bar");') bt( 'if (a) a()\n' + 'else b()\n' + 'newline()') bt( 'if (a) a()\n' + 'newline()') bt('a=typeof(x)', 'a = typeof(x)') bt( 'var a = function() {\n' + ' return null;\n' + ' },\n' + ' b = false;') bt( 'var a = function() {\n' + ' func1()\n' + '}') bt( 'var a = function() {\n' + ' func1()\n' + '}\n' + 'var b = function() {\n' + ' func2()\n' + '}') # code with and without semicolons bt( 'var whatever = require("whatever");\n' + 'function() {\n' + ' a = 6;\n' + '}', # -- output -- 'var whatever = require("whatever");\n' + '\n' + 'function() {\n' + ' a = 6;\n' + '}') bt( 'var whatever = require("whatever")\n' + 'function() {\n' + ' a = 6\n' + '}', # -- output -- 'var whatever = require("whatever")\n' + '\n' + 'function() {\n' + ' a = 6\n' + '}') bt( '{"x":[{"a":1,"b":3},\n' + '7,8,8,8,8,{"b":99},{"a":11}]}', # -- output -- '{\n' + ' "x": [{\n' + ' "a": 1,\n' + ' "b": 3\n' + ' },\n' + ' 7, 8, 8, 8, 8, {\n' + ' "b": 99\n' + ' }, {\n' + ' "a": 11\n' + ' }\n' + ' ]\n' + '}') bt( '{"x":[{"a":1,"b":3},7,8,8,8,8,{"b":99},{"a":11}]}', # -- output -- '{\n' + ' "x": [{\n' + ' "a": 1,\n' + ' "b": 3\n' + ' }, 7, 8, 8, 8, 8, {\n' + ' "b": 99\n' + ' }, {\n' + ' "a": 11\n' + ' }]\n' + '}') bt( '{"1":{"1a":"1b"},"2"}', # -- output -- '{\n' + ' "1": {\n' + ' "1a": "1b"\n' + ' },\n' + ' "2"\n' + '}') bt( '{a:{a:b},c}', # -- output -- '{\n' + ' a: {\n' + ' a: b\n' + ' },\n' + ' c\n' + '}') bt( '{[y[a]];keep_indent;}', # -- output -- '{\n' + ' [y[a]];\n' + ' keep_indent;\n' + '}') bt( 'if (x) {y} else { if (x) {y}}', # -- output -- 'if (x) {\n' + ' y\n' + '} else {\n' + ' if (x) {\n' + ' y\n' + ' }\n' + '}') bt( 'if (foo) one()\n' + 'two()\n' + 'three()') bt( 'if (1 + foo() && bar(baz()) / 2) one()\n' + 'two()\n' + 'three()') bt( 'if (1 + foo() && bar(baz()) / 2) one();\n' + 'two();\n' + 'three();') bt( 'var a=1,b={bang:2},c=3;', # -- output -- 'var a = 1,\n' + ' b = {\n' + ' bang: 2\n' + ' },\n' + ' c = 3;') bt( 'var a={bing:1},b=2,c=3;', # -- output -- 'var a = {\n' + ' bing: 1\n' + ' },\n' + ' b = 2,\n' + ' c = 3;') # Issue #1896: Handle newlines with bitwise ~ operator bt( 'if (foo) {\n' + 'var bar = 1;\n' + '~bar ? 0 : 1\n' + ' }', # -- output -- 'if (foo) {\n' + ' var bar = 1;\n' + ' ~bar ? 0 : 1\n' + '}') def test_beautifier_unconverted(self): test_fragment = self.decodesto bt = self.bt self.reset_options() #============================================================ bt(None, "") self.reset_options() #============================================================ # Test user pebkac protection, converts dash names to underscored names setattr(self.options, 'end-with-newline', True) test_fragment(None, '\n') self.reset_options() #============================================================ # Test passing dictionary or tuple self.options = {'end_with_newline': True, 'eol': '\r\n' } test_fragment(None, '\r\n') self.options = {'end-with-newline': True} test_fragment(None, '\n') self.options = {'end-with-newline': False} test_fragment(None, '') self.options = ( ('end-with-newline', True), ('eol', '\r') ) test_fragment(None, '\r') self.reset_options() #============================================================ self.options.indent_size = 1 self.options.indent_char = ' ' bt('{ one_char() }', "{\n one_char()\n}") bt('var a,b=1,c=2', 'var a, b = 1,\n c = 2') self.options.indent_size = 4 self.options.indent_char = ' ' bt('{ one_char() }', "{\n one_char()\n}") self.options.indent_size = 1 self.options.indent_char = "\t" bt('{ one_char() }', "{\n\tone_char()\n}") bt('x = a ? b : c; x;', 'x = a ? b : c;\nx;') #set to something else than it should change to, but with tabs on, should override self.options.indent_size = 5 self.options.indent_char = ' ' self.options.indent_with_tabs = True bt('{ one_char() }', "{\n\tone_char()\n}") bt('x = a ? b : c; x;', 'x = a ? b : c;\nx;') self.reset_options() #============================================================ self.options.preserve_newlines = False bt('var\na=dont_preserve_newlines;', 'var a = dont_preserve_newlines;') # make sure the blank line between function definitions stays # even when preserve_newlines = False bt('function foo() {\n return 1;\n}\n\nfunction foo() {\n return 1;\n}') bt('function foo() {\n return 1;\n}\nfunction foo() {\n return 1;\n}', 'function foo() {\n return 1;\n}\n\nfunction foo() {\n return 1;\n}' ) bt('function foo() {\n return 1;\n}\n\n\nfunction foo() {\n return 1;\n}', 'function foo() {\n return 1;\n}\n\nfunction foo() {\n return 1;\n}' ) self.options.preserve_newlines = True bt('var\na=do_preserve_newlines;', 'var\n a = do_preserve_newlines;') bt('if (foo) // comment\n{\n bar();\n}') self.reset_options() #============================================================ # START tests for brace positioning # If this is ever supported, update tests for each brace style. # test_fragment('return\n{', 'return\n{') # can't support this?, but that's an improbable and extreme case anyway. self.options.brace_style = 'expand' bt('//case 1\nif (a == 1)\n{}\n//case 2\nelse if (a == 2)\n{}') bt('if(1){2}else{3}', "if (1)\n{\n 2\n}\nelse\n{\n 3\n}") bt('try{a();}catch(b){c();}catch(d){}finally{e();}', "try\n{\n a();\n}\ncatch (b)\n{\n c();\n}\ncatch (d)\n{}\nfinally\n{\n e();\n}") bt('if(a){b();}else if(c) foo();', "if (a)\n{\n b();\n}\nelse if (c) foo();") bt("if (a) {\n// comment\n}else{\n// comment\n}", "if (a)\n{\n // comment\n}\nelse\n{\n // comment\n}") # if/else statement with empty body bt('if (x) {y} else { if (x) {y}}', 'if (x)\n{\n y\n}\nelse\n{\n if (x)\n {\n y\n }\n}') bt('if (a)\n{\nb;\n}\nelse\n{\nc;\n}', 'if (a)\n{\n b;\n}\nelse\n{\n c;\n}') test_fragment(' /*\n* xx\n*/\n// xx\nif (foo) {\n bar();\n}', ' /*\n * xx\n */\n // xx\n if (foo)\n {\n bar();\n }') bt('if (foo)\n{}\nelse /regex/.test();') test_fragment('if (foo) {', 'if (foo)\n{') test_fragment('foo {', 'foo\n{') test_fragment('return {', 'return {') # return needs the brace. test_fragment('return /* inline */ {', 'return /* inline */ {') test_fragment('return;\n{', 'return;\n{') bt("throw {}") bt("throw {\n foo;\n}") bt('var foo = {}') bt('function x() {\n foo();\n}zzz', 'function x()\n{\n foo();\n}\nzzz') test_fragment('a: do {} while (); xxx', 'a: do {} while ();\nxxx') bt('{a: do {} while (); xxx}', '{\n a: do {} while ();xxx\n}') bt('var a = new function() {};') bt('var a = new function a() {};', 'var a = new function a()\n{};') bt('var a = new function()\n{};', 'var a = new function() {};') bt('var a = new function a()\n{};') bt('var a = new function a()\n {},\n b = new function b()\n {};') bt("foo({\n 'a': 1\n},\n10);", "foo(\n {\n 'a': 1\n },\n 10);") bt('(["foo","bar"]).each(function(i) {return i;});', '(["foo", "bar"]).each(function(i)\n{\n return i;\n});') bt('(function(i) {return i;})();', '(function(i)\n{\n return i;\n})();') bt( "test( /*Argument 1*/ {\n" + " 'Value1': '1'\n" + "}, /*Argument 2\n" + " */ {\n" + " 'Value2': '2'\n" + "});", # expected "test( /*Argument 1*/\n" + " {\n" + " 'Value1': '1'\n" + " },\n" + " /*Argument 2\n" + " */\n" + " {\n" + " 'Value2': '2'\n" + " });") bt( "test(\n" + "/*Argument 1*/ {\n" + " 'Value1': '1'\n" + "},\n" + "/*Argument 2\n" + " */ {\n" + " 'Value2': '2'\n" + "});", # expected "test(\n" + " /*Argument 1*/\n" + " {\n" + " 'Value1': '1'\n" + " },\n" + " /*Argument 2\n" + " */\n" + " {\n" + " 'Value2': '2'\n" + " });") bt( "test( /*Argument 1*/\n" + "{\n" + " 'Value1': '1'\n" + "}, /*Argument 2\n" + " */\n" + "{\n" + " 'Value2': '2'\n" + "});", # expected "test( /*Argument 1*/\n" + " {\n" + " 'Value1': '1'\n" + " },\n" + " /*Argument 2\n" + " */\n" + " {\n" + " 'Value2': '2'\n" + " });") self.options.brace_style = 'collapse' bt('//case 1\nif (a == 1) {}\n//case 2\nelse if (a == 2) {}') bt('if(1){2}else{3}', "if (1) {\n 2\n} else {\n 3\n}") bt('try{a();}catch(b){c();}catch(d){}finally{e();}', "try {\n a();\n} catch (b) {\n c();\n} catch (d) {} finally {\n e();\n}") bt('if(a){b();}else if(c) foo();', "if (a) {\n b();\n} else if (c) foo();") bt("if (a) {\n// comment\n}else{\n// comment\n}", "if (a) {\n // comment\n} else {\n // comment\n}") # if/else statement with empty body bt('if (x) {y} else { if (x) {y}}', 'if (x) {\n y\n} else {\n if (x) {\n y\n }\n}') bt('if (a)\n{\nb;\n}\nelse\n{\nc;\n}', 'if (a) {\n b;\n} else {\n c;\n}') test_fragment(' /*\n* xx\n*/\n// xx\nif (foo) {\n bar();\n}', ' /*\n * xx\n */\n // xx\n if (foo) {\n bar();\n }') bt('if (foo) {} else /regex/.test();') test_fragment('if (foo) {', 'if (foo) {') test_fragment('foo {', 'foo {') test_fragment('return {', 'return {') # return needs the brace. test_fragment('return /* inline */ {', 'return /* inline */ {') test_fragment('return;\n{', 'return;\n{') bt("throw {}") bt("throw {\n foo;\n}") bt('var foo = {}') bt('function x() {\n foo();\n}zzz', 'function x() {\n foo();\n}\nzzz') test_fragment('a: do {} while (); xxx', 'a: do {} while ();\nxxx') bt('{a: do {} while (); xxx}', '{\n a: do {} while ();xxx\n}') bt('var a = new function() {};') bt('var a = new function a() {};') bt('var a = new function()\n{};', 'var a = new function() {};') bt('var a = new function a()\n{};', 'var a = new function a() {};') bt('var a = new function a()\n {},\n b = new function b()\n {};', 'var a = new function a() {},\n b = new function b() {};') bt("foo({\n 'a': 1\n},\n10);", "foo({\n 'a': 1\n },\n 10);") bt('(["foo","bar"]).each(function(i) {return i;});', '(["foo", "bar"]).each(function(i) {\n return i;\n});') bt('(function(i) {return i;})();', '(function(i) {\n return i;\n})();') bt( "test( /*Argument 1*/ {\n" + " 'Value1': '1'\n" + "}, /*Argument 2\n" + " */ {\n" + " 'Value2': '2'\n" + "});", # expected "test( /*Argument 1*/ {\n" + " 'Value1': '1'\n" + " },\n" + " /*Argument 2\n" + " */\n" + " {\n" + " 'Value2': '2'\n" + " });") bt( "test(\n" + "/*Argument 1*/ {\n" + " 'Value1': '1'\n" + "},\n" + "/*Argument 2\n" + " */ {\n" + " 'Value2': '2'\n" + "});", # expected "test(\n" + " /*Argument 1*/\n" + " {\n" + " 'Value1': '1'\n" + " },\n" + " /*Argument 2\n" + " */\n" + " {\n" + " 'Value2': '2'\n" + " });") bt( "test( /*Argument 1*/\n" + "{\n" + " 'Value1': '1'\n" + "}, /*Argument 2\n" + " */\n" + "{\n" + " 'Value2': '2'\n" + "});", # expected "test( /*Argument 1*/ {\n" + " 'Value1': '1'\n" + " },\n" + " /*Argument 2\n" + " */\n" + " {\n" + " 'Value2': '2'\n" + " });") self.options.brace_style = "end-expand" bt('//case 1\nif (a == 1) {}\n//case 2\nelse if (a == 2) {}') bt('if(1){2}else{3}', "if (1) {\n 2\n}\nelse {\n 3\n}") bt('try{a();}catch(b){c();}catch(d){}finally{e();}', "try {\n a();\n}\ncatch (b) {\n c();\n}\ncatch (d) {}\nfinally {\n e();\n}") bt('if(a){b();}else if(c) foo();', "if (a) {\n b();\n}\nelse if (c) foo();") bt("if (a) {\n// comment\n}else{\n// comment\n}", "if (a) {\n // comment\n}\nelse {\n // comment\n}") # if/else statement with empty body bt('if (x) {y} else { if (x) {y}}', 'if (x) {\n y\n}\nelse {\n if (x) {\n y\n }\n}') bt('if (a)\n{\nb;\n}\nelse\n{\nc;\n}', 'if (a) {\n b;\n}\nelse {\n c;\n}') test_fragment(' /*\n* xx\n*/\n// xx\nif (foo) {\n bar();\n}', ' /*\n * xx\n */\n // xx\n if (foo) {\n bar();\n }') bt('if (foo) {}\nelse /regex/.test();') test_fragment('if (foo) {', 'if (foo) {') test_fragment('foo {', 'foo {') test_fragment('return {', 'return {') # return needs the brace. test_fragment('return /* inline */ {', 'return /* inline */ {') test_fragment('return;\n{', 'return;\n{') bt("throw {}") bt("throw {\n foo;\n}") bt('var foo = {}') bt('function x() {\n foo();\n}zzz', 'function x() {\n foo();\n}\nzzz') test_fragment('a: do {} while (); xxx', 'a: do {} while ();\nxxx') bt('{a: do {} while (); xxx}', '{\n a: do {} while ();xxx\n}') bt('var a = new function() {};') bt('var a = new function a() {};') bt('var a = new function()\n{};', 'var a = new function() {};') bt('var a = new function a()\n{};', 'var a = new function a() {};') bt('var a = new function a()\n {},\n b = new function b()\n {};', 'var a = new function a() {},\n b = new function b() {};') bt("foo({\n 'a': 1\n},\n10);", "foo({\n 'a': 1\n },\n 10);") bt('(["foo","bar"]).each(function(i) {return i;});', '(["foo", "bar"]).each(function(i) {\n return i;\n});') bt('(function(i) {return i;})();', '(function(i) {\n return i;\n})();') bt( "test( /*Argument 1*/ {\n" + " 'Value1': '1'\n" + "}, /*Argument 2\n" + " */ {\n" + " 'Value2': '2'\n" + "});", # expected "test( /*Argument 1*/ {\n" + " 'Value1': '1'\n" + " },\n" + " /*Argument 2\n" + " */\n" + " {\n" + " 'Value2': '2'\n" + " });") bt( "test(\n" + "/*Argument 1*/ {\n" + " 'Value1': '1'\n" + "},\n" + "/*Argument 2\n" + " */ {\n" + " 'Value2': '2'\n" + "});", # expected "test(\n" + " /*Argument 1*/\n" + " {\n" + " 'Value1': '1'\n" + " },\n" + " /*Argument 2\n" + " */\n" + " {\n" + " 'Value2': '2'\n" + " });") bt( "test( /*Argument 1*/\n" + "{\n" + " 'Value1': '1'\n" + "}, /*Argument 2\n" + " */\n" + "{\n" + " 'Value2': '2'\n" + "});", # expected "test( /*Argument 1*/ {\n" + " 'Value1': '1'\n" + " },\n" + " /*Argument 2\n" + " */\n" + " {\n" + " 'Value2': '2'\n" + " });") self.options.brace_style = 'none' bt('//case 1\nif (a == 1)\n{}\n//case 2\nelse if (a == 2)\n{}') bt('if(1){2}else{3}', "if (1) {\n 2\n} else {\n 3\n}") bt('try{a();}catch(b){c();}catch(d){}finally{e();}', "try {\n a();\n} catch (b) {\n c();\n} catch (d) {} finally {\n e();\n}") bt('if(a){b();}else if(c) foo();', "if (a) {\n b();\n} else if (c) foo();") bt("if (a) {\n// comment\n}else{\n// comment\n}", "if (a) {\n // comment\n} else {\n // comment\n}") # if/else statement with empty body bt('if (x) {y} else { if (x) {y}}', 'if (x) {\n y\n} else {\n if (x) {\n y\n }\n}') bt('if (a)\n{\nb;\n}\nelse\n{\nc;\n}', 'if (a)\n{\n b;\n}\nelse\n{\n c;\n}') test_fragment(' /*\n* xx\n*/\n// xx\nif (foo) {\n bar();\n}', ' /*\n * xx\n */\n // xx\n if (foo) {\n bar();\n }') bt('if (foo)\n{}\nelse /regex/.test();') test_fragment('if (foo) {') test_fragment('foo {') test_fragment('return {') # return needs the brace. test_fragment('return /* inline */ {') test_fragment('return;\n{') bt("throw {}") bt("throw {\n foo;\n}") bt('var foo = {}') bt('function x() {\n foo();\n}zzz', 'function x() {\n foo();\n}\nzzz') test_fragment('a: do {} while (); xxx', 'a: do {} while ();\nxxx') bt('{a: do {} while (); xxx}', '{\n a: do {} while ();xxx\n}') bt('var a = new function() {};') bt('var a = new function a() {};') bt('var a = new function()\n{};', 'var a = new function() {};') bt('var a = new function a()\n{};') bt('var a = new function a()\n {},\n b = new function b()\n {};') bt("foo({\n 'a': 1\n},\n10);", "foo({\n 'a': 1\n },\n 10);") bt('(["foo","bar"]).each(function(i) {return i;});', '(["foo", "bar"]).each(function(i) {\n return i;\n});') bt('(function(i) {return i;})();', '(function(i) {\n return i;\n})();') bt( "test( /*Argument 1*/ {\n" + " 'Value1': '1'\n" + "}, /*Argument 2\n" + " */ {\n" + " 'Value2': '2'\n" + "});", # expected "test( /*Argument 1*/ {\n" + " 'Value1': '1'\n" + " },\n" + " /*Argument 2\n" + " */\n" + " {\n" + " 'Value2': '2'\n" + " });") bt( "test(\n" + "/*Argument 1*/ {\n" + " 'Value1': '1'\n" + "},\n" + "/*Argument 2\n" + " */ {\n" + " 'Value2': '2'\n" + "});", # expected "test(\n" + " /*Argument 1*/\n" + " {\n" + " 'Value1': '1'\n" + " },\n" + " /*Argument 2\n" + " */\n" + " {\n" + " 'Value2': '2'\n" + " });") bt( "test( /*Argument 1*/\n" + "{\n" + " 'Value1': '1'\n" + "}, /*Argument 2\n" + " */\n" + "{\n" + " 'Value2': '2'\n" + "});", # expected "test( /*Argument 1*/\n" + " {\n" + " 'Value1': '1'\n" + " },\n" + " /*Argument 2\n" + " */\n" + " {\n" + " 'Value2': '2'\n" + " });") # END tests for brace position self.reset_options() #============================================================ self.options.preserve_newlines = True bt("var a = 'foo' +\n 'bar';") bt('"foo""bar""baz"', '"foo"\n"bar"\n"baz"') bt("'foo''bar''baz'", "'foo'\n'bar'\n'baz'") bt("{\n get foo() {}\n}") bt("{\n var a = get\n foo();\n}") bt("{\n set foo() {}\n}") bt("{\n var a = set\n foo();\n}") bt("var x = {\n get function()\n}") bt("var x = {\n set function()\n}") # According to my current research get/set have no special meaning outside of an object literal bt("var x = set\n\na() {}", "var x = set\n\na() {}") bt("var x = set\n\nfunction() {}", "var x = set\n\nfunction() {}") bt('for () /abc/.test()') bt('if (k) /aaa/m.test(v) && l();') bt('switch (true) {\n case /swf/i.test(foo):\n bar();\n}') bt('createdAt = {\n type: Date,\n default: Date.now\n}') bt('switch (createdAt) {\n case a:\n Date,\n default:\n Date.now\n}') self.reset_options() #============================================================ def decodesto(self, input, expectation=None): if expectation is None: expectation = input self.assertMultiLineEqual( jsbeautifier.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 is None: self.assertMultiLineEqual( jsbeautifier.beautify(expectation, self.options), expectation) if self.options is None or not isinstance(self.options, (dict, tuple)): # Everywhere we do newlines, they should be replaced with opts.eol self.options.eol = '\r\\n' expectation = expectation.replace('\n', '\r\n') self.options.disabled = True self.assertMultiLineEqual( jsbeautifier.beautify(input, self.options), input or '') self.assertMultiLineEqual( jsbeautifier.beautify('\n\n' + expectation, self.options), '\n\n' + expectation) self.options.disabled = False; self.assertMultiLineEqual( jsbeautifier.beautify(input, self.options), expectation) if input and input.find('\n') != -1: input = input.replace('\n', '\r\n') self.assertMultiLineEqual( jsbeautifier.beautify(input, self.options), expectation) # Ensure support for auto eol detection self.options.eol = 'auto' self.assertMultiLineEqual( jsbeautifier.beautify(input, self.options), expectation) self.options.eol = '\n' def wrap(self, text): return self.wrapregex.sub(' \\1', text) def bt(self, input, expectation=None): if expectation is None: expectation = input self.decodesto(input, expectation) # If we set raw, input should be unchanged self.options.test_output_raw = True if self.options.end_with_newline: self.decodesto(input, input) self.options.test_output_raw = False current_indent_size = None if self.options.js and self.options.js['indent_size']: current_indent_size = self.options.js['indent_size'] if not current_indent_size: current_indent_size = self.options.indent_size if current_indent_size == 4 and input: wrapped_input = '{\n%s\n foo = bar;\n}' % self.wrap(input) wrapped_expect = '{\n%s\n foo = bar;\n}' % self.wrap(expectation) self.decodesto(wrapped_input, wrapped_expect) # If we set raw, input should be unchanged self.options.test_output_raw = True if self.options.end_with_newline: self.decodesto(wrapped_input, wrapped_input) self.options.test_output_raw = False if __name__ == '__main__': unittest.main() python-jsbeautifier-1.15.3/jsbeautifier/tests/testindentation.py000066400000000000000000000026071475627451400252240ustar00rootroot00000000000000import 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() python-jsbeautifier-1.15.3/jsbeautifier/unpackers/000077500000000000000000000000001475627451400222625ustar00rootroot00000000000000python-jsbeautifier-1.15.3/jsbeautifier/unpackers/__init__.py000066400000000000000000000044211475627451400243740ustar00rootroot00000000000000# # General code for JSBeautifier unpackers infrastructure. See README.specs # written by Stefano Sanfilippo # """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 python-jsbeautifier-1.15.3/jsbeautifier/unpackers/evalbased.py000066400000000000000000000022251475627451400245630ustar00rootroot00000000000000# # Unpacker for eval() based packers, a part of javascript beautifier # by Einar Lielmanis # # written by Stefano Sanfilippo # # 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 python-jsbeautifier-1.15.3/jsbeautifier/unpackers/javascriptobfuscator.py000066400000000000000000000033761475627451400271030ustar00rootroot00000000000000# # simple unpacker/deobfuscator for scripts messed up with # javascriptobfuscator.com # # written by Einar Lielmanis # rewritten in Python by Stefano Sanfilippo # # 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 python-jsbeautifier-1.15.3/jsbeautifier/unpackers/myobfuscate.py000066400000000000000000000053121475627451400251560ustar00rootroot00000000000000# # deobfuscator for scripts messed up with myobfuscate.com # by Einar Lielmanis # # written by Stefano Sanfilippo # # 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\='