js-beautify 1.14.1 → 1.14.4

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
@@ -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.1/beautify.js"></script>
62
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.1/beautify-css.js"></script>
63
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.1/beautify-html.js"></script>
61
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.4/beautify.js"></script>
62
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.4/beautify-css.js"></script>
63
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.4/beautify-html.js"></script>
64
64
 
65
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.1/beautify.min.js"></script>
66
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.1/beautify-css.min.js"></script>
67
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.1/beautify-html.min.js"></script>
68
-
69
- <script src="https://cdn.rawgit.com/beautify-web/js-beautify/v1.14.1/js/lib/beautify.js"></script>
70
- <script src="https://cdn.rawgit.com/beautify-web/js-beautify/v1.14.1/js/lib/beautify-css.js"></script>
71
- <script src="https://cdn.rawgit.com/beautify-web/js-beautify/v1.14.1/js/lib/beautify-html.js"></script>
65
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.4/beautify.min.js"></script>
66
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.4/beautify-css.min.js"></script>
67
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.4/beautify-html.min.js"></script>
72
68
  ```
73
69
 
74
70
  Older versions are available by changing the version number.
@@ -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.1)
400
+ (README.md: js-beautify@1.14.4)
@@ -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