js-beautify 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. data/.document +5 -0
  2. data/.gitmodules +4 -0
  3. data/Gemfile +13 -0
  4. data/Gemfile.lock +27 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.rdoc +13 -0
  7. data/Rakefile +29 -0
  8. data/VERSION +1 -0
  9. data/bin/js-beautify +5 -0
  10. data/init.sh +3 -0
  11. data/js-beautify-copy/.gitmodules +3 -0
  12. data/js-beautify-copy/Makefile +71 -0
  13. data/js-beautify-copy/README.md +39 -0
  14. data/js-beautify-copy/attic/beautify-cl/beautify-cl.js +142 -0
  15. data/js-beautify-copy/attic/bin/beautify_js +80 -0
  16. data/js-beautify-copy/attic/opera-userscript/beautifier.js +1087 -0
  17. data/js-beautify-copy/attic/opera-userscript/make_opera_userscript.sh +42 -0
  18. data/js-beautify-copy/attic/qtscript/jsbeautify.cpp +121 -0
  19. data/js-beautify-copy/attic/qtscript/jsbeautify.pro +5 -0
  20. data/js-beautify-copy/attic/qtscript/jsbeautify.qrc +6 -0
  21. data/js-beautify-copy/attic/qtscript/readme.txt +28 -0
  22. data/js-beautify-copy/attic/readme.txt +2 -0
  23. data/js-beautify-copy/attic/unmaintained/bbedit/jsBeautify_BBED.scpt +522 -0
  24. data/js-beautify-copy/attic/unmaintained/c-sharp/JSBeautify.cs +801 -0
  25. data/js-beautify-copy/attic/v8/README.txt +40 -0
  26. data/js-beautify-copy/attic/v8/beautify.h +2390 -0
  27. data/js-beautify-copy/attic/v8/jsbeautify.cpp +215 -0
  28. data/js-beautify-copy/beautify-css.js +198 -0
  29. data/js-beautify-copy/beautify-html.js +514 -0
  30. data/js-beautify-copy/beautify.js +1293 -0
  31. data/js-beautify-copy/favicon.png +0 -0
  32. data/js-beautify-copy/index.html +401 -0
  33. data/js-beautify-copy/jquery/jquery.cookie.js +96 -0
  34. data/js-beautify-copy/jquery/jquery.js +167 -0
  35. data/js-beautify-copy/license.txt +24 -0
  36. data/js-beautify-copy/php/jsbeautifier.php +1599 -0
  37. data/js-beautify-copy/php/test.php +476 -0
  38. data/js-beautify-copy/python/MANIFEST.in +2 -0
  39. data/js-beautify-copy/python/js-beautify +7 -0
  40. data/js-beautify-copy/python/js-beautify-profile +16 -0
  41. data/js-beautify-copy/python/js-beautify-test +10 -0
  42. data/js-beautify-copy/python/jsbeautifier/__init__.py +1166 -0
  43. data/js-beautify-copy/python/jsbeautifier/tests/__init__.py +1 -0
  44. data/js-beautify-copy/python/jsbeautifier/tests/testindentation.py +43 -0
  45. data/js-beautify-copy/python/jsbeautifier/tests/testjsbeautifier.py +464 -0
  46. data/js-beautify-copy/python/jsbeautifier/unpackers/README.specs.mkd +25 -0
  47. data/js-beautify-copy/python/jsbeautifier/unpackers/__init__.py +67 -0
  48. data/js-beautify-copy/python/jsbeautifier/unpackers/evalbased.py +39 -0
  49. data/js-beautify-copy/python/jsbeautifier/unpackers/javascriptobfuscator.py +58 -0
  50. data/js-beautify-copy/python/jsbeautifier/unpackers/myobfuscate.py +86 -0
  51. data/js-beautify-copy/python/jsbeautifier/unpackers/packer.py +104 -0
  52. data/js-beautify-copy/python/jsbeautifier/unpackers/tests/__init__.py +2 -0
  53. data/js-beautify-copy/python/jsbeautifier/unpackers/tests/test-myobfuscate-input.js +1 -0
  54. data/js-beautify-copy/python/jsbeautifier/unpackers/tests/test-myobfuscate-output.js +65 -0
  55. data/js-beautify-copy/python/jsbeautifier/unpackers/tests/test-packer-62-input.js +1 -0
  56. data/js-beautify-copy/python/jsbeautifier/unpackers/tests/test-packer-non62-input.js +1 -0
  57. data/js-beautify-copy/python/jsbeautifier/unpackers/tests/testjavascriptobfuscator.py +46 -0
  58. data/js-beautify-copy/python/jsbeautifier/unpackers/tests/testmyobfuscate.py +40 -0
  59. data/js-beautify-copy/python/jsbeautifier/unpackers/tests/testpacker.py +34 -0
  60. data/js-beautify-copy/python/jsbeautifier/unpackers/tests/testurlencode.py +36 -0
  61. data/js-beautify-copy/python/jsbeautifier/unpackers/urlencode.py +34 -0
  62. data/js-beautify-copy/python/setup.py +17 -0
  63. data/js-beautify-copy/tests/beautify-tests.js +489 -0
  64. data/js-beautify-copy/tests/run-tests +17 -0
  65. data/js-beautify-copy/tests/sanitytest.js +128 -0
  66. data/js-beautify-copy/unpackers/javascriptobfuscator_unpacker.js +103 -0
  67. data/js-beautify-copy/unpackers/myobfuscate_unpacker.js +81 -0
  68. data/js-beautify-copy/unpackers/p_a_c_k_e_r_unpacker.js +61 -0
  69. data/js-beautify-copy/unpackers/urlencode_unpacker.js +51 -0
  70. data/lib/js-beautify.rb +0 -0
  71. data/test/helper.rb +18 -0
  72. data/test/test_js-beautify.rb +7 -0
  73. data/update.sh +23 -0
  74. metadata +173 -0
