js-beautify 1.14.7 → 1.14.9

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,13 +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.7/beautify.js"></script>
62
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.7/beautify-css.js"></script>
63
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.7/beautify-html.js"></script>
61
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.9/beautify.js"></script>
62
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.9/beautify-css.js"></script>
63
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.9/beautify-html.js"></script>
64
64
 
65
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.7/beautify.min.js"></script>
66
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.7/beautify-css.min.js"></script>
67
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.7/beautify-html.min.js"></script>
65
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.9/beautify.min.js"></script>
66
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.9/beautify-css.min.js"></script>
67
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.9/beautify-html.min.js"></script>
68
68
  ```
69
69
 
70
70
  Example usage of a JS tag in html:
@@ -76,7 +76,7 @@ Example usage of a JS tag in html:
76
76
 
77
77
  . . .
78
78
 
79
- <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.7/beautify.min.js"></script>
79
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.9/beautify.min.js"></script>
80
80
  <script src="script.js"></script>
81
81
  </body>
82
82
  </html>
@@ -141,7 +141,7 @@ To use `js-beautify` as a `node` library (after install locally), import and cal
141
141
  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 }`.
142
142
 
143
143
  ```js
144
- var beautify = require('js-beautify').js,
144
+ var beautify = require('js-beautify/js').js,
145
145
  fs = require('fs');
146
146
 
147
147
  fs.readFile('foo.js', 'utf8', function (err, data) {
@@ -368,8 +368,10 @@ HTML Beautifier Options:
368
368
  -S, --indent-scripts [keep|separate|normal] ["normal"]
369
369
  -w, --wrap-line-length Maximum characters per line (0 disables) [250]
370
370
  -A, --wrap-attributes Wrap attributes to new lines [auto|force|force-aligned|force-expand-multiline|aligned-multiple|preserve|preserve-aligned] ["auto"]
371
+ -M, --wrap-attributes-min-attrs Minimum number of html tag attributes for force wrap attribute options [2]
371
372
  -i, --wrap-attributes-indent-size Indent wrapped attributes to after N characters [indent-size] (ignored if wrap-attributes is "aligned")
372
373
  -d, --inline List of tags to be considered inline tags
374
+ --inline_custom_elements Inline custom elements [true]
373
375
  -U, --unformatted List of tags (defaults to inline) that should not be reformatted
374
376
  -T, --content_unformatted List of tags (defaults to pre) whose content should not be reformatted
375
377
  -E, --extra_liners List of tags (defaults to [head,body,/html] that should have an extra newline before them.
@@ -432,4 +434,4 @@ Thanks also to Jason Diamond, Patrick Hof, Nochum Sossonko, Andreas Schneider, D
432
434
  Vasilevsky, Vital Batmanov, Ron Baldwin, Gabriel Harrison, Chris J. Shull,
433
435
  Mathias Bynens, Vittorio Gambaletta and others.
434
436
 
435
- (README.md: js-beautify@1.14.7)
437
+ (README.md: js-beautify@1.14.9)
@@ -879,7 +879,7 @@ Beautifier.prototype.handle_start_block = function(current_token) {
879
879
  }
880
880
  }
881
881
  if (this._flags.last_token.type !== TOKEN.OPERATOR && this._flags.last_token.type !== TOKEN.START_EXPR) {
882
- if (this._flags.last_token.type === TOKEN.START_BLOCK && !this._flags.inline_frame) {
882
+ if (in_array(this._flags.last_token.type, [TOKEN.START_BLOCK, TOKEN.SEMICOLON]) && !this._flags.inline_frame) {
883
883
  this.print_newline();
884
884
  } else {
885
885
  this._output.space_before_token = true;
@@ -2605,6 +2605,7 @@ Tokenizer.prototype._get_next_token = function(previous_token, open_token) { //
2605
2605
 
2606
2606
  token = token || this._read_non_javascript(c);
2607
2607
  token = token || this._read_string(c);
2608
+ token = token || this._read_pair(c, this._input.peek(1)); // Issue #2062 hack for record type '#{'
2608
2609
  token = token || this._read_word(previous_token);
2609
2610
  token = token || this._read_singles(c);
2610
2611
  token = token || this._read_comment(c);
@@ -2663,6 +2664,19 @@ Tokenizer.prototype._read_singles = function(c) {
2663
2664
  return token;
2664
2665
  };
2665
2666
 
2667
+ Tokenizer.prototype._read_pair = function(c, d) {
2668
+ var token = null;
2669
+ if (c === '#' && d === '{') {
2670
+ token = this._create_token(TOKEN.START_BLOCK, c + d);
2671
+ }
2672
+
2673
+ if (token) {
2674
+ this._input.next();
2675
+ this._input.next();
2676
+ }
2677
+ return token;
2678
+ };
2679
+
2666
2680
  Tokenizer.prototype._read_punctuation = function() {
2667
2681
  var resulting_string = this.__patterns.punct.read();
2668
2682
 
@@ -4037,18 +4051,18 @@ function Beautifier(source_text, options) {
4037
4051
 
4038
4052
  // https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
4039
4053
  this.NESTED_AT_RULE = {
4040
- "@page": true,
4041
- "@font-face": true,
4042
- "@keyframes": true,
4054
+ "page": true,
4055
+ "font-face": true,
4056
+ "keyframes": true,
4043
4057
  // also in CONDITIONAL_GROUP_RULE below
4044
- "@media": true,
4045
- "@supports": true,
4046
- "@document": true
4058
+ "media": true,
4059
+ "supports": true,
4060
+ "document": true
4047
4061
  };
4048
4062
  this.CONDITIONAL_GROUP_RULE = {
4049
- "@media": true,
4050
- "@supports": true,
4051
- "@document": true
4063
+ "media": true,
4064
+ "supports": true,
4065
+ "document": true
4052
4066
  };
4053
4067
  this.NON_SEMICOLON_NEWLINE_PROPERTY = [
4054
4068
  "grid-template-areas",
@@ -4176,8 +4190,7 @@ Beautifier.prototype.beautify = function() {
4176
4190
  // label { content: blue }
4177
4191
  var insidePropertyValue = false;
4178
4192
  var enteringConditionalGroup = false;
4179
- var insideAtExtend = false;
4180
- var insideAtImport = false;
4193
+ var insideNonNestedAtRule = false;
4181
4194
  var insideScssMap = false;
4182
4195
  var topCharacter = this._ch;
4183
4196
  var insideNonSemiColonValues = false;
@@ -4232,10 +4245,32 @@ Beautifier.prototype.beautify = function() {
4232
4245
 
4233
4246
  // Ensures any new lines following the comment are preserved
4234
4247
  this.eatWhitespace(true);
4235
- } else if (this._ch === '@' || this._ch === '$') {
4248
+ } else if (this._ch === '$') {
4249
+ this.preserveSingleSpace(isAfterSpace);
4250
+
4251
+ this.print_string(this._ch);
4252
+
4253
+ // strip trailing space, if present, for hash property checks
4254
+ var variable = this._input.peekUntilAfter(/[: ,;{}()[\]\/='"]/g);
4255
+
4256
+ if (variable.match(/[ :]$/)) {
4257
+ // we have a variable or pseudo-class, add it and insert one space before continuing
4258
+ variable = this.eatString(": ").replace(/\s$/, '');
4259
+ this.print_string(variable);
4260
+ this._output.space_before_token = true;
4261
+ }
4262
+
4263
+ variable = variable.replace(/\s$/, '');
4264
+
4265
+ // might be sass variable
4266
+ if (parenLevel === 0 && variable.indexOf(':') !== -1) {
4267
+ insidePropertyValue = true;
4268
+ this.indent();
4269
+ }
4270
+ } else if (this._ch === '@') {
4236
4271
  this.preserveSingleSpace(isAfterSpace);
4237
4272
 
4238
- // deal with less propery mixins @{...}
4273
+ // deal with less property mixins @{...}
4239
4274
  if (this._input.peek() === '{') {
4240
4275
  this.print_string(this._ch + this.eatString('}'));
4241
4276
  } else {
@@ -4253,22 +4288,21 @@ Beautifier.prototype.beautify = function() {
4253
4288
 
4254
4289
  variableOrRule = variableOrRule.replace(/\s$/, '');
4255
4290
 
4256
- if (variableOrRule === 'extend') {
4257
- insideAtExtend = true;
4258
- } else if (variableOrRule === 'import') {
4259
- insideAtImport = true;
4260
- }
4291
+ // might be less variable
4292
+ if (parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
4293
+ insidePropertyValue = true;
4294
+ this.indent();
4261
4295
 
4262
- // might be a nesting at-rule
4263
- if (variableOrRule in this.NESTED_AT_RULE) {
4296
+ // might be a nesting at-rule
4297
+ } else if (variableOrRule in this.NESTED_AT_RULE) {
4264
4298
  this._nestedLevel += 1;
4265
4299
  if (variableOrRule in this.CONDITIONAL_GROUP_RULE) {
4266
4300
  enteringConditionalGroup = true;
4267
4301
  }
4268
- // might be less variable
4269
- } else if (!insideRule && parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
4270
- insidePropertyValue = true;
4271
- this.indent();
4302
+
4303
+ // might be a non-nested at-rule
4304
+ } else if (parenLevel === 0 && !insidePropertyValue) {
4305
+ insideNonNestedAtRule = true;
4272
4306
  }
4273
4307
  }
4274
4308
  } else if (this._ch === '#' && this._input.peek() === '{') {
@@ -4280,6 +4314,9 @@ Beautifier.prototype.beautify = function() {
4280
4314
  this.outdent();
4281
4315
  }
4282
4316
 
4317
+ // non nested at rule becomes nested
4318
+ insideNonNestedAtRule = false;
4319
+
4283
4320
  // when entering conditional groups, only rulesets are allowed
4284
4321
  if (enteringConditionalGroup) {
4285
4322
  enteringConditionalGroup = false;
@@ -4320,8 +4357,7 @@ Beautifier.prototype.beautify = function() {
4320
4357
  if (previous_ch === '{') {
4321
4358
  this._output.trim(true);
4322
4359
  }
4323
- insideAtImport = false;
4324
- insideAtExtend = false;
4360
+
4325
4361
  if (insidePropertyValue) {
4326
4362
  this.outdent();
4327
4363
  insidePropertyValue = false;
@@ -4355,9 +4391,10 @@ Beautifier.prototype.beautify = function() {
4355
4391
  }
4356
4392
  }
4357
4393
 
4358
- if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideAtExtend && parenLevel === 0) {
4394
+ if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideNonNestedAtRule && parenLevel === 0) {
4359
4395
  // 'property: value' delimiter
4360
4396
  // which could be in a conditional group query
4397
+
4361
4398
  this.print_string(':');
4362
4399
  if (!insidePropertyValue) {
4363
4400
  insidePropertyValue = true;
@@ -4394,8 +4431,7 @@ Beautifier.prototype.beautify = function() {
4394
4431
  this.outdent();
4395
4432
  insidePropertyValue = false;
4396
4433
  }
4397
- insideAtExtend = false;
4398
- insideAtImport = false;
4434
+ insideNonNestedAtRule = false;
4399
4435
  this.print_string(this._ch);
4400
4436
  this.eatWhitespace(true);
4401
4437
 
@@ -4460,7 +4496,7 @@ Beautifier.prototype.beautify = function() {
4460
4496
  } else if (this._ch === ',') {
4461
4497
  this.print_string(this._ch);
4462
4498
  this.eatWhitespace(true);
4463
- if (this._options.selector_separator_newline && (!insidePropertyValue || insideScssMap) && parenLevel === 0 && !insideAtImport && !insideAtExtend) {
4499
+ if (this._options.selector_separator_newline && (!insidePropertyValue || insideScssMap) && parenLevel === 0 && !insideNonNestedAtRule) {
4464
4500
  this._output.add_new_line();
4465
4501
  } else {
4466
4502
  this._output.space_before_token = true;
@@ -4924,11 +4960,11 @@ Beautifier.prototype.beautify = function() {
4924
4960
  while (raw_token.type !== TOKEN.EOF) {
4925
4961
 
4926
4962
  if (raw_token.type === TOKEN.TAG_OPEN || raw_token.type === TOKEN.COMMENT) {
4927
- parser_token = this._handle_tag_open(printer, raw_token, last_tag_token, last_token);
4963
+ parser_token = this._handle_tag_open(printer, raw_token, last_tag_token, last_token, tokens);
4928
4964
  last_tag_token = parser_token;
4929
4965
  } else if ((raw_token.type === TOKEN.ATTRIBUTE || raw_token.type === TOKEN.EQUALS || raw_token.type === TOKEN.VALUE) ||
4930
4966
  (raw_token.type === TOKEN.TEXT && !last_tag_token.tag_complete)) {
4931
- parser_token = this._handle_inside_tag(printer, raw_token, last_tag_token, tokens);
4967
+ parser_token = this._handle_inside_tag(printer, raw_token, last_tag_token, last_token);
4932
4968
  } else if (raw_token.type === TOKEN.TAG_CLOSE) {
4933
4969
  parser_token = this._handle_tag_close(printer, raw_token, last_tag_token);
4934
4970
  } else if (raw_token.type === TOKEN.TEXT) {
@@ -4985,7 +5021,7 @@ Beautifier.prototype._handle_tag_close = function(printer, raw_token, last_tag_t
4985
5021
  return parser_token;
4986
5022
  };
4987
5023
 
4988
- Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_token, tokens) {
5024
+ Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_token, last_token) {
4989
5025
  var wrapped = last_tag_token.has_wrapped_attrs;
4990
5026
  var parser_token = {
4991
5027
  text: raw_token.text,
@@ -5006,7 +5042,6 @@ Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_
5006
5042
  } else {
5007
5043
  if (raw_token.type === TOKEN.ATTRIBUTE) {
5008
5044
  printer.set_space_before_token(true);
5009
- last_tag_token.attr_count += 1;
5010
5045
  } else if (raw_token.type === TOKEN.EQUALS) { //no space before =
5011
5046
  printer.set_space_before_token(false);
5012
5047
  } else if (raw_token.type === TOKEN.VALUE && raw_token.previous.type === TOKEN.EQUALS) { //no space before value
@@ -5019,29 +5054,15 @@ Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_
5019
5054
  wrapped = wrapped || raw_token.newlines !== 0;
5020
5055
  }
5021
5056
 
5022
-
5023
- if (this._is_wrap_attributes_force) {
5024
- var force_attr_wrap = last_tag_token.attr_count > 1;
5025
- if (this._is_wrap_attributes_force_expand_multiline && last_tag_token.attr_count === 1) {
5026
- var is_only_attribute = true;
5027
- var peek_index = 0;
5028
- var peek_token;
5029
- do {
5030
- peek_token = tokens.peek(peek_index);
5031
- if (peek_token.type === TOKEN.ATTRIBUTE) {
5032
- is_only_attribute = false;
5033
- break;
5034
- }
5035
- peek_index += 1;
5036
- } while (peek_index < 4 && peek_token.type !== TOKEN.EOF && peek_token.type !== TOKEN.TAG_CLOSE);
5037
-
5038
- force_attr_wrap = !is_only_attribute;
5039
- }
5040
-
5041
- if (force_attr_wrap) {
5042
- printer.print_newline(false);
5043
- wrapped = true;
5044
- }
5057
+ // Wrap for 'force' options, and if the number of attributes is at least that specified in 'wrap_attributes_min_attrs':
5058
+ // 1. always wrap the second and beyond attributes
5059
+ // 2. wrap the first attribute only if 'force-expand-multiline' is specified
5060
+ if (this._is_wrap_attributes_force &&
5061
+ last_tag_token.attr_count >= this._options.wrap_attributes_min_attrs &&
5062
+ (last_token.type !== TOKEN.TAG_OPEN || // ie. second attribute and beyond
5063
+ this._is_wrap_attributes_force_expand_multiline)) {
5064
+ printer.print_newline(false);
5065
+ wrapped = true;
5045
5066
  }
5046
5067
  }
5047
5068
  printer.print_token(raw_token);
@@ -5170,12 +5191,12 @@ Beautifier.prototype._print_custom_beatifier_text = function(printer, raw_token,
5170
5191
  }
5171
5192
  };
5172
5193
 
5173
- Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_token, last_token) {
5194
+ Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_token, last_token, tokens) {
5174
5195
  var parser_token = this._get_tag_open_token(raw_token);
5175
5196
 
5176
5197
  if ((last_tag_token.is_unformatted || last_tag_token.is_content_unformatted) &&
5177
5198
  !last_tag_token.is_empty_element &&
5178
- raw_token.type === TOKEN.TAG_OPEN && raw_token.text.indexOf('</') === 0) {
5199
+ raw_token.type === TOKEN.TAG_OPEN && !parser_token.is_start_tag) {
5179
5200
  // End element tags for unformatted or content_unformatted elements
5180
5201
  // are printed raw to keep any newlines inside them exactly the same.
5181
5202
  printer.add_raw_token(raw_token);
@@ -5189,6 +5210,19 @@ Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_to
5189
5210
  printer.print_token(raw_token);
5190
5211
  }
5191
5212
 
5213
+ // count the number of attributes
5214
+ if (parser_token.is_start_tag && this._is_wrap_attributes_force) {
5215
+ var peek_index = 0;
5216
+ var peek_token;
5217
+ do {
5218
+ peek_token = tokens.peek(peek_index);
5219
+ if (peek_token.type === TOKEN.ATTRIBUTE) {
5220
+ parser_token.attr_count += 1;
5221
+ }
5222
+ peek_index += 1;
5223
+ } while (peek_token.type !== TOKEN.EOF && peek_token.type !== TOKEN.TAG_CLOSE);
5224
+ }
5225
+
5192
5226
  //indent attributes an auto, forced, aligned or forced-align line-wrap
5193
5227
  if (this._is_wrap_attributes_force_aligned || this._is_wrap_attributes_aligned_multiple || this._is_wrap_attributes_preserve_aligned) {
5194
5228
  parser_token.alignment_size = raw_token.text.length + 1;
@@ -5286,7 +5320,7 @@ Beautifier.prototype._get_tag_open_token = function(raw_token) { //function to g
5286
5320
 
5287
5321
  parser_token.is_unformatted = !parser_token.tag_complete && in_array(parser_token.tag_check, this._options.unformatted);
5288
5322
  parser_token.is_content_unformatted = !parser_token.is_empty_element && in_array(parser_token.tag_check, this._options.content_unformatted);
5289
- parser_token.is_inline_element = in_array(parser_token.tag_name, this._options.inline) || parser_token.tag_name.includes("-") || parser_token.tag_start_char === '{';
5323
+ parser_token.is_inline_element = in_array(parser_token.tag_name, this._options.inline) || (this._options.inline_custom_elements && parser_token.tag_name.includes("-")) || parser_token.tag_start_char === '{';
5290
5324
 
5291
5325
  return parser_token;
5292
5326
  };
@@ -5393,7 +5427,7 @@ Beautifier.prototype._calcluate_parent_multiline = function(printer, parser_toke
5393
5427
  };
5394
5428
 
5395
5429
  //To be used for <p> tag special case:
5396
- var p_closers = ['address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', 'main', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul'];
5430
+ var p_closers = ['address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', 'main', 'menu', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul'];
5397
5431
  var p_parent_excludes = ['a', 'audio', 'del', 'ins', 'map', 'noscript', 'video'];
5398
5432
 
5399
5433
  Beautifier.prototype._do_optional_end_element = function(parser_token) {
@@ -5416,7 +5450,7 @@ Beautifier.prototype._do_optional_end_element = function(parser_token) {
5416
5450
 
5417
5451
  } else if (parser_token.tag_name === 'li') {
5418
5452
  // An li element’s end tag may be omitted if the li element is immediately followed by another li element or if there is no more content in the parent element.
5419
- result = result || this._tag_stack.try_pop('li', ['ol', 'ul']);
5453
+ result = result || this._tag_stack.try_pop('li', ['ol', 'ul', 'menu']);
5420
5454
 
5421
5455
  } else if (parser_token.tag_name === 'dd' || parser_token.tag_name === 'dt') {
5422
5456
  // A dd element’s end tag may be omitted if the dd element is immediately followed by another dd element or a dt element, or if there is no more content in the parent element.
@@ -5555,6 +5589,7 @@ function Options(options) {
5555
5589
  this.indent_handlebars = this._get_boolean('indent_handlebars', true);
5556
5590
  this.wrap_attributes = this._get_selection('wrap_attributes',
5557
5591
  ['auto', 'force', 'force-aligned', 'force-expand-multiline', 'aligned-multiple', 'preserve', 'preserve-aligned']);
5592
+ this.wrap_attributes_min_attrs = this._get_number('wrap_attributes_min_attrs', 2);
5558
5593
  this.wrap_attributes_indent_size = this._get_number('wrap_attributes_indent_size', this.indent_size);
5559
5594
  this.extra_liners = this._get_array('extra_liners', ['head', 'body', '/html']);
5560
5595
 
@@ -5572,6 +5607,7 @@ function Options(options) {
5572
5607
  // obsolete inline tags
5573
5608
  'acronym', 'big', 'strike', 'tt'
5574
5609
  ]);
5610
+ this.inline_custom_elements = this._get_boolean('inline_custom_elements', true);
5575
5611
  this.void_elements = this._get_array('void_elements', [
5576
5612
  // HTLM void elements - aka self-closing tags - aka singletons
5577
5613
  // https://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements