js-beautify 1.14.2 → 1.14.5

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.
package/README.md CHANGED
@@ -26,7 +26,7 @@ If you are interested, please take a look at the [CONTRIBUTING.md](https://githu
26
26
 
27
27
  # Installation
28
28
 
29
- You can install the beautifier for node.js or python.
29
+ You can install the beautifier for Node.js or Python.
30
30
 
31
31
  ## Node.js JavaScript
32
32
 
@@ -58,17 +58,13 @@ JS Beautifier is hosted on two CDN services: [cdnjs](https://cdnjs.com/libraries
58
58
 
59
59
  To pull the latest version from one of these services include one set of the script tags below in your document:
60
60
  ```html
61
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.2/beautify.js"></script>
62
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.2/beautify-css.js"></script>
63
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.2/beautify-html.js"></script>
61
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.5/beautify.js"></script>
62
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.5/beautify-css.js"></script>
63
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.5/beautify-html.js"></script>
64
64
 
65
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.2/beautify.min.js"></script>
66
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.2/beautify-css.min.js"></script>
67
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.2/beautify-html.min.js"></script>
68
-
69
- <script src="https://cdn.rawgit.com/beautify-web/js-beautify/v1.14.2/js/lib/beautify.js"></script>
70
- <script src="https://cdn.rawgit.com/beautify-web/js-beautify/v1.14.2/js/lib/beautify-css.js"></script>
71
- <script src="https://cdn.rawgit.com/beautify-web/js-beautify/v1.14.2/js/lib/beautify-html.js"></script>
65
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.5/beautify.min.js"></script>
66
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.5/beautify-css.min.js"></script>
67
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.5/beautify-html.min.js"></script>
72
68
  ```
73
69
 
74
70
  Older versions are available by changing the version number.
@@ -89,7 +85,7 @@ $ pip install cssbeautifier
89
85
  ```
90
86
 
91
87
  # Usage
92
- You can beautify javascript using JS Beautifier in your web browser, or on the command-line using node.js or python.
88
+ You can beautify JavaScript using JS Beautifier in your web browser, or on the command-line using Node.js or Python.
93
89
 
94
90
  ## Web Browser
95
91
  Open [beautifier.io](https://beautifier.io/). Options are available via the UI.
@@ -105,7 +101,7 @@ When installed globally, the beautifier provides an executable `js-beautify` scr
105
101
  $ js-beautify foo.js
106
102
  ```
107
103
 
108
- To use `js-beautify` as a `node` library (after install locally), import and call the appropriate beautifier method for javascript (js), css, or html. All three method signatures are `beautify(code, options)`. `code` is the string of code to be beautified. options is an object with the settings you would like used to beautify the code.
104
+ To use `js-beautify` as a `node` library (after install locally), import and call the appropriate beautifier method for JavaScript (JS), CSS, or HTML. All three method signatures are `beautify(code, options)`. `code` is the string of code to be beautified. options is an object with the settings you would like used to beautify the code.
109
105
 
110
106
  The configuration option names are the same as the CLI names but with underscores instead of dashes. For example, `--indent-size 2 --space-in-empty-paren` would be `{ indent_size: 2, space_in_empty_paren: true }`.
111
107
 
@@ -134,7 +130,7 @@ To use `jsbeautifier` as a library is simple:
134
130
 
135
131
  ```python
136
132
  import jsbeautifier
137
- res = jsbeautifier.beautify('your javascript string')
133
+ res = jsbeautifier.beautify('your JavaScript string')
138
134
  res = jsbeautifier.beautify_file('some_file.js')
139
135
  ```
140
136
 
@@ -144,7 +140,7 @@ res = jsbeautifier.beautify_file('some_file.js')
144
140
  opts = jsbeautifier.default_options()
145
141
  opts.indent_size = 2
146
142
  opts.space_in_empty_paren = True
147
- res = jsbeautifier.beautify('some javascript', opts)
143
+ res = jsbeautifier.beautify('some JavaScript', opts)
148
144
  ```
149
145
 
150
146
  The configuration option names are the same as the CLI names but with underscores instead of dashes. The example above would be set on the command-line as `--indent-size 2 --space-in-empty-paren`.
@@ -192,7 +188,7 @@ Beautifier Options:
192
188
  -C, --comma-first Put commas at the beginning of new line instead of end
193
189
  -O, --operator-position Set operator position (before-newline|after-newline|preserve-newline) [before-newline]
194
190
  --indent-empty-lines Keep indentation on empty lines
195
- --templating List of templating languages (auto,django,erb,handlebars,php,smarty) ["auto"] auto = none in JavaScript, all in html
191
+ --templating List of templating languages (auto,django,erb,handlebars,php,smarty) ["auto"] auto = none in JavaScript, all in HTML
196
192
  ```
197
193
 
198
194
  Which correspond to the underscored option keys for both library interfaces
@@ -255,7 +251,7 @@ Configuration sources provided earlier in this stack will override later ones.
255
251
 
256
252
  The settings are a shallow tree whose values are inherited for all languages, but
257
253
  can be overridden. This works for settings passed directly to the API in either implementation.
258
- In the Javascript implementation, settings loaded from a config file, such as .jsbeautifyrc, can also use inheritance/overriding.
254
+ In the JavaScript implementation, settings loaded from a config file, such as .jsbeautifyrc, can also use inheritance/overriding.
259
255
 
260
256
  Below is an example configuration tree showing all the supported locations
261
257
  for language override nodes. We'll use `indent_size` to discuss how this configuration would behave, but any number of settings can be inherited or overridden:
@@ -401,4 +397,4 @@ Thanks also to Jason Diamond, Patrick Hof, Nochum Sossonko, Andreas Schneider, D
401
397
  Vasilevsky, Vital Batmanov, Ron Baldwin, Gabriel Harrison, Chris J. Shull,
402
398
  Mathias Bynens, Vittorio Gambaletta and others.
403
399
 
404
- (README.md: js-beautify@1.14.2)
400
+ (README.md: js-beautify@1.14.5)
@@ -299,6 +299,7 @@ Beautifier.prototype.create_flags = function(flags_base, mode) {
299
299
  inline_frame: false,
300
300
  if_block: false,
301
301
  else_block: false,
302
+ class_start_block: false, // class A { INSIDE HERE } or class B extends C { INSIDE HERE }
302
303
  do_block: false,
303
304
  do_while: false,
304
305
  import_block: false,
@@ -711,6 +712,8 @@ Beautifier.prototype.handle_start_expr = function(current_token) {
711
712
  (peek_back_two.text === '*' && (peek_back_three.text === '{' || peek_back_three.text === ','))) {
712
713
  this._output.space_before_token = true;
713
714
  }
715
+ } else if (this._flags.parent && this._flags.parent.class_start_block) {
716
+ this._output.space_before_token = true;
714
717
  }
715
718
  }
716
719
  } else {
@@ -805,10 +808,10 @@ Beautifier.prototype.handle_start_block = function(current_token) {
805
808
  )) {
806
809
  // We don't support TypeScript,but we didn't break it for a very long time.
807
810
  // We'll try to keep not breaking it.
808
- if (!in_array(this._last_last_text, ['class', 'interface'])) {
809
- this.set_mode(MODE.ObjectLiteral);
810
- } else {
811
+ if (in_array(this._last_last_text, ['class', 'interface']) && !in_array(second_token.text, [':', ','])) {
811
812
  this.set_mode(MODE.BlockStatement);
813
+ } else {
814
+ this.set_mode(MODE.ObjectLiteral);
812
815
  }
813
816
  } else if (this._flags.last_token.type === TOKEN.OPERATOR && this._flags.last_token.text === '=>') {
814
817
  // arrow function: (param1, paramN) => { statements }
@@ -825,6 +828,12 @@ Beautifier.prototype.handle_start_block = function(current_token) {
825
828
  this.set_mode(MODE.BlockStatement);
826
829
  }
827
830
 
831
+ if (this._flags.last_token) {
832
+ if (reserved_array(this._flags.last_token.previous, ['class', 'extends'])) {
833
+ this._flags.class_start_block = true;
834
+ }
835
+ }
836
+
828
837
  var empty_braces = !next_token.comments_before && next_token.text === '}';
829
838
  var empty_anonymous_function = empty_braces && this._flags.last_word === 'function' &&
830
839
  this._flags.last_token.type === TOKEN.END_EXPR;
@@ -924,7 +933,7 @@ Beautifier.prototype.handle_word = function(current_token) {
924
933
  if (current_token.type === TOKEN.RESERVED) {
925
934
  if (in_array(current_token.text, ['set', 'get']) && this._flags.mode !== MODE.ObjectLiteral) {
926
935
  current_token.type = TOKEN.WORD;
927
- } else if (current_token.text === 'import' && this._tokens.peek().text === '(') {
936
+ } else if (current_token.text === 'import' && in_array(this._tokens.peek().text, ['(', '.'])) {
928
937
  current_token.type = TOKEN.WORD;
929
938
  } else if (in_array(current_token.text, ['as', 'from']) && !this._flags.import_block) {
930
939
  current_token.type = TOKEN.WORD;
@@ -1265,13 +1274,6 @@ Beautifier.prototype.handle_operator = function(current_token) {
1265
1274
  this.handle_whitespace_and_comments(current_token, preserve_statement_flags);
1266
1275
  }
1267
1276
 
1268
- if (reserved_array(this._flags.last_token, special_words)) {
1269
- // "return" had a special handling in TK_WORD. Now we need to return the favor
1270
- this._output.space_before_token = true;
1271
- this.print_token(current_token);
1272
- return;
1273
- }
1274
-
1275
1277
  // hack for actionscript's import .*;
1276
1278
  if (current_token.text === '*' && this._flags.last_token.type === TOKEN.DOT) {
1277
1279
  this.print_token(current_token);
@@ -1399,7 +1401,11 @@ Beautifier.prototype.handle_operator = function(current_token) {
1399
1401
  // http://www.ecma-international.org/ecma-262/5.1/#sec-7.9.1
1400
1402
  // if there is a newline between -- or ++ and anything else we should preserve it.
1401
1403
  if (current_token.newlines && (current_token.text === '--' || current_token.text === '++' || current_token.text === '~')) {
1402
- this.print_newline(false, true);
1404
+ var new_line_needed = reserved_array(this._flags.last_token, special_words) && current_token.newlines;
1405
+ if (new_line_needed && (this._previous_flags.if_block || this._previous_flags.else_block)) {
1406
+ this.restore_mode();
1407
+ }
1408
+ this.print_newline(new_line_needed, true);
1403
1409
  }
1404
1410
 
1405
1411
  if (this._flags.last_token.text === ';' && is_expression(this._flags.mode)) {
@@ -1539,6 +1545,10 @@ Beautifier.prototype.handle_dot = function(current_token) {
1539
1545
  this.handle_whitespace_and_comments(current_token, true);
1540
1546
  }
1541
1547
 
1548
+ if (this._flags.last_token.text.match('^[0-9]+$')) {
1549
+ this._output.space_before_token = true;
1550
+ }
1551
+
1542
1552
  if (reserved_array(this._flags.last_token, special_words)) {
1543
1553
  this._output.space_before_token = false;
1544
1554
  } else {
@@ -2502,7 +2512,7 @@ var digit = /[0-9]/;
2502
2512
  var dot_pattern = /[^\d\.]/;
2503
2513
 
2504
2514
  var positionable_operators = (
2505
- ">>> === !== " +
2515
+ ">>> === !== &&= ??= ||= " +
2506
2516
  "<< && >= ** != == <= >> || ?? |> " +
2507
2517
  "< / - + > : & % ? ^ | *").split(' ');
2508
2518
 
@@ -2510,7 +2520,7 @@ var positionable_operators = (
2510
2520
  // Also, you must update possitionable operators separately from punct
2511
2521
  var punct =
2512
2522
  ">>>= " +
2513
- "... >>= <<= === >>> !== **= " +
2523
+ "... >>= <<= === >>> !== **= &&= ??= ||= " +
2514
2524
  "=> ^= :: /= << <= == && -= >= >> != -- += ** || ?? ++ %= &= *= |= |> " +
2515
2525
  "= ! ? > < : / ^ - + * & % ~ |";
2516
2526
 
@@ -2523,7 +2533,7 @@ var punct_pattern = new RegExp(punct);
2523
2533
 
2524
2534
  // words which should always start on new line.
2525
2535
  var line_starters = 'continue,try,throw,return,var,let,const,if,switch,case,default,for,while,break,function,import,export'.split(',');
2526
- var reserved_words = line_starters.concat(['do', 'in', 'of', 'else', 'get', 'set', 'new', 'catch', 'finally', 'typeof', 'yield', 'async', 'await', 'from', 'as']);
2536
+ var reserved_words = line_starters.concat(['do', 'in', 'of', 'else', 'get', 'set', 'new', 'catch', 'finally', 'typeof', 'yield', 'async', 'await', 'from', 'as', 'class', 'extends']);
2527
2537
  var reserved_word_pattern = new RegExp('^(?:' + reserved_words.join('|') + ')$');
2528
2538
 
2529
2539
  // var template_pattern = /(?:(?:<\?php|<\?=)[\s\S]*?\?>)|(?:<%[\s\S]*?%>)/g;
@@ -2614,7 +2624,8 @@ Tokenizer.prototype._read_word = function(previous_token) {
2614
2624
  if (!(previous_token.type === TOKEN.DOT ||
2615
2625
  (previous_token.type === TOKEN.RESERVED && (previous_token.text === 'set' || previous_token.text === 'get'))) &&
2616
2626
  reserved_word_pattern.test(resulting_string)) {
2617
- if (resulting_string === 'in' || resulting_string === 'of') { // hack for 'in' and 'of' operators
2627
+ if ((resulting_string === 'in' || resulting_string === 'of') &&
2628
+ (previous_token.type === TOKEN.WORD || previous_token.type === TOKEN.STRING)) { // hack for 'in' and 'of' operators
2618
2629
  return this._create_token(TOKEN.OPERATOR, resulting_string);
2619
2630
  }
2620
2631
  return this._create_token(TOKEN.RESERVED, resulting_string);
@@ -4039,6 +4050,10 @@ function Beautifier(source_text, options) {
4039
4050
  "@supports": true,
4040
4051
  "@document": true
4041
4052
  };
4053
+ this.NON_SEMICOLON_NEWLINE_PROPERTY = [
4054
+ "grid-template-areas",
4055
+ "grid-template"
4056
+ ];
4042
4057
 
4043
4058
  }
4044
4059
 
@@ -4163,7 +4178,9 @@ Beautifier.prototype.beautify = function() {
4163
4178
  var enteringConditionalGroup = false;
4164
4179
  var insideAtExtend = false;
4165
4180
  var insideAtImport = false;
4181
+ var insideScssMap = false;
4166
4182
  var topCharacter = this._ch;
4183
+ var insideNonSemiColonValues = false;
4167
4184
  var whitespace;
4168
4185
  var isAfterSpace;
4169
4186
  var previous_ch;
@@ -4215,7 +4232,7 @@ Beautifier.prototype.beautify = function() {
4215
4232
 
4216
4233
  // Ensures any new lines following the comment are preserved
4217
4234
  this.eatWhitespace(true);
4218
- } else if (this._ch === '@') {
4235
+ } else if (this._ch === '@' || this._ch === '$') {
4219
4236
  this.preserveSingleSpace(isAfterSpace);
4220
4237
 
4221
4238
  // deal with less propery mixins @{...}
@@ -4286,7 +4303,12 @@ Beautifier.prototype.beautify = function() {
4286
4303
  this.indent();
4287
4304
  this._output.set_indent(this._indentLevel);
4288
4305
  } else {
4289
- this.indent();
4306
+ // inside mixin and first param is object
4307
+ if (previous_ch === '(') {
4308
+ this._output.space_before_token = false;
4309
+ } else if (previous_ch !== ',') {
4310
+ this.indent();
4311
+ }
4290
4312
  this.print_string(this._ch);
4291
4313
  }
4292
4314
 
@@ -4318,7 +4340,21 @@ Beautifier.prototype.beautify = function() {
4318
4340
  this._output.add_new_line(true);
4319
4341
  }
4320
4342
  }
4343
+ if (this._input.peek() === ')') {
4344
+ this._output.trim(true);
4345
+ if (this._options.brace_style === "expand") {
4346
+ this._output.add_new_line(true);
4347
+ }
4348
+ }
4321
4349
  } else if (this._ch === ":") {
4350
+
4351
+ for (var i = 0; i < this.NON_SEMICOLON_NEWLINE_PROPERTY.length; i++) {
4352
+ if (this._input.lookBack(this.NON_SEMICOLON_NEWLINE_PROPERTY[i])) {
4353
+ insideNonSemiColonValues = true;
4354
+ break;
4355
+ }
4356
+ }
4357
+
4322
4358
  if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideAtExtend && parenLevel === 0) {
4323
4359
  // 'property: value' delimiter
4324
4360
  // which could be in a conditional group query
@@ -4347,10 +4383,12 @@ Beautifier.prototype.beautify = function() {
4347
4383
  }
4348
4384
  }
4349
4385
  } else if (this._ch === '"' || this._ch === '\'') {
4350
- this.preserveSingleSpace(isAfterSpace);
4386
+ var preserveQuoteSpace = previous_ch === '"' || previous_ch === '\'';
4387
+ this.preserveSingleSpace(preserveQuoteSpace || isAfterSpace);
4351
4388
  this.print_string(this._ch + this.eatString(this._ch));
4352
4389
  this.eatWhitespace(true);
4353
4390
  } else if (this._ch === ';') {
4391
+ insideNonSemiColonValues = false;
4354
4392
  if (parenLevel === 0) {
4355
4393
  if (insidePropertyValue) {
4356
4394
  this.outdent();
@@ -4390,22 +4428,39 @@ Beautifier.prototype.beautify = function() {
4390
4428
  }
4391
4429
  }
4392
4430
  } else {
4393
- this.preserveSingleSpace(isAfterSpace);
4431
+ var space_needed = false;
4432
+ if (this._input.lookBack("with")) {
4433
+ // look back is not an accurate solution, we need tokens to confirm without whitespaces
4434
+ space_needed = true;
4435
+ }
4436
+ this.preserveSingleSpace(isAfterSpace || space_needed);
4394
4437
  this.print_string(this._ch);
4395
- this.eatWhitespace();
4396
- parenLevel++;
4397
- this.indent();
4438
+
4439
+ // handle scss/sass map
4440
+ if (insidePropertyValue && previous_ch === "$" && this._options.selector_separator_newline) {
4441
+ this._output.add_new_line();
4442
+ insideScssMap = true;
4443
+ } else {
4444
+ this.eatWhitespace();
4445
+ parenLevel++;
4446
+ this.indent();
4447
+ }
4398
4448
  }
4399
4449
  } else if (this._ch === ')') {
4400
4450
  if (parenLevel) {
4401
4451
  parenLevel--;
4402
4452
  this.outdent();
4403
4453
  }
4454
+ if (insideScssMap && this._input.peek() === ";" && this._options.selector_separator_newline) {
4455
+ insideScssMap = false;
4456
+ this.outdent();
4457
+ this._output.add_new_line();
4458
+ }
4404
4459
  this.print_string(this._ch);
4405
4460
  } else if (this._ch === ',') {
4406
4461
  this.print_string(this._ch);
4407
4462
  this.eatWhitespace(true);
4408
- if (this._options.selector_separator_newline && !insidePropertyValue && parenLevel === 0 && !insideAtImport && !insideAtExtend) {
4463
+ if (this._options.selector_separator_newline && (!insidePropertyValue || insideScssMap) && parenLevel === 0 && !insideAtImport && !insideAtExtend) {
4409
4464
  this._output.add_new_line();
4410
4465
  } else {
4411
4466
  this._output.space_before_token = true;
@@ -4436,11 +4491,16 @@ Beautifier.prototype.beautify = function() {
4436
4491
  this._ch = '';
4437
4492
  }
4438
4493
  } else if (this._ch === '!' && !this._input.lookBack("\\")) { // !important
4439
- this.print_string(' ');
4494
+ this._output.space_before_token = true;
4440
4495
  this.print_string(this._ch);
4441
4496
  } else {
4442
- this.preserveSingleSpace(isAfterSpace);
4497
+ var preserveAfterSpace = previous_ch === '"' || previous_ch === '\'';
4498
+ this.preserveSingleSpace(preserveAfterSpace || isAfterSpace);
4443
4499
  this.print_string(this._ch);
4500
+
4501
+ if (!this._output.just_added_newline() && this._input.peek() === '\n' && insideNonSemiColonValues) {
4502
+ this._output.add_new_line();
4503
+ }
4444
4504
  }
4445
4505
  }
4446
4506
 
@@ -5175,14 +5235,19 @@ var TagOpenParserToken = function(parent, raw_token) {
5175
5235
  tag_check_match = raw_token.text.match(/^<([^\s>]*)/);
5176
5236
  this.tag_check = tag_check_match ? tag_check_match[1] : '';
5177
5237
  } else {
5178
- tag_check_match = raw_token.text.match(/^{{(?:[\^]|#\*?)?([^\s}]+)/);
5238
+ tag_check_match = raw_token.text.match(/^{{~?(?:[\^]|#\*?)?([^\s}]+)/);
5179
5239
  this.tag_check = tag_check_match ? tag_check_match[1] : '';
5180
5240
 
5181
- // handle "{{#> myPartial}}
5182
- if (raw_token.text === '{{#>' && this.tag_check === '>' && raw_token.next !== null) {
5183
- this.tag_check = raw_token.next.text.split(' ')[0];
5241
+ // handle "{{#> myPartial}}" or "{{~#> myPartial}}"
5242
+ if ((raw_token.text.startsWith('{{#>') || raw_token.text.startsWith('{{~#>')) && this.tag_check[0] === '>') {
5243
+ if (this.tag_check === '>' && raw_token.next !== null) {
5244
+ this.tag_check = raw_token.next.text.split(' ')[0];
5245
+ } else {
5246
+ this.tag_check = raw_token.text.split('>')[1];
5247
+ }
5184
5248
  }
5185
5249
  }
5250
+
5186
5251
  this.tag_check = this.tag_check.toLowerCase();
5187
5252
 
5188
5253
  if (raw_token.type === TOKEN.COMMENT) {
@@ -5194,9 +5259,17 @@ var TagOpenParserToken = function(parent, raw_token) {
5194
5259
  this.is_end_tag = !this.is_start_tag ||
5195
5260
  (raw_token.closed && raw_token.closed.text === '/>');
5196
5261
 
5262
+ // if whitespace handler ~ included (i.e. {{~#if true}}), handlebars tags start at pos 3 not pos 2
5263
+ var handlebar_starts = 2;
5264
+ if (this.tag_start_char === '{' && this.text.length >= 3) {
5265
+ if (this.text.charAt(2) === '~') {
5266
+ handlebar_starts = 3;
5267
+ }
5268
+ }
5269
+
5197
5270
  // handlebars tags that don't start with # or ^ are single_tags, and so also start and end.
5198
5271
  this.is_end_tag = this.is_end_tag ||
5199
- (this.tag_start_char === '{' && (this.text.length < 3 || (/[^#\^]/.test(this.text.charAt(2)))));
5272
+ (this.tag_start_char === '{' && (this.text.length < 3 || (/[^#\^]/.test(this.text.charAt(handlebar_starts)))));
5200
5273
  }
5201
5274
  };
5202
5275