@@ -0,0 +1,2 @@
1
+ include js-beautify
2
+ include js-beautify-test
@@ -0,0 +1,7 @@
1
+ #! /usr/bin/env python
2
+ #
3
+ # Stub script to run jsbeautifier
4
+ #
5
+
6
+ from jsbeautifier import main
7
+ main()
@@ -0,0 +1,16 @@
1
+ #! /usr/bin/env python
2
+
3
+ import sys
4
+ import unittest
5
+
6
+ #Speedup things...
7
+ try:
8
+ import cProfile as profile
9
+ except ImportError:
10
+ import profile
11
+
12
+ def run():
13
+ sys.argv.append('discover')
14
+ unittest.main()
15
+
16
+ profile.run('run()')
@@ -0,0 +1,10 @@
1
+ #! /bin/sh
2
+ #
3
+ # Test suite launcher
4
+ #
5
+
6
+ if [ -z $PYTHON ]; then
7
+ env python -m unittest discover "$@"
8
+ else
9
+ env $PYTHON -m unittest discover "$@"
10
+ fi
@@ -0,0 +1,1166 @@
1
+ import sys
2
+ import getopt
3
+ import re
4
+ import string
5
+
6
+ #
7
+ # Originally written by Einar Lielmanis et al.,
8
+ # Conversion to python by Einar Lielmanis, einar@jsbeautifier.org,
9
+ # MIT licence, enjoy.
10
+ #
11
+ # Python is not my native language, feel free to push things around.
12
+ #
13
+ # Use either from command line (script displays its usage when run
14
+ # without any parameters),
15
+ #
16
+ #
17
+ # or, alternatively, use it as a module:
18
+ #
19
+ # import jsbeautifier
20
+ # res = jsbeautifier.beautify('your javascript string')
21
+ # res = jsbeautifier.beautify_file('some_file.js')
22
+ #
23
+ # you may specify some options:
24
+ #
25
+ # opts = jsbeautifier.default_options()
26
+ # opts.indent_size = 2
27
+ # res = jsbeautifier.beautify('some javascript', opts)
28
+ #
29
+ #
30
+ # Here are the available options: (read source)
31
+
32
+
33
+ class BeautifierOptions:
34
+ def __init__(self):
35
+ self.indent_size = 4
36
+ self.indent_char = ' '
37
+ self.indent_with_tabs = False
38
+ self.preserve_newlines = True
39
+ self.max_preserve_newlines = 10.
40
+ self.jslint_happy = False
41
+ self.brace_style = 'collapse'
42
+ self.keep_array_indentation = False
43
+ self.keep_function_indentation = False
44
+ self.eval_code = False
45
+
46
+
47
+
48
+ def __repr__(self):
49
+ return \
50
+ """indent_size = %d
51
+ indent_char = [%s]
52
+ preserve_newlines = %s
53
+ max_preserve_newlines = %d
54
+ jslint_happy = %s
55
+ indent_with_tabs = %s
56
+ brace_style = %s
57
+ keep_array_indentation = %s
58
+ eval_code = %s
59
+ """ % ( self.indent_size,
60
+ self.indent_char,
61
+ self.preserve_newlines,
62
+ self.max_preserve_newlines,
63
+ self.jslint_happy,
64
+ self.indent_with_tabs,
65
+ self.brace_style,
66
+ self.keep_array_indentation,
67
+ self.eval_code,
68
+ )
69
+
70
+
71
+ class BeautifierFlags:
72
+ def __init__(self, mode):
73
+ self.previous_mode = 'BLOCK'
74
+ self.mode = mode
75
+ self.var_line = False
76
+ self.var_line_tainted = False
77
+ self.var_line_reindented = False
78
+ self.in_html_comment = False
79
+ self.if_line = False
80
+ self.in_case = False
81
+ self.in_case_statement = False
82
+ self.eat_next_space = False
83
+ self.indentation_baseline = -1
84
+ self.indentation_level = 0
85
+ self.ternary_depth = 0
86
+
87
+
88
+ def default_options():
89
+ return BeautifierOptions()
90
+
91
+
92
+ def beautify(string, opts = default_options() ):
93
+ b = Beautifier()
94
+ return b.beautify(string, opts)
95
+
96
+ def beautify_file(file_name, opts = default_options() ):
97
+
98
+ if file_name == '-': # stdin
99
+ f = sys.stdin
100
+ else:
101
+ try:
102
+ f = open(file_name)
103
+ except Exception as ex:
104
+ return 'The file could not be opened'
105
+
106
+ b = Beautifier()
107
+ return b.beautify(''.join(f.readlines()), opts)
108
+
109
+
110
+ def usage():
111
+
112
+ print("""Javascript beautifier (http://jsbeautifier.org/)
113
+
114
+ Usage: jsbeautifier.py [options] <infile>
115
+
116
+ <infile> can be "-", which means stdin.
117
+ <outfile> defaults to stdout
118
+
119
+ Input options:
120
+
121
+ -i, --stdin read input from stdin
122
+
123
+ Output options:
124
+
125
+ -s, --indent-size=NUMBER indentation size. (default 4).
126
+ -c, --indent-char=CHAR character to indent with. (default space).
127
+ -t, --indent-with-tabs Indent with tabs, overrides -s and -c
128
+ -d, --disable-preserve-newlines do not preserve existing line breaks.
129
+ -j, --jslint-happy more jslint-compatible output
130
+ -b, --brace-style=collapse brace style (collapse, expand, end-expand)
131
+ -k, --keep-array-indentation keep array indentation.
132
+ -o, --outfile=FILE specify a file to output to (default stdout)
133
+ -f, --keep-function-indentation Do not re-indent function bodies defined in var lines.
134
+
135
+ Rarely needed options:
136
+
137
+ --eval-code evaluate code if a JS interpreter is
138
+ installed. May be useful with some obfuscated
139
+ script but poses a potential security issue.
140
+
141
+ -l, --indent-level=NUMBER initial indentation level. (default 0).
142
+
143
+ -h, --help, --usage prints this help statement.
144
+
145
+ """)
146
+
147
+
148
+
149
+
150
+
151
+
152
+ class Beautifier:
153
+
154
+ def __init__(self, opts = default_options() ):
155
+
156
+ self.opts = opts
157
+ self.blank_state()
158
+
159
+ def blank_state(self):
160
+
161
+ # internal flags
162
+ self.flags = BeautifierFlags('BLOCK')
163
+ self.flag_store = []
164
+ self.wanted_newline = False
165
+ self.just_added_newline = False
166
+ self.do_block_just_closed = False
167
+
168
+ if self.opts.indent_with_tabs:
169
+ self.indent_string = "\t"
170
+ else:
171
+ self.indent_string = self.opts.indent_char * self.opts.indent_size
172
+
173
+ self.preindent_string = ''
174
+ self.last_word = '' # last TK_WORD seen
175
+ self.last_type = 'TK_START_EXPR' # last token type
176
+ self.last_text = '' # last token text
177
+ self.last_last_text = '' # pre-last token text
178
+
179
+ self.input = None
180
+ self.output = [] # formatted javascript gets built here
181
+
182
+ self.whitespace = ["\n", "\r", "\t", " "]
183
+ self.wordchar = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$'
184
+ self.digits = '0123456789'
185
+ self.punct = '+ - * / % & ++ -- = += -= *= /= %= == === != !== > < >= <= >> << >>> >>>= >>= <<= && &= | || ! !! , : ? ^ ^= |= ::'
186
+ self.punct += ' <?= <? ?> <%= <% %>'
187
+ self.punct = self.punct.split(' ')
188
+
189
+
190
+ # Words which always should start on a new line
191
+ self.line_starters = 'continue,try,throw,return,var,if,switch,case,default,for,while,break,function'.split(',')
192
+ self.set_mode('BLOCK')
193
+
194
+ global parser_pos
195
+ parser_pos = 0
196
+
197
+
198
+ def beautify(self, s, opts = None ):
199
+
200
+ if opts != None:
201
+ self.opts = opts
202
+
203
+
204
+ if self.opts.brace_style not in ['expand', 'collapse', 'end-expand']:
205
+ raise(Exception('opts.brace_style must be "expand", "collapse" or "end-expand".'))
206
+
207
+ self.blank_state()
208
+
209
+ while s and s[0] in [' ', '\t']:
210
+ self.preindent_string += s[0]
211
+ s = s[1:]
212
+
213
+ self.input = self.unpack(s, opts.eval_code)
214
+
215
+ parser_pos = 0
216
+ while True:
217
+ token_text, token_type = self.get_next_token()
218
+ #print (token_text, token_type, self.flags.mode)
219
+ if token_type == 'TK_EOF':
220
+ break
221
+
222
+ handlers = {
223
+ 'TK_START_EXPR': self.handle_start_expr,
224
+ 'TK_END_EXPR': self.handle_end_expr,
225
+ 'TK_START_BLOCK': self.handle_start_block,
226
+ 'TK_END_BLOCK': self.handle_end_block,
227
+ 'TK_WORD': self.handle_word,
228
+ 'TK_SEMICOLON': self.handle_semicolon,
229
+ 'TK_STRING': self.handle_string,
230
+ 'TK_EQUALS': self.handle_equals,
231
+ 'TK_OPERATOR': self.handle_operator,
232
+ 'TK_BLOCK_COMMENT': self.handle_block_comment,
233
+ 'TK_INLINE_COMMENT': self.handle_inline_comment,
234
+ 'TK_COMMENT': self.handle_comment,
235
+ 'TK_UNKNOWN': self.handle_unknown,
236
+ }
237
+
238
+ handlers[token_type](token_text)
239
+
240
+ self.last_last_text = self.last_text
241
+ self.last_type = token_type
242
+ self.last_text = token_text
243
+
244
+ sweet_code = self.preindent_string + re.sub('[\n ]+$', '', ''.join(self.output))
245
+ return sweet_code
246
+
247
+ def unpack(self, source, evalcode=False):
248
+ import jsbeautifier.unpackers as unpackers
249
+ try:
250
+ return unpackers.run(source, evalcode)
251
+ except unpackers.UnpackingError as error:
252
+ print('error:', error)
253
+ return ''
254
+
255
+ def trim_output(self, eat_newlines = False):
256
+ while len(self.output) \
257
+ and (
258
+ self.output[-1] == ' '\
259
+ or self.output[-1] == self.indent_string \
260
+ or self.output[-1] == self.preindent_string \
261
+ or (eat_newlines and self.output[-1] in ['\n', '\r'])):
262
+ self.output.pop()
263
+
264
+ def is_special_word(self, s):
265
+ return s in ['case', 'return', 'do', 'if', 'throw', 'else'];
266
+
267
+ def is_array(self, mode):
268
+ return mode in ['[EXPRESSION]', '[INDENDED-EXPRESSION]']
269
+
270
+
271
+ def is_expression(self, mode):
272
+ return mode in ['[EXPRESSION]', '[INDENDED-EXPRESSION]', '(EXPRESSION)', '(FOR-EXPRESSION)', '(COND-EXPRESSION)']
273
+
274
+
275
+ def append_newline_forced(self):
276
+ old_array_indentation = self.opts.keep_array_indentation
277
+ self.opts.keep_array_indentation = False
278
+ self.append_newline()
279
+ self.opts.keep_array_indentation = old_array_indentation
280
+
281
+ def append_newline(self, ignore_repeated = True):
282
+
283
+ self.flags.eat_next_space = False
284
+
285
+ if self.opts.keep_array_indentation and self.is_array(self.flags.mode):
286
+ return
287
+
288
+ self.flags.if_line = False
289
+ self.trim_output()
290
+
291
+ if len(self.output) == 0:
292
+ # no newline on start of file
293
+ return
294
+
295
+ if self.output[-1] != '\n' or not ignore_repeated:
296
+ self.just_added_newline = True
297
+ self.output.append('\n')
298
+
299
+ if self.preindent_string:
300
+ self.output.append(self.preindent_string)
301
+
302
+ for i in range(self.flags.indentation_level):
303
+ self.output.append(self.indent_string)
304
+
305
+ if self.flags.var_line and self.flags.var_line_reindented:
306
+ self.output.append(self.indent_string)
307
+
308
+
309
+ def append(self, s):
310
+ if s == ' ':
311
+ # do not add just a single space after the // comment, ever
312
+ if self.last_type == 'TK_COMMENT':
313
+ return self.append_newline()
314
+
315
+ # make sure only single space gets drawn
316
+ if self.flags.eat_next_space:
317
+ self.flags.eat_next_space = False
318
+ elif len(self.output) and self.output[-1] not in [' ', '\n', self.indent_string]:
319
+ self.output.append(' ')
320
+ else:
321
+ self.just_added_newline = False
322
+ self.flags.eat_next_space = False
323
+ self.output.append(s)
324
+
325
+
326
+ def indent(self):
327
+ self.flags.indentation_level = self.flags.indentation_level + 1
328
+
329
+
330
+ def remove_indent(self):
331
+ if len(self.output) and self.output[-1] in [self.indent_string, self.preindent_string]:
332
+ self.output.pop()
333
+
334
+
335
+ def set_mode(self, mode):
336
+
337
+ prev = BeautifierFlags('BLOCK')
338
+
339
+ if self.flags:
340
+ self.flag_store.append(self.flags)
341
+ prev = self.flags
342
+
343
+ self.flags = BeautifierFlags(mode)
344
+
345
+ if len(self.flag_store) == 1:
346
+ self.flags.indentation_level = 0
347
+ else:
348
+ self.flags.indentation_level = prev.indentation_level
349
+ if prev.var_line and prev.var_line_reindented:
350
+ self.flags.indentation_level = self.flags.indentation_level + 1
351
+ self.flags.previous_mode = prev.mode
352
+
353
+
354
+ def restore_mode(self):
355
+ self.do_block_just_closed = self.flags.mode == 'DO_BLOCK'
356
+ if len(self.flag_store) > 0:
357
+ mode = self.flags.mode
358
+ self.flags = self.flag_store.pop()
359
+ self.flags.previous_mode = mode
360
+
361
+
362
+ def get_next_token(self):
363
+
364
+ global parser_pos
365
+
366
+ self.n_newlines = 0
367
+
368
+ if parser_pos >= len(self.input):
369
+ return '', 'TK_EOF'
370
+
371
+ self.wanted_newline = False
372
+ c = self.input[parser_pos]
373
+ parser_pos += 1
374
+
375
+ keep_whitespace = self.opts.keep_array_indentation and self.is_array(self.flags.mode)
376
+
377
+ if keep_whitespace:
378
+ # slight mess to allow nice preservation of array indentation and reindent that correctly
379
+ # first time when we get to the arrays:
380
+ # var a = [
381
+ # ....'something'
382
+ # we make note of whitespace_count = 4 into flags.indentation_baseline
383
+ # so we know that 4 whitespaces in original source match indent_level of reindented source
384
+ #
385
+ # and afterwards, when we get to
386
+ # 'something,
387
+ # .......'something else'
388
+ # we know that this should be indented to indent_level + (7 - indentation_baseline) spaces
389
+
390
+ whitespace_count = 0
391
+ while c in self.whitespace:
392
+ if c == '\n':
393
+ self.trim_output()
394
+ self.output.append('\n')
395
+ self.just_added_newline = True
396
+ whitespace_count = 0
397
+ elif c == '\t':
398
+ whitespace_count += 4
399
+ elif c == '\r':
400
+ pass
401
+ else:
402
+ whitespace_count += 1
403
+
404
+ if parser_pos >= len(self.input):
405
+ return '', 'TK_EOF'
406
+
407
+ c = self.input[parser_pos]
408
+ parser_pos += 1
409
+
410
+ if self.flags.indentation_baseline == -1:
411
+
412
+ self.flags.indentation_baseline = whitespace_count
413
+
414
+ if self.just_added_newline:
415
+ for i in range(self.flags.indentation_level + 1):
416
+ self.output.append(self.indent_string)
417
+
418
+ if self.flags.indentation_baseline != -1:
419
+ for i in range(whitespace_count - self.flags.indentation_baseline):
420
+ self.output.append(' ')
421
+
422
+ else: # not keep_whitespace
423
+ while c in self.whitespace:
424
+ if c == '\n':
425
+ if self.opts.max_preserve_newlines == 0 or self.opts.max_preserve_newlines > self.n_newlines:
426
+ self.n_newlines += 1
427
+
428
+ if parser_pos >= len(self.input):
429
+ return '', 'TK_EOF'
430
+
431
+ c = self.input[parser_pos]
432
+ parser_pos += 1
433
+
434
+ if self.opts.preserve_newlines and self.n_newlines > 1:
435
+ for i in range(self.n_newlines):
436
+ self.append_newline(i == 0)
437
+ self.just_added_newline = True
438
+
439
+ self.wanted_newline = self.n_newlines > 0
440
+
441
+
442
+ if c in self.wordchar:
443
+ if parser_pos < len(self.input):
444
+ while self.input[parser_pos] in self.wordchar:
445
+ c = c + self.input[parser_pos]
446
+ parser_pos += 1
447
+ if parser_pos == len(self.input):
448
+ break
449
+
450
+ # small and surprisingly unugly hack for 1E-10 representation
451
+ if parser_pos != len(self.input) and self.input[parser_pos] in '+-' \
452
+ and re.match('^[0-9]+[Ee]$', c):
453
+
454
+ sign = self.input[parser_pos]
455
+ parser_pos += 1
456
+ t = self.get_next_token()
457
+ c += sign + t[0]
458
+ return c, 'TK_WORD'
459
+
460
+ if c == 'in': # in is an operator, need to hack
461
+ return c, 'TK_OPERATOR'
462
+
463
+ if self.wanted_newline and \
464
+ self.last_type != 'TK_OPERATOR' and\
465
+ self.last_type != 'TK_EQUALS' and\
466
+ not self.flags.if_line and \
467
+ (self.opts.preserve_newlines or self.last_text != 'var'):
468
+ self.append_newline()
469
+
470
+ return c, 'TK_WORD'
471
+
472
+ if c in '([':
473
+ return c, 'TK_START_EXPR'
474
+
475
+ if c in ')]':
476
+ return c, 'TK_END_EXPR'
477
+
478
+ if c == '{':
479
+ return c, 'TK_START_BLOCK'
480
+
481
+ if c == '}':
482
+ return c, 'TK_END_BLOCK'
483
+
484
+ if c == ';':
485
+ return c, 'TK_SEMICOLON'
486
+
487
+ if c == '/':
488
+ comment = ''
489
+ inline_comment = True
490
+ comment_mode = 'TK_INLINE_COMMENT'
491
+ if self.input[parser_pos] == '*': # peek /* .. */ comment
492
+ parser_pos += 1
493
+ if parser_pos < len(self.input):
494
+ while not (self.input[parser_pos] == '*' and \
495
+ parser_pos + 1 < len(self.input) and \
496
+ self.input[parser_pos + 1] == '/')\
497
+ and parser_pos < len(self.input):
498
+ c = self.input[parser_pos]
499
+ comment += c
500
+ if c in '\r\n':
501
+ comment_mode = 'TK_BLOCK_COMMENT'
502
+ parser_pos += 1
503
+ if parser_pos >= len(self.input):
504
+ break
505
+ parser_pos += 2
506
+ return '/*' + comment + '*/', comment_mode
507
+ if self.input[parser_pos] == '/': # peek // comment
508
+ comment = c
509
+ while self.input[parser_pos] not in '\r\n':
510
+ comment += self.input[parser_pos]
511
+ parser_pos += 1
512
+ if parser_pos >= len(self.input):
513
+ break
514
+ parser_pos += 1
515
+ if self.wanted_newline:
516
+ self.append_newline()
517
+ return comment, 'TK_COMMENT'
518
+
519
+
520
+
521
+ if c == "'" or c == '"' or \
522
+ (c == '/' and ((self.last_type == 'TK_WORD' and self.is_special_word(self.last_text)) or \
523
+ (self.last_type == 'TK_END_EXPR' and self.flags.previous_mode in ['(FOR-EXPRESSION)', '(COND-EXPRESSION)']) or \
524
+ (self.last_type in ['TK_COMMENT', 'TK_START_EXPR', 'TK_START_BLOCK', 'TK_END_BLOCK', 'TK_OPERATOR',
525
+ 'TK_EQUALS', 'TK_EOF', 'TK_SEMICOLON']))):
526
+ sep = c
527
+ esc = False
528
+ resulting_string = c
529
+ in_char_class = False
530
+
531
+ if parser_pos < len(self.input):
532
+ if sep == '/':
533
+ # handle regexp
534
+ in_char_class = False
535
+ while esc or in_char_class or self.input[parser_pos] != sep:
536
+ resulting_string += self.input[parser_pos]
537
+ if not esc:
538
+ esc = self.input[parser_pos] == '\\'
539
+ if self.input[parser_pos] == '[':
540
+ in_char_class = True
541
+ elif self.input[parser_pos] == ']':
542
+ in_char_class = False
543
+ else:
544
+ esc = False
545
+ parser_pos += 1
546
+ if parser_pos >= len(self.input):
547
+ # incomplete regex when end-of-file reached
548
+ # bail out with what has received so far
549
+ return resulting_string, 'TK_STRING'
550
+ else:
551
+ # handle string
552
+ while esc or self.input[parser_pos] != sep:
553
+ resulting_string += self.input[parser_pos]
554
+ if not esc:
555
+ esc = self.input[parser_pos] == '\\'
556
+ else:
557
+ esc = False
558
+ parser_pos += 1
559
+ if parser_pos >= len(self.input):
560
+ # incomplete string when end-of-file reached
561
+ # bail out with what has received so far
562
+ return resulting_string, 'TK_STRING'
563
+
564
+
565
+ parser_pos += 1
566
+ resulting_string += sep
567
+ if sep == '/':
568
+ # regexps may have modifiers /regexp/MOD, so fetch those too
569
+ while parser_pos < len(self.input) and self.input[parser_pos] in self.wordchar:
570
+ resulting_string += self.input[parser_pos]
571
+ parser_pos += 1
572
+ return resulting_string, 'TK_STRING'
573
+
574
+ if c == '#':
575
+
576
+ # she-bang
577
+ if len(self.output) == 0 and len(self.input) > 1 and self.input[parser_pos] == '!':
578
+ resulting_string = c
579
+ while parser_pos < len(self.input) and c != '\n':
580
+ c = self.input[parser_pos]
581
+ resulting_string += c
582
+ parser_pos += 1
583
+ self.output.append(resulting_string.strip() + "\n")
584
+ self.append_newline()
585
+ return self.get_next_token()
586
+
587
+
588
+ # Spidermonkey-specific sharp variables for circular references
589
+ # https://developer.mozilla.org/En/Sharp_variables_in_JavaScript
590
+ # http://mxr.mozilla.org/mozilla-central/source/js/src/jsscan.cpp around line 1935
591
+ sharp = '#'
592
+ if parser_pos < len(self.input) and self.input[parser_pos] in self.digits:
593
+ while True:
594
+ c = self.input[parser_pos]
595
+ sharp += c
596
+ parser_pos += 1
597
+ if parser_pos >= len(self.input) or c == '#' or c == '=':
598
+ break
599
+ if c == '#' or parser_pos >= len(self.input):
600
+ pass
601
+ elif self.input[parser_pos] == '[' and self.input[parser_pos + 1] == ']':
602
+ sharp += '[]'
603
+ parser_pos += 2
604
+ elif self.input[parser_pos] == '{' and self.input[parser_pos + 1] == '}':
605
+ sharp += '{}'
606
+ parser_pos += 2
607
+ return sharp, 'TK_WORD'
608
+
609
+ if c == '<' and self.input[parser_pos - 1 : parser_pos + 3] == '<!--':
610
+ parser_pos += 3
611
+ c = '<!--'
612
+ while parser_pos < len(self.input) and self.input[parser_pos] != '\n':
613
+ c += self.input[parser_pos]
614
+ parser_pos += 1
615
+ self.flags.in_html_comment = True
616
+ return c, 'TK_COMMENT'
617
+
618
+ if c == '-' and self.flags.in_html_comment and self.input[parser_pos - 1 : parser_pos + 2] == '-->':
619
+ self.flags.in_html_comment = False
620
+ parser_pos += 2
621
+ if self.wanted_newline:
622
+ self.append_newline()
623
+ return '-->', 'TK_COMMENT'
624
+
625
+ if c in self.punct:
626
+ while parser_pos < len(self.input) and c + self.input[parser_pos] in self.punct:
627
+ c += self.input[parser_pos]
628
+ parser_pos += 1
629
+ if parser_pos >= len(self.input):
630
+ break
631
+ if c == '=':
632
+ return c, 'TK_EQUALS'
633
+ else:
634
+ return c, 'TK_OPERATOR'
635
+ return c, 'TK_UNKNOWN'
636
+
637
+
638
+
639
+ def handle_start_expr(self, token_text):
640
+ if token_text == '[':
641
+ if self.last_type == 'TK_WORD' or self.last_text == ')':
642
+ if self.last_text in self.line_starters:
643
+ self.append(' ')
644
+ self.set_mode('(EXPRESSION)')
645
+ self.append(token_text)
646
+ return
647
+
648
+ if self.flags.mode in ['[EXPRESSION]', '[INDENTED-EXPRESSION]']:
649
+ if self.last_last_text == ']' and self.last_text == ',':
650
+ # ], [ goes to a new line
651
+ if self.flags.mode == '[EXPRESSION]':
652
+ self.flags.mode = '[INDENTED-EXPRESSION]'
653
+ if not self.opts.keep_array_indentation:
654
+ self.indent()
655
+ self.set_mode('[EXPRESSION]')
656
+ if not self.opts.keep_array_indentation:
657
+ self.append_newline()
658
+ elif self.last_text == '[':
659
+ if self.flags.mode == '[EXPRESSION]':
660
+ self.flags.mode = '[INDENTED-EXPRESSION]'
661
+ if not self.opts.keep_array_indentation:
662
+ self.indent()
663
+ self.set_mode('[EXPRESSION]')
664
+
665
+ if not self.opts.keep_array_indentation:
666
+ self.append_newline()
667
+ else:
668
+ self.set_mode('[EXPRESSION]')
669
+ else:
670
+ self.set_mode('[EXPRESSION]')
671
+ else:
672
+ if self.last_text == 'for':
673
+ self.set_mode('(FOR-EXPRESSION)')
674
+ elif self.last_text in ['if', 'while']:
675
+ self.set_mode('(COND-EXPRESSION)')
676
+ else:
677
+ self.set_mode('(EXPRESSION)')
678
+
679
+
680
+ if self.last_text == ';' or self.last_type == 'TK_START_BLOCK':
681
+ self.append_newline()
682
+ elif self.last_type in ['TK_END_EXPR', 'TK_START_EXPR', 'TK_END_BLOCK'] or self.last_text == '.':
683
+ # do nothing on (( and )( and ][ and ]( and .(
684
+ if self.wanted_newline:
685
+ self.append_newline();
686
+ elif self.last_type not in ['TK_WORD', 'TK_OPERATOR']:
687
+ self.append(' ')
688
+ elif self.last_word == 'function' or self.last_word == 'typeof':
689
+ # function() vs function (), typeof() vs typeof ()
690
+ if self.opts.jslint_happy:
691
+ self.append(' ')
692
+ elif self.last_text in self.line_starters or self.last_text == 'catch':
693
+ self.append(' ')
694
+
695
+ self.append(token_text)
696
+
697
+
698
+ def handle_end_expr(self, token_text):
699
+ if token_text == ']':
700
+ if self.opts.keep_array_indentation:
701
+ if self.last_text == '}':
702
+ self.remove_indent()
703
+ self.append(token_text)
704
+ self.restore_mode()
705
+ return
706
+ else:
707
+ if self.flags.mode == '[INDENTED-EXPRESSION]':
708
+ if self.last_text == ']':
709
+ self.restore_mode()
710
+ self.append_newline()
711
+ self.append(token_text)
712
+ return
713
+ self.restore_mode()
714
+ self.append(token_text)
715
+
716
+
717
+ def handle_start_block(self, token_text):
718
+ if self.last_word == 'do':
719
+ self.set_mode('DO_BLOCK')
720
+ else:
721
+ self.set_mode('BLOCK')
722
+
723
+ if self.opts.brace_style == 'expand':
724
+ if self.last_type != 'TK_OPERATOR':
725
+ if self.last_text == '=' or (self.is_special_word(self.last_text) and self.last_text != 'else'):
726
+ self.append(' ')
727
+ else:
728
+ self.append_newline(True)
729
+
730
+ self.append(token_text)
731
+ self.indent()
732
+ else:
733
+ if self.last_type not in ['TK_OPERATOR', 'TK_START_EXPR']:
734
+ if self.last_type == 'TK_START_BLOCK':
735
+ self.append_newline()
736
+ else:
737
+ self.append(' ')
738
+ else:
739
+ # if TK_OPERATOR or TK_START_EXPR
740
+ if self.is_array(self.flags.previous_mode) and self.last_text == ',':
741
+ if self.last_last_text == '}':
742
+ self.append(' ')
743
+ else:
744
+ self.append_newline()
745
+ self.indent()
746
+ self.append(token_text)
747
+
748
+
749
+ def handle_end_block(self, token_text):
750
+ self.restore_mode()
751
+ if self.opts.brace_style == 'expand':
752
+ if self.last_text != '{':
753
+ self.append_newline()
754
+ else:
755
+ if self.last_type == 'TK_START_BLOCK':
756
+ if self.just_added_newline:
757
+ self.remove_indent()
758
+ else:
759
+ # {}
760
+ self.trim_output()
761
+ else:
762
+ if self.is_array(self.flags.mode) and self.opts.keep_array_indentation:
763
+ self.opts.keep_array_indentation = False
764
+ self.append_newline()
765
+ self.opts.keep_array_indentation = True
766
+ else:
767
+ self.append_newline()
768
+
769
+ self.append(token_text)
770
+
771
+
772
+ def handle_word(self, token_text):
773
+ if self.do_block_just_closed:
774
+ self.append(' ')
775
+ self.append(token_text)
776
+ self.append(' ')
777
+ self.do_block_just_closed = False
778
+ return
779
+
780
+ if token_text == 'function':
781
+
782
+ if self.flags.var_line:
783
+ self.flags.var_line_reindented = not self.opts.keep_function_indentation
784
+ if (self.just_added_newline or self.last_text == ';') and self.last_text != '{':
785
+ # make sure there is a nice clean space of at least one blank line
786
+ # before a new function definition
787
+ have_newlines = self.n_newlines
788
+ if not self.just_added_newline:
789
+ have_newlines = 0
790
+ if not self.opts.preserve_newlines:
791
+ have_newlines = 1
792
+ for i in range(2 - have_newlines):
793
+ self.append_newline(False)
794
+
795
+ if token_text == 'case' or (token_text == 'default' and self.flags.in_case_statement):
796
+ if self.last_text == ':':
797
+ self.remove_indent()
798
+ else:
799
+ self.flags.indentation_level -= 1
800
+ self.append_newline()
801
+ self.flags.indentation_level += 1
802
+ self.append(token_text)
803
+ self.flags.in_case = True
804
+ self.flags.in_case_statement = True
805
+ return
806
+
807
+ prefix = 'NONE'
808
+
809
+ if self.last_type == 'TK_END_BLOCK':
810
+ if token_text not in ['else', 'catch', 'finally']:
811
+ prefix = 'NEWLINE'
812
+ else:
813
+ if self.opts.brace_style in ['expand', 'end-expand']:
814
+ prefix = 'NEWLINE'
815
+ else:
816
+ prefix = 'SPACE'
817
+ self.append(' ')
818
+ elif self.last_type == 'TK_SEMICOLON' and self.flags.mode in ['BLOCK', 'DO_BLOCK']:
819
+ prefix = 'NEWLINE'
820
+ elif self.last_type == 'TK_SEMICOLON' and self.is_expression(self.flags.mode):
821
+ prefix = 'SPACE'
822
+ elif self.last_type == 'TK_STRING':
823
+ prefix = 'NEWLINE'
824
+ elif self.last_type == 'TK_WORD':
825
+ if self.last_text == 'else':
826
+ # eat newlines between ...else *** some_op...
827
+ # won't preserve extra newlines in this place (if any), but don't care that much
828
+ self.trim_output(True)
829
+ prefix = 'SPACE'
830
+ elif self.last_type == 'TK_START_BLOCK':
831
+ prefix = 'NEWLINE'
832
+ elif self.last_type == 'TK_END_EXPR':
833
+ self.append(' ')
834
+ prefix = 'NEWLINE'
835
+
836
+ if self.flags.if_line and self.last_type == 'TK_END_EXPR':
837
+ self.flags.if_line = False
838
+
839
+ if token_text in self.line_starters:
840
+ if self.last_text == 'else':
841
+ prefix = 'SPACE'
842
+ else:
843
+ prefix = 'NEWLINE'
844
+
845
+ if token_text == 'function' and self.last_text in ['get', 'set']:
846
+ prefix = 'SPACE'
847
+
848
+ if token_text in ['else', 'catch', 'finally']:
849
+ if self.last_type != 'TK_END_BLOCK' \
850
+ or self.opts.brace_style == 'expand' \
851
+ or self.opts.brace_style == 'end-expand':
852
+ self.append_newline()
853
+ else:
854
+ self.trim_output(True)
855
+ self.append(' ')
856
+ elif prefix == 'NEWLINE':
857
+ if token_text == 'function' and (self.last_type == 'TK_START_EXPR' or self.last_text in '=,'):
858
+ # no need to force newline on "function" -
859
+ # (function...
860
+ pass
861
+ elif token_text == 'function' and self.last_text == 'new':
862
+ self.append(' ')
863
+ elif self.is_special_word(self.last_text):
864
+ # no newline between return nnn
865
+ self.append(' ')
866
+ elif self.last_type != 'TK_END_EXPR':
867
+ if (self.last_type != 'TK_START_EXPR' or token_text != 'var') and self.last_text != ':':
868
+ # no need to force newline on VAR -
869
+ # for (var x = 0...
870
+ if token_text == 'if' and self.last_word == 'else' and self.last_text != '{':
871
+ self.append(' ')
872
+ else:
873
+ self.flags.var_line = False
874
+ self.flags.var_line_reindented = False
875
+ self.append_newline()
876
+ elif token_text in self.line_starters and self.last_text != ')':
877
+ self.flags.var_line = False
878
+ self.flags.var_line_reindented = False
879
+ self.append_newline()
880
+ elif self.is_array(self.flags.mode) and self.last_text == ',' and self.last_last_text == '}':
881
+ self.append_newline() # }, in lists get a newline
882
+ elif prefix == 'SPACE':
883
+ self.append(' ')
884
+
885
+
886
+ self.append(token_text)
887
+ self.last_word = token_text
888
+
889
+ if token_text == 'var':
890
+ self.flags.var_line = True
891
+ self.flags.var_line_reindented = False
892
+ self.flags.var_line_tainted = False
893
+
894
+
895
+ if token_text == 'if':
896
+ self.flags.if_line = True
897
+
898
+ if token_text == 'else':
899
+ self.flags.if_line = False
900
+
901
+
902
+ def handle_semicolon(self, token_text):
903
+ self.append(token_text)
904
+ self.flags.var_line = False
905
+ self.flags.var_line_reindented = False
906
+ if self.flags.mode == 'OBJECT':
907
+ # OBJECT mode is weird and doesn't get reset too well.
908
+ self.flags.mode = 'BLOCK'
909
+
910
+
911
+ def handle_string(self, token_text):
912
+ if self.last_type == 'TK_END_EXPR' and self.flags.previous_mode in ['(COND-EXPRESSION)', '(FOR-EXPRESSION)']:
913
+ self.append(' ')
914
+ if self.last_type in ['TK_STRING', 'TK_START_BLOCK', 'TK_END_BLOCK', 'TK_SEMICOLON']:
915
+ self.append_newline()
916
+ elif self.last_type == 'TK_WORD':
917
+ self.append(' ')
918
+
919
+ # Try to replace readable \x-encoded characters with their equivalent,
920
+ # if it is possible (e.g. '\x41\x42\x43\x01' becomes 'ABC\x01').
921
+ def unescape(match):
922
+ block, code = match.group(0, 1)
923
+ char = chr(int(code, 16))
924
+ if block.count('\\') == 1 and char in string.printable:
925
+ return char
926
+ return block
927
+
928
+ token_text = re.sub(r'\\{1,2}x([a-fA-F0-9]{2})', unescape, token_text)
929
+
930
+ self.append(token_text)
931
+
932
+ def handle_equals(self, token_text):
933
+ if self.flags.var_line:
934
+ # just got an '=' in a var-line, different line breaking rules will apply
935
+ self.flags.var_line_tainted = True
936
+
937
+ self.append(' ')
938
+ self.append(token_text)
939
+ self.append(' ')
940
+
941
+
942
+ def handle_operator(self, token_text):
943
+ space_before = True
944
+ space_after = True
945
+
946
+ if self.flags.var_line and token_text == ',' and self.is_expression(self.flags.mode):
947
+ # do not break on comma, for ( var a = 1, b = 2
948
+ self.flags.var_line_tainted = False
949
+
950
+ if self.flags.var_line and token_text == ',':
951
+ if self.flags.var_line_tainted:
952
+ self.append(token_text)
953
+ self.flags.var_line_reindented = True
954
+ self.flags.var_line_tainted = False
955
+ self.append_newline()
956
+ return
957
+ else:
958
+ self.flags.var_line_tainted = False
959
+
960
+ if self.is_special_word(self.last_text):
961
+ # return had a special handling in TK_WORD
962
+ self.append(' ')
963
+ self.append(token_text)
964
+ return
965
+
966
+ # hack for actionscript's import .*;
967
+ if token_text == '*' and self.last_type == 'TK_UNKNOWN' and not self.last_last_text.isdigit():
968
+ self.append(token_text)
969
+ return
970
+
971
+
972
+ if token_text == ':' and self.flags.in_case:
973
+ self.append(token_text)
974
+ self.append_newline()
975
+ self.flags.in_case = False
976
+ return
977
+
978
+ if token_text == '::':
979
+ # no spaces around the exotic namespacing syntax operator
980
+ self.append(token_text)
981
+ return
982
+
983
+
984
+ if token_text == ',':
985
+ if self.flags.var_line:
986
+ if self.flags.var_line_tainted:
987
+ # This never happens, as it's handled previously, right?
988
+ self.append(token_text)
989
+ self.append_newline()
990
+ self.flags.var_line_tainted = False
991
+ else:
992
+ self.append(token_text)
993
+ self.append(' ')
994
+ elif self.last_type == 'TK_END_BLOCK' and self.flags.mode != '(EXPRESSION)':
995
+ self.append(token_text)
996
+ if self.flags.mode == 'OBJECT' and self.last_text == '}':
997
+ self.append_newline()
998
+ else:
999
+ self.append(' ')
1000
+ else:
1001
+ if self.flags.mode == 'OBJECT':
1002
+ self.append(token_text)
1003
+ self.append_newline()
1004
+ else:
1005
+ # EXPR or DO_BLOCK
1006
+ self.append(token_text)
1007
+ self.append(' ')
1008
+ # comma handled
1009
+ return
1010
+ elif token_text in ['--', '++', '!'] \
1011
+ or (token_text in ['+', '-'] \
1012
+ and (self.last_type in ['TK_START_BLOCK', 'TK_START_EXPR', 'TK_EQUALS', 'TK_OPERATOR'] \
1013
+ or self.last_text in self.line_starters)):
1014
+
1015
+ space_before = False
1016
+ space_after = False
1017
+
1018
+ if self.last_text == ';' and self.is_expression(self.flags.mode):
1019
+ # for (;; ++i)
1020
+ # ^^
1021
+ space_before = True
1022
+
1023
+ if self.last_type == 'TK_WORD' and self.last_text in self.line_starters:
1024
+ space_before = True
1025
+
1026
+ if self.flags.mode == 'BLOCK' and self.last_text in ['{', ';']:
1027
+ # { foo: --i }
1028
+ # foo(): --bar
1029
+ self.append_newline()
1030
+
1031
+ elif token_text == '.':
1032
+ # decimal digits or object.property
1033
+ space_before = False
1034
+
1035
+ elif token_text == ':':
1036
+ if self.flags.ternary_depth == 0:
1037
+ if self.flags.mode == 'BLOCK':
1038
+ self.flags.mode = 'OBJECT'
1039
+ space_before = False
1040
+ else:
1041
+ self.flags.ternary_depth -= 1
1042
+ elif token_text == '?':
1043
+ self.flags.ternary_depth += 1
1044
+
1045
+ if space_before:
1046
+ self.append(' ')
1047
+
1048
+ self.append(token_text)
1049
+
1050
+ if space_after:
1051
+ self.append(' ')
1052
+
1053
+
1054
+
1055
+ def handle_block_comment(self, token_text):
1056
+
1057
+ lines = token_text.replace('\x0d', '').split('\x0a')
1058
+ # all lines start with an asterisk? that's a proper box comment
1059
+ if not any(l for l in lines[1:] if ( l.strip() == '' or (l.lstrip())[0] != '*')):
1060
+ self.append_newline()
1061
+ self.append(lines[0])
1062
+ for line in lines[1:]:
1063
+ self.append_newline()
1064
+ self.append(' ' + line.strip())
1065
+ else:
1066
+ # simple block comment: leave intact
1067
+ if len(lines) > 1:
1068
+ # multiline comment starts on a new line
1069
+ self.append_newline()
1070
+ else:
1071
+ # single line /* ... */ comment stays on the same line
1072
+ self.append(' ')
1073
+ for line in lines:
1074
+ self.append(line)
1075
+ self.append('\n')
1076
+ self.append_newline()
1077
+
1078
+
1079
+ def handle_inline_comment(self, token_text):
1080
+ self.append(' ')
1081
+ self.append(token_text)
1082
+ if self.is_expression(self.flags.mode):
1083
+ self.append(' ')
1084
+ else:
1085
+ self.append_newline_forced()
1086
+
1087
+
1088
+ def handle_comment(self, token_text):
1089
+ if self.last_type == 'TK_COMMENT':
1090
+ self.append_newline()
1091
+ if self.wanted_newline:
1092
+ self.append_newline(False)
1093
+ else:
1094
+ if self.wanted_newline:
1095
+ self.append_newline()
1096
+ else:
1097
+ self.append(' ')
1098
+
1099
+ self.append(token_text)
1100
+ self.append_newline_forced()
1101
+
1102
+
1103
+ def handle_unknown(self, token_text):
1104
+ if self.last_text in ['return', 'throw']:
1105
+ self.append(' ')
1106
+
1107
+ self.append(token_text)
1108
+
1109
+
1110
+
1111
+
1112
+
1113
+ def main():
1114
+
1115
+ argv = sys.argv[1:]
1116
+
1117
+ try:
1118
+ opts, args = getopt.getopt(argv, "s:c:o:djbkil:htf", ['indent-size=','indent-char=','outfile=', 'disable-preserve-newlines',
1119
+ 'jslint-happy', 'brace-style=',
1120
+ 'keep-array-indentation', 'indent-level=', 'help',
1121
+ 'usage', 'stdin', 'eval-code', 'indent-with-tabs', 'keep-function-indentation'])
1122
+ except getopt.GetoptError:
1123
+ return usage()
1124
+
1125
+ js_options = default_options()
1126
+
1127
+ file = None
1128
+ outfile = 'stdout'
1129
+ if len(args) == 1:
1130
+ file = args[0]
1131
+
1132
+ for opt, arg in opts:
1133
+ if opt in ('--keep-array-indentation', '-k'):
1134
+ js_options.keep_array_indentation = True
1135
+ if opt in ('--keep-function-indentation','-f'):
1136
+ js_options.keep_function_indentation = True
1137
+ elif opt in ('--outfile', '-o'):
1138
+ outfile = arg
1139
+ elif opt in ('--indent-size', '-s'):
1140
+ js_options.indent_size = int(arg)
1141
+ elif opt in ('--indent-char', '-c'):
1142
+ js_options.indent_char = arg
1143
+ elif opt in ('--indent-with-tabs', '-t'):
1144
+ js_options.indent_with_tabs = True
1145
+ elif opt in ('--disable-preserve_newlines', '-d'):
1146
+ js_options.preserve_newlines = False
1147
+ elif opt in ('--jslint-happy', '-j'):
1148
+ js_options.jslint_happy = True
1149
+ elif opt in ('--eval-code'):
1150
+ js_options.eval_code = True
1151
+ elif opt in ('--brace-style', '-b'):
1152
+ js_options.brace_style = arg
1153
+ elif opt in ('--stdin', '-i'):
1154
+ file = '-'
1155
+ elif opt in ('--help', '--usage', '-h'):
1156
+ return usage()
1157
+
1158
+ if not file:
1159
+ return usage()
1160
+ else:
1161
+ if outfile == 'stdout':
1162
+ print(beautify_file(file, js_options))
1163
+ else:
1164
+ with open(outfile, 'w') as f:
1165
+ f.write(beautify_file(file, js_options) + '\n')
1166
+