diff --git a/bundles/javascript.tmbundle/Commands/Copy as Bookmarklet to Clipboard.tmCommand b/bundles/javascript.tmbundle/Commands/Copy as Bookmarklet to Clipboard.tmCommand new file mode 100644 index 000000000..7410fbf51 --- /dev/null +++ b/bundles/javascript.tmbundle/Commands/Copy as Bookmarklet to Clipboard.tmCommand @@ -0,0 +1,54 @@ + + + + + beforeRunningCommand + nop + command + #!/usr/bin/env perl +# +# Written by John Gruber, taken with permission from: +# http://daringfireball.net/2007/03/javascript_bookmarklet_builder + +use strict; +use warnings; +use URI::Escape qw(uri_escape_utf8); +use open IO => ":utf8", # UTF8 by default + ":std"; # Apply to STDIN/STDOUT/STDERR + +my $src = do { local $/; <> }; + +# Zap the first line if there's already a bookmarklet comment: +$src =~ s{^// ?javascript:.+\n}{}; +my $bookmarklet = $src; + +$bookmarklet =~ s{^\s*//.+\n}{}gm; # Kill comments. +$bookmarklet =~ s{\t}{ }gm; # Tabs to spaces +$bookmarklet =~ s{ +}{ }gm; # Space runs to one space +$bookmarklet =~ s{^\s+}{}gm; # Kill line-leading whitespace +$bookmarklet =~ s{\s+$}{}gm; # Kill line-ending whitespace +$bookmarklet =~ s{\n}{}gm; # Kill newlines + +# Escape single- and double-quotes, spaces, control chars, unicode: +$bookmarklet = "javascript:" . + uri_escape_utf8($bookmarklet, qq('" \x00-\x1f\x7f-\xff)); + +print "// $bookmarklet\n" . $src; + +# Put bookmarklet on clipboard: +`/bin/echo -n '$bookmarklet' | /usr/bin/pbcopy`; + + input + selection + keyEquivalent + ^H + name + Copy as Bookmarklet to Clipboard + output + replaceSelectedText + scope + source.js + uuid + 20E61C43-B81F-4FB9-9362-BFFE668EB9C9 + + diff --git a/bundles/javascript.tmbundle/Commands/Documentation for Word.plist b/bundles/javascript.tmbundle/Commands/Documentation for Word.plist new file mode 100644 index 000000000..d9d98f993 --- /dev/null +++ b/bundles/javascript.tmbundle/Commands/Documentation for Word.plist @@ -0,0 +1,30 @@ + + + + + beforeRunningCommand + nop + command + # index created using: curl -s 'http://devguru.com/technologies/javascript/index.asp'|grep -o '<a href="[0-9]*.asp">[a-z][a-zA-Z]*</a>'|perl -pe 's/<a href="([^"]*)">([^<]*)<\/a>/$2\t$1/'|sort|uniq|gzip >dev_guru_index.gz + +ref=$(zgrep -w "^${TM_SELECTED_TEXT:-$TM_CURRENT_WORD}" "$TM_BUNDLE_SUPPORT/dev_guru_index.gz"|cut -f2) + +[[ -n "$ref" ]] && exit_show_html "<meta http-equiv='Refresh' content='0;URL=http://devguru.com/technologies/javascript/$ref'>" + +echo "No documentation found." + fallbackInput + word + input + selection + keyEquivalent + ^h + name + Documentation for Word / Selection + output + showAsTooltip + scope + source.js + uuid + B4874A14-2491-465A-A349-61E4EBCF4700 + + diff --git a/bundles/javascript.tmbundle/Commands/New Function.tmCommand b/bundles/javascript.tmbundle/Commands/New Function.tmCommand new file mode 100644 index 000000000..064d36410 --- /dev/null +++ b/bundles/javascript.tmbundle/Commands/New Function.tmCommand @@ -0,0 +1,28 @@ + + + + + beforeRunningCommand + nop + command + cat <<SNIPPET +function ${TM_SELECTED_TEXT:-$TM_CURRENT_WORD}(\${1:args}) { + \$0 +} +SNIPPET + fallbackInput + word + input + selection + keyEquivalent + $ + name + New Function + output + insertAsSnippet + scope + source.js + uuid + 73951799-AC15-40A6-81DB-EC051AB4A033 + + diff --git a/bundles/javascript.tmbundle/Commands/New Method.tmCommand b/bundles/javascript.tmbundle/Commands/New Method.tmCommand new file mode 100644 index 000000000..2e02018ee --- /dev/null +++ b/bundles/javascript.tmbundle/Commands/New Method.tmCommand @@ -0,0 +1,28 @@ + + + + + beforeRunningCommand + nop + command + cat <<SNIPPET +${TM_SELECTED_TEXT:-$TM_CURRENT_WORD}: function(\${1:args}) { + \$0 +}\${2:,} +SNIPPET + fallbackInput + word + input + selection + keyEquivalent + ~$ + name + New Method + output + insertAsSnippet + scope + source.js + uuid + 1717B5AE-209B-4548-9155-9E88A7230C1C + + diff --git a/bundles/javascript.tmbundle/Commands/Reformat Document : Selection.tmCommand b/bundles/javascript.tmbundle/Commands/Reformat Document : Selection.tmCommand new file mode 100644 index 000000000..644f3ba63 --- /dev/null +++ b/bundles/javascript.tmbundle/Commands/Reformat Document : Selection.tmCommand @@ -0,0 +1,40 @@ + + + + + beforeRunningCommand + nop + command + #!/usr/bin/env python + +import os +import sys + +sys.path.append(os.path.join(os.environ["TM_BUNDLE_SUPPORT"], "lib")) + +import jsbeautifier + +opts = jsbeautifier.default_options() + +if os.environ["TM_SOFT_TABS"] == 'NO': + opts.indent_size = 1 + opts.indent_char = '\t' +else: + opts.indent_size = int(os.environ["TM_TAB_SIZE"]) + +print jsbeautifier.beautify_file('-', opts) + + input + selection + keyEquivalent + ^H + name + Reformat Document / Selection + output + replaceSelectedText + scope + source.js + uuid + 36EC03E9-EFF4-479A-AB90-8DFA16800642 + + diff --git a/bundles/javascript.tmbundle/Preferences/Comments.tmPreferences b/bundles/javascript.tmbundle/Preferences/Comments.tmPreferences new file mode 100644 index 000000000..2b7a18388 --- /dev/null +++ b/bundles/javascript.tmbundle/Preferences/Comments.tmPreferences @@ -0,0 +1,36 @@ + + + + + name + Comments + scope + source.js + settings + + shellVariables + + + name + TM_COMMENT_START + value + // + + + name + TM_COMMENT_START_2 + value + /* + + + name + TM_COMMENT_END_2 + value + */ + + + + uuid + A67A8BD9-A951-406F-9175-018DD4B52FD1 + + diff --git a/bundles/javascript.tmbundle/Preferences/JavaScript Indent.tmPreferences b/bundles/javascript.tmbundle/Preferences/JavaScript Indent.tmPreferences new file mode 100644 index 000000000..b6b6ffc54 --- /dev/null +++ b/bundles/javascript.tmbundle/Preferences/JavaScript Indent.tmPreferences @@ -0,0 +1,19 @@ + + + + + name + JavaScript Indent + scope + source.js + settings + + decreaseIndentPattern + ^(.*\*/)?\s*(\}|\))([^{]*\{)?([;,]?\s*|\.[^{]*|\s*\)[;\s]*)$ + increaseIndentPattern + ^.*(\{[^}"']*|\([^)"']*)$ + + uuid + BC062860-3346-4D3B-8421-C5543F83D11F + + diff --git a/bundles/javascript.tmbundle/Preferences/Symbol List Banned.tmPreferences b/bundles/javascript.tmbundle/Preferences/Symbol List Banned.tmPreferences new file mode 100644 index 000000000..c51de2a03 --- /dev/null +++ b/bundles/javascript.tmbundle/Preferences/Symbol List Banned.tmPreferences @@ -0,0 +1,17 @@ + + + + + name + Symbol List Banned + scope + source.js meta.property.function entity.name.function + settings + + showInSymbolList + 0 + + uuid + 834BC727-6B31-4073-A161-4823227219EF + + diff --git a/bundles/javascript.tmbundle/Preferences/Symbol List Class.tmPreferences b/bundles/javascript.tmbundle/Preferences/Symbol List Class.tmPreferences new file mode 100644 index 000000000..50d8a7fcf --- /dev/null +++ b/bundles/javascript.tmbundle/Preferences/Symbol List Class.tmPreferences @@ -0,0 +1,21 @@ + + + + + name + Symbol List Class + scope + source.js entity.name.type.class + settings + + showInSymbolList + 1 + symbolTransformation + + s/^/• /g; + + + uuid + 3CEA49B2-A5C5-405C-82E2-B8B668877C37 + + diff --git a/bundles/javascript.tmbundle/Preferences/Symbol List Instance.tmPreferences b/bundles/javascript.tmbundle/Preferences/Symbol List Instance.tmPreferences new file mode 100644 index 000000000..55ebd5fa9 --- /dev/null +++ b/bundles/javascript.tmbundle/Preferences/Symbol List Instance.tmPreferences @@ -0,0 +1,21 @@ + + + + + name + Symbol List Instance + scope + source.js entity.name.instance + settings + + showInSymbolList + 1 + symbolTransformation + + s/^/\t/g; + + + uuid + E6EB7CC8-04E8-43A9-93B2-BC9EF5BA862B + + diff --git a/bundles/javascript.tmbundle/Preferences/Symbol List Sub 1.tmPreferences b/bundles/javascript.tmbundle/Preferences/Symbol List Sub 1.tmPreferences new file mode 100644 index 000000000..28acc1392 --- /dev/null +++ b/bundles/javascript.tmbundle/Preferences/Symbol List Sub 1.tmPreferences @@ -0,0 +1,21 @@ + + + + + name + Symbol List Sub 1 + scope + source.js object.property.function -(meta.group meta.group) + settings + + showInSymbolList + 1 + symbolTransformation + + s/^/ :/g; + + + uuid + 73557394-4F0F-4DD3-8029-EEE8201AC7F5 + + diff --git a/bundles/javascript.tmbundle/Preferences/Symbol List Sub 2.tmPreferences b/bundles/javascript.tmbundle/Preferences/Symbol List Sub 2.tmPreferences new file mode 100644 index 000000000..be4beb83f --- /dev/null +++ b/bundles/javascript.tmbundle/Preferences/Symbol List Sub 2.tmPreferences @@ -0,0 +1,21 @@ + + + + + name + Symbol List Sub 2 + scope + source.js meta.group meta.group object.property.function + settings + + showInSymbolList + 1 + symbolTransformation + + s/^/  :/g; + + + uuid + 51841DDB-C2A4-461C-A8AB-6C124AD50EAE + + diff --git a/bundles/javascript.tmbundle/Snippets/Get Elements.tmSnippet b/bundles/javascript.tmbundle/Snippets/Get Elements.tmSnippet new file mode 100644 index 000000000..3031d9f12 --- /dev/null +++ b/bundles/javascript.tmbundle/Snippets/Get Elements.tmSnippet @@ -0,0 +1,16 @@ + + + + + content + getElement${1/(T)|.*/(?1:s)/}By${1:T}${1/(T)|(I)|.*/(?1:agName)(?2:d)/}('$2') + name + Get Elements + scope + source.js + tabTrigger + get + uuid + 9E0E3BCC-7F20-4D6B-891D-A44D6EC56E31 + + diff --git a/bundles/javascript.tmbundle/Snippets/Object Method String.tmSnippet b/bundles/javascript.tmbundle/Snippets/Object Method String.tmSnippet new file mode 100644 index 000000000..8b7ec64cd --- /dev/null +++ b/bundles/javascript.tmbundle/Snippets/Object Method String.tmSnippet @@ -0,0 +1,18 @@ + + + + + content + '${1:${2:#thing}:${3:click}}': function(element){ + $0 +}${10:,} + name + Object Method String + scope + source.js + tabTrigger + '':f + uuid + 7B9AEFCC-B450-416D-8527-430FE2A08568 + + diff --git a/bundles/javascript.tmbundle/Snippets/Object Method.tmSnippet b/bundles/javascript.tmbundle/Snippets/Object Method.tmSnippet new file mode 100644 index 000000000..5ee0d08f3 --- /dev/null +++ b/bundles/javascript.tmbundle/Snippets/Object Method.tmSnippet @@ -0,0 +1,18 @@ + + + + + content + ${1:method_name}: function(${3:attribute}){ + $0 +}${10:,} + name + Object Method + scope + source.js + tabTrigger + :f + uuid + 77065D69-742A-4FF0-9A41-AD211DFBE72F + + diff --git a/bundles/javascript.tmbundle/Snippets/Object Value JS.tmSnippet b/bundles/javascript.tmbundle/Snippets/Object Value JS.tmSnippet new file mode 100644 index 000000000..b74121730 --- /dev/null +++ b/bundles/javascript.tmbundle/Snippets/Object Value JS.tmSnippet @@ -0,0 +1,16 @@ + + + + + content + ${1:value_name}:${0:value}, + name + Object Value JS + scope + source.js + tabTrigger + :, + uuid + AD506BEC-B33C-4168-A900-0A4D386A4B05 + + diff --git "a/bundles/javascript.tmbundle/Snippets/Object key — key: \"value\".tmSnippet" "b/bundles/javascript.tmbundle/Snippets/Object key — key: \"value\".tmSnippet" new file mode 100644 index 000000000..12bc4e1da --- /dev/null +++ "b/bundles/javascript.tmbundle/Snippets/Object key — key: \"value\".tmSnippet" @@ -0,0 +1,18 @@ + + + + + content + ${1:key}: ${2:"${3:value}"}${4:, } + keyEquivalent + ~: + name + Object key — key: "value" + scope + source.js + tabTrigger + : + uuid + DC8B46FB-8ADA-45EA-8F36-94C807A0D302 + + diff --git a/bundles/javascript.tmbundle/Snippets/Prototype (proto).plist b/bundles/javascript.tmbundle/Snippets/Prototype (proto).plist new file mode 100644 index 000000000..252c27906 --- /dev/null +++ b/bundles/javascript.tmbundle/Snippets/Prototype (proto).plist @@ -0,0 +1,19 @@ + + + + + content + ${1:class_name}.prototype.${2:method_name} = function(${3:first_argument}) { + ${0:// body...} +}; + + name + Prototype + scope + source.js + tabTrigger + proto + uuid + 2F96136B-0193-42F5-90FC-B6F456A3AD77 + + diff --git a/bundles/javascript.tmbundle/Snippets/for (…) {…} (faster).tmSnippet b/bundles/javascript.tmbundle/Snippets/for (…) {…} (faster).tmSnippet new file mode 100644 index 000000000..34e6b712e --- /dev/null +++ b/bundles/javascript.tmbundle/Snippets/for (…) {…} (faster).tmSnippet @@ -0,0 +1,18 @@ + + + + + content + for (var ${20:i} = ${1:Things}.length - 1; ${20:i} >= 0; ${20:i}--){ + ${100:${1:Things}[${20:i}]}$0 +}; + name + for (…) {…} (Improved Native For-Loop) + scope + source.js + tabTrigger + for + uuid + C207B7C3-5597-4873-8AAD-C46FB8842AF2 + + diff --git a/bundles/javascript.tmbundle/Snippets/for (…) {…}.tmSnippet b/bundles/javascript.tmbundle/Snippets/for (…) {…}.tmSnippet new file mode 100644 index 000000000..d41b04768 --- /dev/null +++ b/bundles/javascript.tmbundle/Snippets/for (…) {…}.tmSnippet @@ -0,0 +1,18 @@ + + + + + content + for (var ${20:i}=0; ${20:i} < ${1:Things}.length; ${20:i}++) { + ${100:${1:Things}[${20:i}]}$0 +}; + name + for (…) {…} + scope + source.js + tabTrigger + for + uuid + 011C4681-FBEC-4891-9326-3DECFCDED6D6 + + diff --git a/bundles/javascript.tmbundle/Snippets/function (fun).plist b/bundles/javascript.tmbundle/Snippets/function (fun).plist new file mode 100644 index 000000000..0ca6d4eb8 --- /dev/null +++ b/bundles/javascript.tmbundle/Snippets/function (fun).plist @@ -0,0 +1,18 @@ + + + + + content + function ${1:function_name} (${2:argument}) { + ${0:// body...} +} + name + Function + scope + source.js + tabTrigger + fun + uuid + F0E4FB6A-4878-48C6-A777-62438DF1E14F + + diff --git a/bundles/javascript.tmbundle/Snippets/function.tmSnippet b/bundles/javascript.tmbundle/Snippets/function.tmSnippet new file mode 100644 index 000000000..8a3cf1e4e --- /dev/null +++ b/bundles/javascript.tmbundle/Snippets/function.tmSnippet @@ -0,0 +1,16 @@ + + + + + content + function($1) {${0:$TM_SELECTED_TEXT}}; + name + Anonymous Function + scope + source.js + tabTrigger + f + uuid + 4C6EDB43-3E2E-411B-A016-13C135C59833 + + diff --git a/bundles/javascript.tmbundle/Snippets/if ___ else.tmSnippet b/bundles/javascript.tmbundle/Snippets/if ___ else.tmSnippet new file mode 100644 index 000000000..421f45e41 --- /dev/null +++ b/bundles/javascript.tmbundle/Snippets/if ___ else.tmSnippet @@ -0,0 +1,16 @@ + + + + + content + if (${1:true}) {${0:$TM_SELECTED_TEXT}} else{}; + name + if … else + scope + source.js + tabTrigger + ife + uuid + 31964029-9D71-4ADC-8213-DFE5C4E222B3 + + diff --git a/bundles/javascript.tmbundle/Snippets/if.tmSnippet b/bundles/javascript.tmbundle/Snippets/if.tmSnippet new file mode 100644 index 000000000..dbfb7e73f --- /dev/null +++ b/bundles/javascript.tmbundle/Snippets/if.tmSnippet @@ -0,0 +1,16 @@ + + + + + content + if (${1:true}) {${0:$TM_SELECTED_TEXT}}; + name + if + scope + source.js + tabTrigger + if + uuid + F19F3732-39A7-48EC-A72B-A8F477A01795 + + diff --git a/bundles/javascript.tmbundle/Snippets/setTimeout function.tmSnippet b/bundles/javascript.tmbundle/Snippets/setTimeout function.tmSnippet new file mode 100644 index 000000000..5d9894e38 --- /dev/null +++ b/bundles/javascript.tmbundle/Snippets/setTimeout function.tmSnippet @@ -0,0 +1,16 @@ + + + + + content + setTimeout(function() {$0}${2:}, ${1:10}); + name + setTimeout function + scope + source.js + tabTrigger + timeout + uuid + 009A3E6C-FE3F-4A18-8759-2DC31F17BBE2 + + diff --git a/bundles/javascript.tmbundle/Support/dev_guru_index.gz b/bundles/javascript.tmbundle/Support/dev_guru_index.gz new file mode 100644 index 000000000..b657fbc5e Binary files /dev/null and b/bundles/javascript.tmbundle/Support/dev_guru_index.gz differ diff --git a/bundles/javascript.tmbundle/Support/lib/jsbeautifier-license.txt b/bundles/javascript.tmbundle/Support/lib/jsbeautifier-license.txt new file mode 100755 index 000000000..1857514a6 --- /dev/null +++ b/bundles/javascript.tmbundle/Support/lib/jsbeautifier-license.txt @@ -0,0 +1,22 @@ +Copyright (c) 2009 - 2011, Einar Lielmanis + +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. diff --git a/bundles/javascript.tmbundle/Support/lib/jsbeautifier.py b/bundles/javascript.tmbundle/Support/lib/jsbeautifier.py new file mode 100755 index 000000000..492658f84 --- /dev/null +++ b/bundles/javascript.tmbundle/Support/lib/jsbeautifier.py @@ -0,0 +1,1080 @@ +#!/usr/bin/env python + +import sys +import getopt +import re + +# +# Originally written by Einar Lielmanis et al., +# Conversion to python by Einar Lielmanis, einar@jsbeautifier.org, +# MIT licence, enjoy. +# +# 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) + + +class BeautifierOptions: + def __init__(self): + self.indent_size = 4 + self.indent_char = ' ' + self.preserve_newlines = True + self.max_preserve_newlines = 10. + self.jslint_happy = False + self.brace_style = 'collapse' + self.keep_array_indentation = False + self.indent_level = 0 + + + + def __repr__(self): + return \ +"""indent_size = %d +indent_char = [%s] +preserve_newlines = %s +max_preserve_newlines = %d +jslint_happy = %s +brace_style = %s +keep_array_indentation = %s +indent_level = %d +""" % ( self.indent_size, + self.indent_char, + self.preserve_newlines, + self.max_preserve_newlines, + self.jslint_happy, + self.brace_style, + self.keep_array_indentation, + self.indent_level) + + +class BeautifierFlags: + def __init__(self, mode): + self.previous_mode = 'BLOCK' + self.mode = mode + self.var_line = False + self.var_line_tainted = False + self.var_line_reindented = False + self.in_html_comment = False + self.if_line = False + self.in_case = False + self.eat_next_space = False + self.indentation_baseline = -1 + self.indentation_level = 0 + self.ternary_depth = 0 + + +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() ): + + if file_name == '-': # stdin + f = sys.stdin + else: + f = open(file_name) + + b = Beautifier() + return b.beautify(''.join(f.readlines()), opts) + + +def usage(): + + print("""Javascript beautifier (http://jsbeautifier.org/) + +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). + -d, --disable-preserve-newlines do not preserve existing line breaks. + -j, --jslint-happy more jslint-compatible output + -b, --brace-style=collapse brace style (collapse, expand, end-expand) + -k, --keep-array-indentation keep array indentation. + +Rarely needed options: + + -l, --indent-level=NUMBER initial indentation level. (default 0). + + -h, --help, --usage prints this help statement. + +"""); + + + + + + +class Beautifier: + + def __init__(self, opts = default_options() ): + + self.opts = opts + self.blank_state() + + def blank_state(self): + + # internal flags + self.flags = BeautifierFlags('BLOCK') + self.flag_store = [] + self.wanted_newline = False + self.just_added_newline = False + self.do_block_just_closed = False + + + self.indent_string = self.opts.indent_char * self.opts.indent_size + self.last_word = '' # last TK_WORD seen + self.last_type = 'TK_START_EXPR' # last token type + self.last_text = '' # last token text + self.last_last_text = '' # pre-last token text + + self.input = None + self.output = [] # formatted javascript gets built here + + self.whitespace = ["\n", "\r", "\t", " "] + self.wordchar = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$' + self.digits = '0123456789' + self.punct = '+ - * / % & ++ -- = += -= *= /= %= == === != !== > < >= <= >> << >>> >>>= >>= <<= && &= | || ! !! , : ? ^ ^= |= ::'.split(' '); + + + # Words which always should start on a new line + self.line_starters = 'continue,try,throw,return,var,if,switch,case,default,for,while,break,function'.split(',') + self.set_mode('BLOCK') + + global parser_pos + parser_pos = 0 + + + def beautify(self, s, opts = None ): + + if opts != None: + self.opts = opts + + + if self.opts.brace_style not in ['expand', 'collapse', 'end-expand']: + raise(Exception('opts.brace_style must be "expand", "collapse" or "end-expand".')) + + self.blank_state() + + self.input = s + + parser_pos = 0 + while True: + token_text, token_type = self.get_next_token() + #print (token_text, token_type, self.flags.mode) + if token_type == 'TK_EOF': + break + + handlers = { + 'TK_START_EXPR': self.handle_start_expr, + 'TK_END_EXPR': self.handle_end_expr, + 'TK_START_BLOCK': self.handle_start_block, + 'TK_END_BLOCK': self.handle_end_block, + 'TK_WORD': self.handle_word, + 'TK_SEMICOLON': self.handle_semicolon, + 'TK_STRING': self.handle_string, + 'TK_EQUALS': self.handle_equals, + 'TK_OPERATOR': self.handle_operator, + 'TK_BLOCK_COMMENT': self.handle_block_comment, + 'TK_INLINE_COMMENT': self.handle_inline_comment, + 'TK_COMMENT': self.handle_comment, + 'TK_UNKNOWN': self.handle_unknown, + } + + handlers[token_type](token_text) + + self.last_last_text = self.last_text + self.last_type = token_type + self.last_text = token_text + + return re.sub('[\n ]+$', '', ''.join(self.output)) + + + def trim_output(self, eat_newlines = False): + while len(self.output) \ + and ( + self.output[-1] == ' '\ + or self.output[-1] == self.indent_string \ + or (eat_newlines and self.output[-1] in ['\n', '\r'])): + self.output.pop() + + + def is_array(self, mode): + return mode in ['[EXPRESSION]', '[INDENDED-EXPRESSION]'] + + + def is_expression(self, mode): + return mode in ['[EXPRESSION]', '[INDENDED-EXPRESSION]', '(EXPRESSION)'] + + + def append_newline(self, ignore_repeated = True): + + self.flags.eat_next_space = False; + + if self.opts.keep_array_indentation and self.is_array(self.flags.mode): + return + + self.flags.if_line = False; + self.trim_output(); + + if len(self.output) == 0: + # no newline on start of file + return + + if self.output[-1] != '\n' or not ignore_repeated: + self.just_added_newline = True + self.output.append('\n') + + for i in range(self.flags.indentation_level): + self.output.append(self.indent_string) + + if self.flags.var_line and self.flags.var_line_reindented: + if self.opts.indent_char == ' ': + # var_line always pushes 4 spaces, so that the variables would be one under another + self.output.append(' ') + else: + self.output.append(self.indent_string) + + + def append(self, s): + if s == ' ': + # make sure only single space gets drawn + if self.flags.eat_next_space: + self.flags.eat_next_space = False + elif len(self.output) and self.output[-1] not in [' ', '\n', self.indent_string]: + self.output.append(' ') + else: + self.just_added_newline = False + self.flags.eat_next_space = False + self.output.append(s) + + + def indent(self): + self.flags.indentation_level = self.flags.indentation_level + 1 + + + def remove_indent(self): + if len(self.output) and self.output[-1] == self.indent_string: + self.output.pop() + + + def set_mode(self, mode): + + prev = BeautifierFlags('BLOCK') + + if self.flags: + self.flag_store.append(self.flags) + prev = self.flags + + self.flags = BeautifierFlags(mode) + + if len(self.flag_store) == 1: + self.flags.indentation_level = self.opts.indent_level + else: + self.flags.indentation_level = prev.indentation_level + if prev.var_line and prev.var_line_reindented: + self.flags.indentation_level = self.flags.indentation_level + 1 + self.flags.previous_mode = prev.mode + + + def restore_mode(self): + self.do_block_just_closed = self.flags.mode == 'DO_BLOCK' + if len(self.flag_store) > 0: + self.flags = self.flag_store.pop() + + + def get_next_token(self): + + global parser_pos + + self.n_newlines = 0 + + if parser_pos >= len(self.input): + return '', 'TK_EOF' + + self.wanted_newline = False; + c = self.input[parser_pos] + parser_pos += 1 + + keep_whitespace = self.opts.keep_array_indentation and self.is_array(self.flags.mode) + + if keep_whitespace: + # slight mess to allow nice preservation of array indentation and reindent that correctly + # first time when we get to the arrays: + # var a = [ + # ....'something' + # we make note of whitespace_count = 4 into flags.indentation_baseline + # so we know that 4 whitespaces in original source match indent_level of reindented source + # + # and afterwards, when we get to + # 'something, + # .......'something else' + # we know that this should be indented to indent_level + (7 - indentation_baseline) spaces + + whitespace_count = 0 + while c in self.whitespace: + if c == '\n': + self.trim_output() + self.output.append('\n') + self.just_added_newline = True + whitespace_count = 0 + elif c == '\t': + whitespace_count += 4 + elif c == '\r': + pass + else: + whitespace_count += 1 + + if parser_pos >= len(self.input): + return '', 'TK_EOF' + + c = self.input[parser_pos] + parser_pos += 1 + + if self.flags.indentation_baseline == -1: + + self.flags.indentation_baseline = whitespace_count + + if self.just_added_newline: + for i in range(self.flags.indentation_level + 1): + self.output.append(self.indent_string) + + if self.flags.indentation_baseline != -1: + for i in range(whitespace_count - self.flags.indentation_baseline): + self.output.append(' ') + + else: # not keep_whitespace + while c in self.whitespace: + if c == '\n': + if self.opts.max_preserve_newlines == 0 or self.opts.max_preserve_newlines > self.n_newlines: + self.n_newlines += 1 + + if parser_pos >= len(self.input): + return '', 'TK_EOF' + + c = self.input[parser_pos] + parser_pos += 1 + + if self.opts.preserve_newlines and self.n_newlines > 1: + for i in range(self.n_newlines): + self.append_newline(i == 0) + self.just_added_newline = True + + self.wanted_newline = self.n_newlines > 0 + + + if c in self.wordchar: + if parser_pos < len(self.input): + while self.input[parser_pos] in self.wordchar: + c = c + self.input[parser_pos] + parser_pos += 1 + if parser_pos == len(self.input): + break + + # small and surprisingly unugly hack for 1E-10 representation + if parser_pos != len(self.input) and self.input[parser_pos] in '+-' \ + and re.match('^[0-9]+[Ee]$', c): + + sign = self.input[parser_pos] + parser_pos += 1 + t = self.get_next_token() + c += sign + t[0] + return c, 'TK_WORD' + + if c == 'in': # in is an operator, need to hack + return c, 'TK_OPERATOR' + + if self.wanted_newline and \ + self.last_type != 'TK_OPERATOR' and\ + self.last_type != 'TK_EQUALS' and\ + not self.flags.if_line and \ + (self.opts.preserve_newlines or self.last_text != 'var'): + self.append_newline() + + return c, 'TK_WORD' + + if c in '([': + return c, 'TK_START_EXPR' + + if c in ')]': + return c, 'TK_END_EXPR' + + if c == '{': + return c, 'TK_START_BLOCK' + + if c == '}': + return c, 'TK_END_BLOCK' + + if c == ';': + return c, 'TK_SEMICOLON' + + if c == '/': + comment = '' + inline_comment = True + comment_mode = 'TK_INLINE_COMMENT' + if self.input[parser_pos] == '*': # peek /* .. */ comment + parser_pos += 1 + if parser_pos < len(self.input): + while not (self.input[parser_pos] == '*' and \ + parser_pos + 1 < len(self.input) and \ + self.input[parser_pos + 1] == '/')\ + and parser_pos < len(self.input): + c = self.input[parser_pos] + comment += c + if c in '\r\n': + comment_mode = 'TK_BLOCK_COMMENT' + parser_pos += 1 + if parser_pos >= len(self.input): + break + parser_pos += 2 + return '/*' + comment + '*/', comment_mode + if self.input[parser_pos] == '/': # peek // comment + comment = c + while self.input[parser_pos] not in '\r\n': + comment += self.input[parser_pos] + parser_pos += 1 + if parser_pos >= len(self.input): + break + parser_pos += 1 + if self.wanted_newline: + self.append_newline() + return comment, 'TK_COMMENT' + + + + if c == "'" or c == '"' or \ + (c == '/' and ((self.last_type == 'TK_WORD' and self.last_text in ['return', 'do']) or \ + (self.last_type in ['TK_COMMENT', 'TK_START_EXPR', 'TK_START_BLOCK', 'TK_END_BLOCK', 'TK_OPERATOR', + 'TK_EQUALS', 'TK_EOF', 'TK_SEMICOLON']))): + sep = c + esc = False + resulting_string = c + in_char_class = False + + if parser_pos < len(self.input): + if sep == '/': + # handle regexp + in_char_class = False + while esc or in_char_class or self.input[parser_pos] != sep: + resulting_string += self.input[parser_pos] + if not esc: + esc = self.input[parser_pos] == '\\' + if self.input[parser_pos] == '[': + in_char_class = True + elif self.input[parser_pos] == ']': + in_char_class = False + else: + esc = False + parser_pos += 1 + if parser_pos >= len(self.input): + # incomplete regex when end-of-file reached + # bail out with what has received so far + return resulting_string, 'TK_STRING' + else: + # handle string + while esc or self.input[parser_pos] != sep: + resulting_string += self.input[parser_pos] + if not esc: + esc = self.input[parser_pos] == '\\' + else: + esc = False + parser_pos += 1 + if parser_pos >= len(self.input): + # incomplete string when end-of-file reached + # bail out with what has received so far + return resulting_string, 'TK_STRING' + + + parser_pos += 1 + resulting_string += sep + if sep == '/': + # regexps may have modifiers /regexp/MOD, so fetch those too + while parser_pos < len(self.input) and self.input[parser_pos] in self.wordchar: + resulting_string += self.input[parser_pos] + parser_pos += 1 + return resulting_string, 'TK_STRING' + + if c == '#': + + # she-bang + if len(self.output) == 0 and len(self.input) > 1 and self.input[parser_pos] == '!': + resulting_string = c + while parser_pos < len(self.input) and c != '\n': + c = self.input[parser_pos] + resulting_string += c + parser_pos += 1 + self.output.append(resulting_string.strip() + "\n") + self.append_newline() + return self.get_next_token() + + + # 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 parser_pos < len(self.input) and self.input[parser_pos] in self.digits: + while True: + c = self.input[parser_pos] + sharp += c + parser_pos += 1 + if parser_pos >= len(self.input) or c == '#' or c == '=': + break + if c == '#' or parser_pos >= len(self.input): + pass + elif self.input[parser_pos] == '[' and self.input[parser_pos + 1] == ']': + sharp += '[]' + parser_pos += 2 + elif self.input[parser_pos] == '{' and self.input[parser_pos + 1] == '}': + sharp += '{}' + parser_pos += 2 + return sharp, 'TK_WORD' + + if c == '<' and self.input[parser_pos - 1 : parser_pos + 3] == '': + self.flags.in_html_comment = False + parser_pos += 2 + if self.wanted_newline: + self.append_newline() + return '-->', 'TK_COMMENT' + + if c in self.punct: + while parser_pos < len(self.input) and c + self.input[parser_pos] in self.punct: + c += self.input[parser_pos] + parser_pos += 1 + if parser_pos >= len(self.input): + break + if c == '=': + return c, 'TK_EQUALS' + else: + return c, 'TK_OPERATOR' + return c, 'TK_UNKNOWN' + + + + def handle_start_expr(self, token_text): + if token_text == '[': + if self.last_type == 'TK_WORD' or self.last_text == ')': + if self.last_text in self.line_starters: + self.append(' ') + self.set_mode('(EXPRESSION)') + self.append(token_text) + return + + if self.flags.mode in ['[EXPRESSION]', '[INDENTED-EXPRESSION]']: + if self.last_last_text == ']' and self.last_text == ',': + # ], [ goes to a new line + if self.flags.mode == '[EXPRESSION]': + self.flags.mode = '[INDENTED-EXPRESSION]' + if not self.opts.keep_array_indentation: + self.indent() + self.set_mode('[EXPRESSION]') + if not self.opts.keep_array_indentation: + self.append_newline() + elif self.last_text == '[': + if self.flags.mode == '[EXPRESSION]': + self.flags.mode = '[INDENTED-EXPRESSION]' + if not self.opts.keep_array_indentation: + self.indent() + self.set_mode('[EXPRESSION]') + + if not self.opts.keep_array_indentation: + self.append_newline() + else: + self.set_mode('[EXPRESSION]') + else: + self.set_mode('[EXPRESSION]') + else: + self.set_mode('(EXPRESSION)') + + + if self.last_text == ';' or self.last_type == 'TK_START_BLOCK': + self.append_newline() + elif self.last_type in ['TK_END_EXPR', 'TK_START_EXPR', 'TK_END_BLOCK'] or self.last_text == '.': + # do nothing on (( and )( and ][ and ]( and .( + pass + elif self.last_type not in ['TK_WORD', 'TK_OPERATOR']: + self.append(' ') + elif self.last_word == 'function' or self.last_word == 'typeof': + # function() vs function (), typeof() vs typeof () + if self.opts.jslint_happy: + self.append(' ') + elif self.last_text in self.line_starters or self.last_text == 'catch': + self.append(' ') + + self.append(token_text) + + + def handle_end_expr(self, token_text): + if token_text == ']': + if self.opts.keep_array_indentation: + if self.last_text == '}': + self.remove_indent() + self.append(token_text) + self.restore_mode() + return + else: + if self.flags.mode == '[INDENTED-EXPRESSION]': + if self.last_text == ']': + self.restore_mode() + self.append_newline() + self.append(token_text) + return + self.restore_mode() + self.append(token_text) + + + def handle_start_block(self, token_text): + if self.last_word == 'do': + self.set_mode('DO_BLOCK') + else: + self.set_mode('BLOCK') + + if self.opts.brace_style == 'expand': + if self.last_type != 'TK_OPERATOR': + if self.last_text in ['return', '=']: + self.append(' ') + else: + self.append_newline(True) + + self.append(token_text) + self.indent() + else: + if self.last_type not in ['TK_OPERATOR', 'TK_START_EXPR']: + if self.last_type == 'TK_START_BLOCK': + self.append_newline() + else: + self.append(' ') + else: + # if TK_OPERATOR or TK_START_EXPR + if self.is_array(self.flags.previous_mode) and self.last_text == ',': + if self.last_last_text == '}': + self.append(' ') + else: + self.append_newline() + self.indent() + self.append(token_text) + + + + + + def handle_end_block(self, token_text): + self.restore_mode() + if self.opts.brace_style == 'expand': + if self.last_text != '{': + self.append_newline() + else: + if self.last_type == 'TK_START_BLOCK': + if self.just_added_newline: + self.remove_indent() + else: + # {} + self.trim_output() + else: + if self.is_array(self.flags.mode) and self.opts.keep_array_indentation: + self.opts.keep_array_indentation = False + self.append_newline() + self.opts.keep_array_indentation = True + else: + self.append_newline() + + self.append(token_text) + + + def handle_word(self, token_text): + if self.do_block_just_closed: + self.append(' ') + self.append(token_text) + self.append(' ') + self.do_block_just_closed = False + return + + if token_text == 'function': + + if self.flags.var_line: + self.flags.var_line_reindented = True + if (self.just_added_newline or self.last_text == ';') and self.last_text != '{': + # make sure there is a nice clean space of at least one blank line + # before a new function definition + have_newlines = self.n_newlines + if not self.just_added_newline: + have_newlines = 0 + if not self.opts.preserve_newlines: + have_newlines = 1 + for i in range(2 - have_newlines): + self.append_newline(False) + + if token_text in ['case', 'default']: + if self.last_text == ':': + self.remove_indent() + else: + self.flags.indentation_level -= 1 + self.append_newline() + self.flags.indentation_level += 1 + self.append(token_text) + self.flags.in_case = True + return + + prefix = 'NONE' + + if self.last_type == 'TK_END_BLOCK': + if token_text not in ['else', 'catch', 'finally']: + prefix = 'NEWLINE' + else: + if self.opts.brace_style in ['expand', 'end-expand']: + prefix = 'NEWLINE' + else: + prefix = 'SPACE' + self.append(' ') + elif self.last_type == 'TK_SEMICOLON' and self.flags.mode in ['BLOCK', 'DO_BLOCK']: + prefix = 'NEWLINE' + elif self.last_type == 'TK_SEMICOLON' and self.is_expression(self.flags.mode): + prefix = 'SPACE' + elif self.last_type == 'TK_STRING': + prefix = 'NEWLINE' + elif self.last_type == 'TK_WORD': + if self.last_text == 'else': + # eat newlines between ...else *** some_op... + # won't preserve extra newlines in this place (if any), but don't care that much + self.trim_output(True); + prefix = 'SPACE' + elif self.last_type == 'TK_START_BLOCK': + prefix = 'NEWLINE' + elif self.last_type == 'TK_END_EXPR': + self.append(' ') + prefix = 'NEWLINE' + + if self.flags.if_line and self.last_type == 'TK_END_EXPR': + self.flags.if_line = False + + if token_text in self.line_starters: + if self.last_text == 'else': + prefix = 'SPACE' + else: + prefix = 'NEWLINE' + + if token_text in ['else', 'catch', 'finally']: + if self.last_type != 'TK_END_BLOCK' \ + or self.opts.brace_style == 'expand' \ + or self.opts.brace_style == 'end-expand': + self.append_newline() + else: + self.trim_output(True) + self.append(' ') + elif prefix == 'NEWLINE': + if token_text == 'function' and (self.last_type == 'TK_START_EXPR' or self.last_text in '=,'): + # no need to force newline on "function" - + # (function... + pass + elif token_text == 'function' and self.last_text == 'new': + self.append(' ') + elif self.last_text in ['return', 'throw']: + # no newline between return nnn + self.append(' ') + elif self.last_type != 'TK_END_EXPR': + if (self.last_type != 'TK_START_EXPR' or token_text != 'var') and self.last_text != ':': + # no need to force newline on VAR - + # for (var x = 0... + if token_text == 'if' and self.last_word == 'else' and self.last_text != '{': + self.append(' ') + else: + self.flags.var_line = False + self.flags.var_line_reindented = False + self.append_newline() + elif token_text in self.line_starters and self.last_text != ')': + self.flags.var_line = False + self.flags.var_line_reindented = False + self.append_newline() + elif self.is_array(self.flags.mode) and self.last_text == ',' and self.last_last_text == '}': + self.append_newline() # }, in lists get a newline + elif prefix == 'SPACE': + self.append(' ') + + + self.append(token_text) + self.last_word = token_text + + if token_text == 'var': + self.flags.var_line = True + self.flags.var_line_reindented = False + self.flags.var_line_tainted = False + + + if token_text == 'if': + self.flags.if_line = True + + if token_text == 'else': + self.flags.if_line = False + + + def handle_semicolon(self, token_text): + self.append(token_text) + self.flags.var_line = False + self.flags.var_line_reindented = False + if self.flags.mode == 'OBJECT': + # OBJECT mode is weird and doesn't get reset too well. + self.flags.mode = 'BLOCK' + + + def handle_string(self, token_text): + if self.last_type in ['TK_START_BLOCK', 'TK_END_BLOCK', 'TK_SEMICOLON']: + self.append_newline() + elif self.last_type == 'TK_WORD': + self.append(' ') + + self.append(token_text) + + + def handle_equals(self, token_text): + if self.flags.var_line: + # just got an '=' in a var-line, different line breaking rules will apply + self.flags.var_line_tainted = True + + self.append(' ') + self.append(token_text) + self.append(' ') + + + def handle_operator(self, token_text): + space_before = True + space_after = True + + if self.flags.var_line and token_text == ',' and self.is_expression(self.flags.mode): + # do not break on comma, for ( var a = 1, b = 2 + self.flags.var_line_tainted = False + + if self.flags.var_line and token_text == ',': + if self.flags.var_line_tainted: + self.append(token_text) + self.flags.var_line_reindented = True + self.flags.var_line_tainted = False + self.append_newline() + return + else: + self.flags.var_line_tainted = False + + if self.last_text in ['return', 'throw']: + # return had a special handling in TK_WORD + self.append(' ') + self.append(token_text) + return + + if token_text == ':' and self.flags.in_case: + self.append(token_text) + self.append_newline() + self.flags.in_case = False + return + + if token_text == '::': + # no spaces around the exotic namespacing syntax operator + self.append(token_text) + return + + if token_text == ',': + if self.flags.var_line: + if self.flags.var_line_tainted: + # This never happens, as it's handled previously, right? + self.append(token_text) + self.append_newline() + self.flags.var_line_tainted = False + else: + self.append(token_text) + self.append(' ') + elif self.last_type == 'TK_END_BLOCK' and self.flags.mode != '(EXPRESSION)': + self.append(token_text) + if self.flags.mode == 'OBJECT' and self.last_text == '}': + self.append_newline() + else: + self.append(' ') + else: + if self.flags.mode == 'OBJECT': + self.append(token_text) + self.append_newline() + else: + # EXPR or DO_BLOCK + self.append(token_text) + self.append(' ') + # comma handled + return + elif token_text in ['--', '++', '!'] \ + or (token_text in ['+', '-'] \ + and self.last_type in ['TK_START_BLOCK', 'TK_START_EXPR', 'TK_EQUALS', 'TK_OPERATOR']) \ + or self.last_text in self.line_starters: + + space_before = False + space_after = False + + if self.last_text == ';' and self.is_expression(self.flags.mode): + # for (;; ++i) + # ^^ + space_before = True + + if self.last_type == 'TK_WORD' and self.last_text in self.line_starters: + space_before = True + + if self.flags.mode == 'BLOCK' and self.last_text in ['{', ';']: + # { foo: --i } + # foo(): --bar + self.append_newline() + + elif token_text == '.': + # decimal digits or object.property + space_before = False + + elif token_text == ':': + if self.flags.ternary_depth == 0: + self.flags.mode = 'OBJECT' + space_before = False + else: + self.flags.ternary_depth -= 1 + elif token_text == '?': + self.flags.ternary_depth += 1 + + if space_before: + self.append(' ') + + self.append(token_text) + + if space_after: + self.append(' ') + + + + + def handle_block_comment(self, token_text): + + lines = token_text.replace('\x0d', '').split('\x0a') + if token_text[:3] == '/**': + # javadoc: reformat and reindent + self.append_newline() + self.append(lines[0]) + for line in lines[1:]: + self.append_newline() + self.append(' ' + line.strip()) + else: + # simple block comment: leave intact + if len(lines) > 1: + # multiline comment starts on a new line + self.append_newline() + self.trim_output() + else: + # single line /* ... */ comment stays on the same line + self.append(' ') + for line in lines: + self.append(line) + self.append('\n') + self.append_newline() + + + def handle_inline_comment(self, token_text): + self.append(' ') + self.append(token_text) + if self.is_expression(self.flags.mode): + self.append(' ') + else: + self.append_newline() + + + def handle_comment(self, token_text): + if self.wanted_newline: + self.append_newline() + else: + self.append(' ') + + self.append(token_text) + self.append_newline() + + + def handle_unknown(self, token_text): + if self.last_text in ['return', 'throw']: + self.append(' ') + + self.append(token_text) + + + + + +def main(): + + argv = sys.argv[1:] + + try: + opts, args = getopt.getopt(argv, "s:c:djbkil:h", ['indent-size=','indent-char=', 'disable-preserve-newlines', + 'jslint-happy', 'brace-style=', + 'keep-array-indentation', 'indent-level=', 'help', + 'usage', 'stdin']) + except getopt.GetoptError: + usage() + sys.exit(2) + + js_options = default_options() + + file = None + if len(args) == 1: + file = args[0] + + for opt, arg in opts: + if opt in ('--keep-array-indentation', '-k'): + js_options.keep_array_indentation = True + if 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 ('--disable-preserve_newlines', '-d'): + js_options.preserve_newlines = False + elif opt in ('--jslint-happy', '-j'): + js_options.jslint_happy = True + elif opt in ('--brace-style', '-b'): + js_options.brace_style = arg + elif opt in ('--indent-level', '-l'): + js_options.indent_level = int(arg) + elif opt in ('--stdin', '-i'): + file = '-' + elif opt in ('--help', '--usage', '--h'): + return usage() + + if file == None: + return usage() + else: + print(beautify_file(file, js_options)) + + + +if __name__ == "__main__": + main() + + diff --git a/bundles/javascript.tmbundle/Syntaxes/JavaScript.plist b/bundles/javascript.tmbundle/Syntaxes/JavaScript.plist new file mode 100644 index 000000000..0f8de7e3b --- /dev/null +++ b/bundles/javascript.tmbundle/Syntaxes/JavaScript.plist @@ -0,0 +1,712 @@ + + + + + comment + JavaScript Syntax: version 2.0 + fileTypes + + js + htc + jsx + + foldingStartMarker + ^.*\bfunction\s*(\w+\s*)?\([^\)]*\)(\s*\{[^\}]*)?\s*$ + foldingStopMarker + ^\s*\} + keyEquivalent + ^~J + name + JavaScript + patterns + + + captures + + 1 + + name + support.class.js + + 2 + + name + support.constant.js + + 3 + + name + keyword.operator.js + + + comment + match stuff like: Sound.prototype = { … } when extending an object + match + ([a-zA-Z_?.$][\w?.$]*)\.(prototype)\s*(=)\s* + name + meta.class.js + + + captures + + 1 + + name + support.class.js + + 2 + + name + support.constant.js + + 3 + + name + entity.name.function.js + + 4 + + name + keyword.operator.js + + 5 + + name + storage.type.function.js + + 6 + + name + punctuation.definition.parameters.begin.js + + 7 + + name + variable.parameter.function.js + + 8 + + name + punctuation.definition.parameters.end.js + + + comment + match stuff like: Sound.prototype.play = function() { … } + match + ([a-zA-Z_?.$][\w?.$]*)\.(prototype)\.([a-zA-Z_?.$][\w?.$]*)\s*(=)\s*(function)?\s*(\()(.*?)(\)) + name + meta.function.prototype.js + + + captures + + 1 + + name + support.class.js + + 2 + + name + support.constant.js + + 3 + + name + entity.name.function.js + + 4 + + name + keyword.operator.js + + + comment + match stuff like: Sound.prototype.play = myfunc + match + ([a-zA-Z_?.$][\w?.$]*)\.(prototype)\.([a-zA-Z_?.$][\w?.$]*)\s*(=)\s* + name + meta.function.js + + + captures + + 1 + + name + support.class.js + + 2 + + name + entity.name.function.js + + 3 + + name + keyword.operator.js + + 4 + + name + storage.type.function.js + + 5 + + name + punctuation.definition.parameters.begin.js + + 6 + + name + variable.parameter.function.js + + 7 + + name + punctuation.definition.parameters.end.js + + + comment + match stuff like: Sound.play = function() { … } + match + ([a-zA-Z_?.$][\w?.$]*)\.([a-zA-Z_?.$][\w?.$]*)\s*(=)\s*(function)\s*(\()(.*?)(\)) + name + meta.function.js + + + captures + + 1 + + name + entity.name.function.js + + 2 + + name + keyword.operator.js + + 3 + + name + storage.type.function.js + + 4 + + name + punctuation.definition.parameters.begin.js + + 5 + + name + variable.parameter.function.js + + 6 + + name + punctuation.definition.parameters.end.js + + + comment + match stuff like: play = function() { … } + match + ([a-zA-Z_?$][\w?$]*)\s*(=)\s*(function)\s*(\()(.*?)(\)) + name + meta.function.js + + + captures + + 1 + + name + storage.type.function.js + + 2 + + name + entity.name.function.js + + 3 + + name + punctuation.definition.parameters.begin.js + + 4 + + name + variable.parameter.function.js + + 5 + + name + punctuation.definition.parameters.end.js + + + comment + match regular function like: function myFunc(arg) { … } + match + \b(function)\s+([a-zA-Z_$]\w*)?\s*(\()(.*?)(\)) + name + meta.function.js + + + captures + + 1 + + name + entity.name.function.js + + 2 + + name + storage.type.function.js + + 3 + + name + punctuation.definition.parameters.begin.js + + 4 + + name + variable.parameter.function.js + + 5 + + name + punctuation.definition.parameters.end.js + + + comment + match stuff like: foobar: function() { … } + match + \b([a-zA-Z_?.$][\w?.$]*)\s*:\s*\b(function)?\s*(\()(.*?)(\)) + name + meta.function.json.js + + + captures + + 1 + + name + string.quoted.single.js + + 10 + + name + punctuation.definition.parameters.begin.js + + 11 + + name + variable.parameter.function.js + + 12 + + name + punctuation.definition.parameters.end.js + + 2 + + name + punctuation.definition.string.begin.js + + 3 + + name + entity.name.function.js + + 4 + + name + punctuation.definition.string.end.js + + 5 + + name + string.quoted.double.js + + 6 + + name + punctuation.definition.string.begin.js + + 7 + + name + entity.name.function.js + + 8 + + name + punctuation.definition.string.end.js + + 9 + + name + entity.name.function.js + + + comment + Attempt to match "foo": function + match + (?:((')(.*?)('))|((")(.*?)(")))\s*:\s*\b(function)?\s*(\()(.*?)(\)) + name + meta.function.json.js + + + captures + + 1 + + name + keyword.operator.new.js + + 2 + + name + entity.name.type.instance.js + + + match + (new)\s+(\w+(?:\.\w*)?) + name + meta.class.instance.constructor + + + match + \b(console)\b + name + entity.name.type.object.js.firebug + + + match + \.(warn|info|log|error|time|timeEnd|assert)\b + name + support.function.js.firebug + + + match + \b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?))\b + name + constant.numeric.js + + + begin + ' + beginCaptures + + 0 + + name + punctuation.definition.string.begin.js + + + end + ' + endCaptures + + 0 + + name + punctuation.definition.string.end.js + + + name + string.quoted.single.js + patterns + + + match + \\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.) + name + constant.character.escape.js + + + + + begin + " + beginCaptures + + 0 + + name + punctuation.definition.string.begin.js + + + end + " + endCaptures + + 0 + + name + punctuation.definition.string.end.js + + + name + string.quoted.double.js + patterns + + + match + \\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]|37[0-7]?|[4-7][0-7]?|.) + name + constant.character.escape.js + + + + + begin + /\*\*(?!/) + captures + + 0 + + name + punctuation.definition.comment.js + + + end + \*/ + name + comment.block.documentation.js + + + begin + /\* + captures + + 0 + + name + punctuation.definition.comment.js + + + end + \*/ + name + comment.block.js + + + captures + + 1 + + name + punctuation.definition.comment.js + + + match + (//).*$\n? + name + comment.line.double-slash.js + + + captures + + 0 + + name + punctuation.definition.comment.html.js + + 2 + + name + punctuation.definition.comment.html.js + + + match + (<!--|-->) + name + comment.block.html.js + + + match + \b(boolean|byte|char|class|double|enum|float|function|int|interface|long|short|var|void)\b + name + storage.type.js + + + match + \b(const|export|extends|final|implements|native|private|protected|public|static|synchronized|throws|transient|volatile)\b + name + storage.modifier.js + + + match + \b(break|case|catch|continue|default|do|else|finally|for|goto|if|import|package|return|switch|throw|try|while)\b + name + keyword.control.js + + + match + \b(delete|in|instanceof|new|typeof|with)\b + name + keyword.operator.js + + + match + \btrue\b + name + constant.language.boolean.true.js + + + match + \bfalse\b + name + constant.language.boolean.false.js + + + match + \bnull\b + name + constant.language.null.js + + + match + \b(super|this)\b + name + variable.language.js + + + match + \b(debugger)\b + name + keyword.other.js + + + match + \b(Anchor|Applet|Area|Array|Boolean|Button|Checkbox|Date|document|event|FileUpload|Form|Frame|Function|Hidden|History|Image|JavaArray|JavaClass|JavaObject|JavaPackage|java|Layer|Link|Location|Math|MimeType|Number|navigator|netscape|Object|Option|Packages|Password|Plugin|Radio|RegExp|Reset|Select|String|Style|Submit|screen|sun|Text|Textarea|window|XMLHttpRequest)\b + name + support.class.js + + + match + \b(s(h(ift|ow(Mod(elessDialog|alDialog)|Help))|croll(X|By(Pages|Lines)?|Y|To)?|t(op|rike)|i(n|zeToContent|debar|gnText)|ort|u(p|b(str(ing)?)?)|pli(ce|t)|e(nd|t(Re(sizable|questHeader)|M(i(nutes|lliseconds)|onth)|Seconds|Ho(tKeys|urs)|Year|Cursor|Time(out)?|Interval|ZOptions|Date|UTC(M(i(nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(ome|andleEvent)|navigate|c(har(CodeAt|At)|o(s|n(cat|textual|firm)|mpile)|eil|lear(Timeout|Interval)?|a(ptureEvents|ll)|reate(StyleSheet|Popup|EventObject))|t(o(GMTString|S(tring|ource)|U(TCString|pperCase)|Lo(caleString|werCase))|est|a(n|int(Enabled)?))|i(s(NaN|Finite)|ndexOf|talics)|d(isableExternalCapture|ump|etachEvent)|u(n(shift|taint|escape|watch)|pdateCommands)|j(oin|avaEnabled)|p(o(p|w)|ush|lugins.refresh|a(ddings|rse(Int|Float)?)|r(int|ompt|eference))|e(scape|nableExternalCapture|val|lementFromPoint|x(p|ec(Script|Command)?))|valueOf|UTC|queryCommand(State|Indeterm|Enabled|Value)|f(i(nd|le(ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(nt(size|color)|rward)|loor|romCharCode)|watch|l(ink|o(ad|g)|astIndexOf)|a(sin|nchor|cos|t(tachEvent|ob|an(2)?)|pply|lert|b(s|ort))|r(ou(nd|teEvents)|e(size(By|To)|calc|turnValue|place|verse|l(oad|ease(Capture|Events)))|andom)|g(o|et(ResponseHeader|M(i(nutes|lliseconds)|onth)|Se(conds|lection)|Hours|Year|Time(zoneOffset)?|Da(y|te)|UTC(M(i(nutes|lliseconds)|onth)|Seconds|Hours|Da(y|te)|FullYear)|FullYear|A(ttention|llResponseHeaders)))|m(in|ove(B(y|elow)|To(Absolute)?|Above)|ergeAttributes|a(tch|rgins|x))|b(toa|ig|o(ld|rderWidths)|link|ack))\b(?=\() + name + support.function.js + + + match + \b(s(ub(stringData|mit)|plitText|e(t(NamedItem|Attribute(Node)?)|lect))|has(ChildNodes|Feature)|namedItem|c(l(ick|o(se|neNode))|reate(C(omment|DATASection|aption)|T(Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(ntityReference|lement)|Attribute))|tabIndex|i(nsert(Row|Before|Cell|Data)|tem)|open|delete(Row|C(ell|aption)|T(Head|Foot)|Data)|focus|write(ln)?|a(dd|ppend(Child|Data))|re(set|place(Child|Data)|move(NamedItem|Child|Attribute(Node)?)?)|get(NamedItem|Element(sBy(Name|TagName)|ById)|Attribute(Node)?)|blur)\b(?=\() + name + support.function.dom.js + + + match + (?<=\.)(s(ystemLanguage|cr(ipts|ollbars|een(X|Y|Top|Left))|t(yle(Sheets)?|atus(Text|bar)?)|ibling(Below|Above)|ource|uffixes|e(curity(Policy)?|l(ection|f)))|h(istory|ost(name)?|as(h|Focus))|y|X(MLDocument|SLDocument)|n(ext|ame(space(s|URI)|Prop))|M(IN_VALUE|AX_VALUE)|c(haracterSet|o(n(structor|trollers)|okieEnabled|lorDepth|mp(onents|lete))|urrent|puClass|l(i(p(boardData)?|entInformation)|osed|asses)|alle(e|r)|rypto)|t(o(olbar|p)|ext(Transform|Indent|Decoration|Align)|ags)|SQRT(1_2|2)|i(n(ner(Height|Width)|put)|ds|gnoreCase)|zIndex|o(scpu|n(readystatechange|Line)|uter(Height|Width)|p(sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(i(splay|alog(Height|Top|Width|Left|Arguments)|rectories)|e(scription|fault(Status|Ch(ecked|arset)|View)))|u(ser(Profile|Language|Agent)|n(iqueID|defined)|pdateInterval)|_content|p(ixelDepth|ort|ersonalbar|kcs11|l(ugins|atform)|a(thname|dding(Right|Bottom|Top|Left)|rent(Window|Layer)?|ge(X(Offset)?|Y(Offset)?))|r(o(to(col|type)|duct(Sub)?|mpter)|e(vious|fix)))|e(n(coding|abledPlugin)|x(ternal|pando)|mbeds)|v(isibility|endor(Sub)?|Linkcolor)|URLUnencoded|P(I|OSITIVE_INFINITY)|f(ilename|o(nt(Size|Family|Weight)|rmName)|rame(s|Element)|gColor)|E|whiteSpace|l(i(stStyleType|n(eHeight|kColor))|o(ca(tion(bar)?|lName)|wsrc)|e(ngth|ft(Context)?)|a(st(M(odified|atch)|Index|Paren)|yer(s|X)|nguage))|a(pp(MinorVersion|Name|Co(deName|re)|Version)|vail(Height|Top|Width|Left)|ll|r(ity|guments)|Linkcolor|bove)|r(ight(Context)?|e(sponse(XML|Text)|adyState))|global|x|m(imeTypes|ultiline|enubar|argin(Right|Bottom|Top|Left))|L(N(10|2)|OG(10E|2E))|b(o(ttom|rder(Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(Color|Image)))\b + name + support.constant.js + + + match + (?<=\.)(s(hape|ystemId|c(heme|ope|rolling)|ta(ndby|rt)|ize|ummary|pecified|e(ctionRowIndex|lected(Index)?)|rc)|h(space|t(tpEquiv|mlFor)|e(ight|aders)|ref(lang)?)|n(o(Resize|tation(s|Name)|Shade|Href|de(Name|Type|Value)|Wrap)|extSibling|ame)|c(h(ildNodes|Off|ecked|arset)?|ite|o(ntent|o(kie|rds)|de(Base|Type)?|l(s|Span|or)|mpact)|ell(s|Spacing|Padding)|l(ear|assName)|aption)|t(ype|Bodies|itle|Head|ext|a(rget|gName)|Foot)|i(sMap|ndex|d|m(plementation|ages))|o(ptions|wnerDocument|bject)|d(i(sabled|r)|o(c(type|umentElement)|main)|e(clare|f(er|ault(Selected|Checked|Value)))|at(eTime|a))|useMap|p(ublicId|arentNode|r(o(file|mpt)|eviousSibling))|e(n(ctype|tities)|vent|lements)|v(space|ersion|alue(Type)?|Link|Align)|URL|f(irstChild|orm(s)?|ace|rame(Border)?)|width|l(ink(s)?|o(ngDesc|wSrc)|a(stChild|ng|bel))|a(nchors|c(ce(ssKey|pt(Charset)?)|tion)|ttributes|pplets|l(t|ign)|r(chive|eas)|xis|Link|bbr)|r(ow(s|Span|Index)|ules|e(v|ferrer|l|adOnly))|m(ultiple|e(thod|dia)|a(rgin(Height|Width)|xLength))|b(o(dy|rder)|ackground|gColor))\b + name + support.constant.dom.js + + + match + \b(ELEMENT_NODE|ATTRIBUTE_NODE|TEXT_NODE|CDATA_SECTION_NODE|ENTITY_REFERENCE_NODE|ENTITY_NODE|PROCESSING_INSTRUCTION_NODE|COMMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE|DOCUMENT_FRAGMENT_NODE|NOTATION_NODE|INDEX_SIZE_ERR|DOMSTRING_SIZE_ERR|HIERARCHY_REQUEST_ERR|WRONG_DOCUMENT_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR|NOT_SUPPORTED_ERR|INUSE_ATTRIBUTE_ERR)\b + name + support.constant.dom.js + + + match + \bon(R(ow(s(inserted|delete)|e(nter|xit))|e(s(ize(start|end)?|et)|adystatechange))|Mouse(o(ut|ver)|down|up|move)|B(efore(cut|deactivate|u(nload|pdate)|p(aste|rint)|editfocus|activate)|lur)|S(croll|top|ubmit|elect(start|ionchange)?)|H(over|elp)|C(hange|ont(extmenu|rolselect)|ut|ellchange|l(ick|ose))|D(eactivate|ata(setc(hanged|omplete)|available)|r(op|ag(start|over|drop|en(ter|d)|leave)?)|blclick)|Unload|P(aste|ropertychange)|Error(update)?|Key(down|up|press)|Focus|Load|A(ctivate|fter(update|print)|bort))\b + name + support.function.event-handler.js + + + match + !|\$|%|&|\*|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\|\||\?\:|\*=|(?<!\()/=|%=|\+=|\-=|&=|\^=|\b(in|instanceof|new|delete|typeof|void)\b + name + keyword.operator.js + + + match + \b(Infinity|NaN|undefined)\b + name + constant.language.js + + + begin + (?<=[=(:]|^|return|&&|\|\||!)\s*(/)(?![/*+{}?]) + beginCaptures + + 1 + + name + punctuation.definition.string.begin.js + + + end + (/)[igm]* + endCaptures + + 1 + + name + punctuation.definition.string.end.js + + + name + string.regexp.js + patterns + + + match + \\. + name + constant.character.escape.js + + + + + match + \; + name + punctuation.terminator.statement.js + + + match + ,[ |\t]* + name + meta.delimiter.object.comma.js + + + match + \. + name + meta.delimiter.method.period.js + + + match + \{|\} + name + meta.brace.curly.js + + + match + \(|\) + name + meta.brace.round.js + + + match + \[|\] + name + meta.brace.square.js + + + scopeName + source.js + uuid + 93E017CC-6F27-11D9-90EB-000D93589AF6 + + diff --git a/bundles/javascript.tmbundle/info.plist b/bundles/javascript.tmbundle/info.plist new file mode 100644 index 000000000..ea4a6ab44 --- /dev/null +++ b/bundles/javascript.tmbundle/info.plist @@ -0,0 +1,136 @@ + + + + + contactEmailRot13 + boyvivbhf@fhogyrTenqvrag.pbz + contactName + Thomas Aylott + deleted + + 0FE55436-0C29-4545-A3BE-B858EF81E27B + + description + Support for <a href="http://developer.mozilla.org/en/docs/About_JavaScript">JavaScript</a>. + mainMenu + + items + + D2E6A1FE-2881-4754-B399-B65F61F29C2F + 43F40EB6-5839-4BE8-99C8-4976D0534E5D + 52090C49-D8B2-49A0-9597-80574354B3CD + ------------------------------------ + B4874A14-2491-465A-A349-61E4EBCF4700 + ------------------------------------ + 36EC03E9-EFF4-479A-AB90-8DFA16800642 + 20E61C43-B81F-4FB9-9362-BFFE668EB9C9 + + submenus + + 43F40EB6-5839-4BE8-99C8-4976D0534E5D + + items + + 9E0E3BCC-7F20-4D6B-891D-A44D6EC56E31 + + name + DOM + + 52090C49-D8B2-49A0-9597-80574354B3CD + + items + + 009A3E6C-FE3F-4A18-8759-2DC31F17BBE2 + + name + BOM + + 66778C58-CE08-4F21-AD36-562149AEEE80 + + items + + 4C6EDB43-3E2E-411B-A016-13C135C59833 + F0E4FB6A-4878-48C6-A777-62438DF1E14F + ------------------------------------ + 73951799-AC15-40A6-81DB-EC051AB4A033 + 1717B5AE-209B-4548-9155-9E88A7230C1C + ------------------------------------ + 77065D69-742A-4FF0-9A41-AD211DFBE72F + 7B9AEFCC-B450-416D-8527-430FE2A08568 + + name + Function + + 7699AC1A-80AC-4120-A375-9371D1591F79 + + items + + F19F3732-39A7-48EC-A72B-A8F477A01795 + 31964029-9D71-4ADC-8213-DFE5C4E222B3 + ------------------------------------ + 011C4681-FBEC-4891-9326-3DECFCDED6D6 + C207B7C3-5597-4873-8AAD-C46FB8842AF2 + + name + Control + + D2E6A1FE-2881-4754-B399-B65F61F29C2F + + items + + 7699AC1A-80AC-4120-A375-9371D1591F79 + EC690F46-1906-4F55-9089-3C2929D5BB69 + 66778C58-CE08-4F21-AD36-562149AEEE80 + + name + Core + + EC690F46-1906-4F55-9089-3C2929D5BB69 + + items + + DC8B46FB-8ADA-45EA-8F36-94C807A0D302 + AD506BEC-B33C-4168-A900-0A4D386A4B05 + ------------------------------------ + 2F96136B-0193-42F5-90FC-B6F456A3AD77 + + name + Language + + + + name + JavaScript + ordering + + 73951799-AC15-40A6-81DB-EC051AB4A033 + 1717B5AE-209B-4548-9155-9E88A7230C1C + B4874A14-2491-465A-A349-61E4EBCF4700 + 36EC03E9-EFF4-479A-AB90-8DFA16800642 + 20E61C43-B81F-4FB9-9362-BFFE668EB9C9 + 77065D69-742A-4FF0-9A41-AD211DFBE72F + F0E4FB6A-4878-48C6-A777-62438DF1E14F + 2F96136B-0193-42F5-90FC-B6F456A3AD77 + 4C6EDB43-3E2E-411B-A016-13C135C59833 + 93E017CC-6F27-11D9-90EB-000D93589AF6 + A67A8BD9-A951-406F-9175-018DD4B52FD1 + BC062860-3346-4D3B-8421-C5543F83D11F + 834BC727-6B31-4073-A161-4823227219EF + 3CEA49B2-A5C5-405C-82E2-B8B668877C37 + E6EB7CC8-04E8-43A9-93B2-BC9EF5BA862B + 73557394-4F0F-4DD3-8029-EEE8201AC7F5 + 51841DDB-C2A4-461C-A8AB-6C124AD50EAE + F19F3732-39A7-48EC-A72B-A8F477A01795 + 31964029-9D71-4ADC-8213-DFE5C4E222B3 + 011C4681-FBEC-4891-9326-3DECFCDED6D6 + C207B7C3-5597-4873-8AAD-C46FB8842AF2 + AD506BEC-B33C-4168-A900-0A4D386A4B05 + DC8B46FB-8ADA-45EA-8F36-94C807A0D302 + 009A3E6C-FE3F-4A18-8759-2DC31F17BBE2 + 7B9AEFCC-B450-416D-8527-430FE2A08568 + 9E0E3BCC-7F20-4D6B-891D-A44D6EC56E31 + + uuid + AAB4FD74-73F9-11D9-B89A-000D93589AF6 + +