Skip to content

Commit 495c8c3

Browse files
authored
Merge branch 'main' into feat/2113-inline-custom-elements-behavior
2 parents d62a502 + 9859430 commit 495c8c3

26 files changed

+561
-2890
lines changed

.github/workflows/main.yml

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,14 @@ jobs:
1717
fail-fast: false
1818
matrix:
1919
os: [ ubuntu, windows, macos ]
20-
python-version: [3.7, 3.8, 3.9, '3.10']
20+
python-version: [3.8, '3.10', 3.11]
2121
include:
22-
- python-version: 3.7
23-
node-version: 12
2422
- python-version: 3.8
25-
node-version: 14
26-
- python-version: 3.9
2723
node-version: 16
2824
- python-version: '3.10'
29-
node-version: 16
30-
exclude:
31-
- os: windows
32-
python-version: 2.7
25+
node-version: 18
26+
- python-version: 3.11
27+
node-version: 20
3328
steps:
3429
- uses: actions/checkout@v2
3530
- name: Set up Node ${{ matrix.node-version }}

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# Changelog
22

3+
## v1.14.8
4+
* Require nodejs v12 or greater ([#2151](https://github.com/beautify-web/js-beautify/pull/2151))
5+
* CSS insideNonNestedAtRule generic variable ([#2147](https://github.com/beautify-web/js-beautify/pull/2147))
6+
* Update dependencies ([#2145](https://github.com/beautify-web/js-beautify/pull/2145))
7+
* Fix CI build ([#2144](https://github.com/beautify-web/js-beautify/pull/2144))
8+
* Fixed #2133 Theme Toggle on without\_codemirror Mode ([#2138](https://github.com/beautify-web/js-beautify/pull/2138))
9+
* use correct variable name ([#2135](https://github.com/beautify-web/js-beautify/pull/2135))
10+
* docs: Fix a few typos ([#2127](https://github.com/beautify-web/js-beautify/pull/2127))
11+
* Add support for new record types (cont.) ([#2118](https://github.com/beautify-web/js-beautify/pull/2118))
12+
* fix - semicolon followed by block statement doesnt have new line ([#2117](https://github.com/beautify-web/js-beautify/pull/2117))
13+
* Fix formatting related to the <menu> element ([#2114](https://github.com/beautify-web/js-beautify/pull/2114))
14+
* issue prettifying (function(){code();{code}})() ([#1852](https://github.com/beautify-web/js-beautify/issues/1852))
15+
316
## v1.14.7
417
* Doc: Updates web browser implementation examples ([#2107](https://github.com/beautify-web/js-beautify/pull/2107))
518
* HTML formatter breaks layout by introducing newlines ([#1989](https://github.com/beautify-web/js-beautify/issues/1989))

README.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,13 @@ JS Beautifier is hosted on two CDN services: [cdnjs](https://cdnjs.com/libraries
5858

5959
To pull the latest version from one of these services include one set of the script tags below in your document:
6060
```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.8/beautify.js"></script>
62+
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.8/beautify-css.js"></script>
63+
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.8/beautify-html.js"></script>
6464

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.8/beautify.min.js"></script>
66+
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.8/beautify-css.min.js"></script>
67+
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.8/beautify-html.min.js"></script>
6868
```
6969

7070
Example usage of a JS tag in html:
@@ -76,7 +76,7 @@ Example usage of a JS tag in html:
7676

7777
. . .
7878

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.8/beautify.min.js"></script>
8080
<script src="script.js"></script>
8181
</body>
8282
</html>
@@ -141,7 +141,7 @@ To use `js-beautify` as a `node` library (after install locally), import and cal
141141
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 }`.
142142

143143
```js
144-
var beautify = require('js-beautify').js,
144+
var beautify = require('js-beautify/js').js,
145145
fs = require('fs');
146146

147147
fs.readFile('foo.js', 'utf8', function (err, data) {
@@ -368,6 +368,7 @@ HTML Beautifier Options:
368368
-S, --indent-scripts [keep|separate|normal] ["normal"]
369369
-w, --wrap-line-length Maximum characters per line (0 disables) [250]
370370
-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]
371372
-i, --wrap-attributes-indent-size Indent wrapped attributes to after N characters [indent-size] (ignored if wrap-attributes is "aligned")
372373
-d, --inline List of tags to be considered inline tags
373374
--inline_custom_elements Inline custom elements [true]
@@ -433,4 +434,4 @@ Thanks also to Jason Diamond, Patrick Hof, Nochum Sossonko, Andreas Schneider, D
433434
Vasilevsky, Vital Batmanov, Ron Baldwin, Gabriel Harrison, Chris J. Shull,
434435
Mathias Bynens, Vittorio Gambaletta and others.
435436
436-
(README.md: [email protected].7)
437+
(README.md: [email protected].8)

js/src/cli.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ var path = require('path'),
9999
"unescape_strings": Boolean,
100100
"wrap_line_length": Number,
101101
"wrap_attributes": ["auto", "force", "force-aligned", "force-expand-multiline", "aligned-multiple", "preserve", "preserve-aligned"],
102+
"wrap_attributes_min_attrs": Number,
102103
"wrap_attributes_indent_size": Number,
103104
"e4x": Boolean,
104105
"end_with_newline": Boolean,
@@ -164,6 +165,7 @@ var path = require('path'),
164165
"N": ["--newline_between_rules"],
165166
// HTML-only
166167
"A": ["--wrap_attributes"],
168+
"M": ["--wrap_attributes_min_attrs"],
167169
"i": ["--wrap_attributes_indent_size"],
168170
"W": ["--max_char"], // obsolete since 1.3.5
169171
"d": ["--inline"],
@@ -397,6 +399,7 @@ function usage(err) {
397399
msg.push(' -S, --indent-scripts [keep|separate|normal] ["normal"]');
398400
msg.push(' -w, --wrap-line-length Wrap lines that exceed N characters [0]');
399401
msg.push(' -A, --wrap-attributes Wrap html tag attributes to new lines [auto|force|force-aligned|force-expand-multiline|aligned-multiple|preserve|preserve-aligned] ["auto"]');
402+
msg.push(' -M, --wrap-attributes-min-attrs Minimum number of html tag attributes for force wrap attribute options [2]');
400403
msg.push(' -i, --wrap-attributes-indent-size Indent wrapped tags to after N characters [indent-level]');
401404
msg.push(' -p, --preserve-newlines Preserve line-breaks (--no-preserve-newlines disables)');
402405
msg.push(' -m, --max-preserve-newlines Number of line-breaks to be preserved in one chunk [10]');

js/src/css/beautifier.js

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,18 @@ function Beautifier(source_text, options) {
5454

5555
// https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
5656
this.NESTED_AT_RULE = {
57-
"@page": true,
58-
"@font-face": true,
59-
"@keyframes": true,
57+
"page": true,
58+
"font-face": true,
59+
"keyframes": true,
6060
// also in CONDITIONAL_GROUP_RULE below
61-
"@media": true,
62-
"@supports": true,
63-
"@document": true
61+
"media": true,
62+
"supports": true,
63+
"document": true
6464
};
6565
this.CONDITIONAL_GROUP_RULE = {
66-
"@media": true,
67-
"@supports": true,
68-
"@document": true
66+
"media": true,
67+
"supports": true,
68+
"document": true
6969
};
7070
this.NON_SEMICOLON_NEWLINE_PROPERTY = [
7171
"grid-template-areas",
@@ -193,8 +193,7 @@ Beautifier.prototype.beautify = function() {
193193
// label { content: blue }
194194
var insidePropertyValue = false;
195195
var enteringConditionalGroup = false;
196-
var insideAtExtend = false;
197-
var insideAtImport = false;
196+
var insideNonNestedAtRule = false;
198197
var insideScssMap = false;
199198
var topCharacter = this._ch;
200199
var insideNonSemiColonValues = false;
@@ -249,10 +248,32 @@ Beautifier.prototype.beautify = function() {
249248

250249
// Ensures any new lines following the comment are preserved
251250
this.eatWhitespace(true);
252-
} else if (this._ch === '@' || this._ch === '$') {
251+
} else if (this._ch === '$') {
253252
this.preserveSingleSpace(isAfterSpace);
254253

255-
// deal with less propery mixins @{...}
254+
this.print_string(this._ch);
255+
256+
// strip trailing space, if present, for hash property checks
257+
var variable = this._input.peekUntilAfter(/[: ,;{}()[\]\/='"]/g);
258+
259+
if (variable.match(/[ :]$/)) {
260+
// we have a variable or pseudo-class, add it and insert one space before continuing
261+
variable = this.eatString(": ").replace(/\s$/, '');
262+
this.print_string(variable);
263+
this._output.space_before_token = true;
264+
}
265+
266+
variable = variable.replace(/\s$/, '');
267+
268+
// might be sass variable
269+
if (parenLevel === 0 && variable.indexOf(':') !== -1) {
270+
insidePropertyValue = true;
271+
this.indent();
272+
}
273+
} else if (this._ch === '@') {
274+
this.preserveSingleSpace(isAfterSpace);
275+
276+
// deal with less property mixins @{...}
256277
if (this._input.peek() === '{') {
257278
this.print_string(this._ch + this.eatString('}'));
258279
} else {
@@ -270,22 +291,21 @@ Beautifier.prototype.beautify = function() {
270291

271292
variableOrRule = variableOrRule.replace(/\s$/, '');
272293

273-
if (variableOrRule === 'extend') {
274-
insideAtExtend = true;
275-
} else if (variableOrRule === 'import') {
276-
insideAtImport = true;
277-
}
294+
// might be less variable
295+
if (parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
296+
insidePropertyValue = true;
297+
this.indent();
278298

279-
// might be a nesting at-rule
280-
if (variableOrRule in this.NESTED_AT_RULE) {
299+
// might be a nesting at-rule
300+
} else if (variableOrRule in this.NESTED_AT_RULE) {
281301
this._nestedLevel += 1;
282302
if (variableOrRule in this.CONDITIONAL_GROUP_RULE) {
283303
enteringConditionalGroup = true;
284304
}
285-
// might be less variable
286-
} else if (!insideRule && parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
287-
insidePropertyValue = true;
288-
this.indent();
305+
306+
// might be a non-nested at-rule
307+
} else if (parenLevel === 0 && !insidePropertyValue) {
308+
insideNonNestedAtRule = true;
289309
}
290310
}
291311
} else if (this._ch === '#' && this._input.peek() === '{') {
@@ -297,6 +317,9 @@ Beautifier.prototype.beautify = function() {
297317
this.outdent();
298318
}
299319

320+
// non nested at rule becomes nested
321+
insideNonNestedAtRule = false;
322+
300323
// when entering conditional groups, only rulesets are allowed
301324
if (enteringConditionalGroup) {
302325
enteringConditionalGroup = false;
@@ -337,8 +360,7 @@ Beautifier.prototype.beautify = function() {
337360
if (previous_ch === '{') {
338361
this._output.trim(true);
339362
}
340-
insideAtImport = false;
341-
insideAtExtend = false;
363+
342364
if (insidePropertyValue) {
343365
this.outdent();
344366
insidePropertyValue = false;
@@ -372,9 +394,10 @@ Beautifier.prototype.beautify = function() {
372394
}
373395
}
374396

375-
if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideAtExtend && parenLevel === 0) {
397+
if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideNonNestedAtRule && parenLevel === 0) {
376398
// 'property: value' delimiter
377399
// which could be in a conditional group query
400+
378401
this.print_string(':');
379402
if (!insidePropertyValue) {
380403
insidePropertyValue = true;
@@ -411,8 +434,7 @@ Beautifier.prototype.beautify = function() {
411434
this.outdent();
412435
insidePropertyValue = false;
413436
}
414-
insideAtExtend = false;
415-
insideAtImport = false;
437+
insideNonNestedAtRule = false;
416438
this.print_string(this._ch);
417439
this.eatWhitespace(true);
418440

@@ -477,7 +499,7 @@ Beautifier.prototype.beautify = function() {
477499
} else if (this._ch === ',') {
478500
this.print_string(this._ch);
479501
this.eatWhitespace(true);
480-
if (this._options.selector_separator_newline && (!insidePropertyValue || insideScssMap) && parenLevel === 0 && !insideAtImport && !insideAtExtend) {
502+
if (this._options.selector_separator_newline && (!insidePropertyValue || insideScssMap) && parenLevel === 0 && !insideNonNestedAtRule) {
481503
this._output.add_new_line();
482504
} else {
483505
this._output.space_before_token = true;

js/src/html/beautifier.js

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -296,11 +296,11 @@ Beautifier.prototype.beautify = function() {
296296
while (raw_token.type !== TOKEN.EOF) {
297297

298298
if (raw_token.type === TOKEN.TAG_OPEN || raw_token.type === TOKEN.COMMENT) {
299-
parser_token = this._handle_tag_open(printer, raw_token, last_tag_token, last_token);
299+
parser_token = this._handle_tag_open(printer, raw_token, last_tag_token, last_token, tokens);
300300
last_tag_token = parser_token;
301301
} else if ((raw_token.type === TOKEN.ATTRIBUTE || raw_token.type === TOKEN.EQUALS || raw_token.type === TOKEN.VALUE) ||
302302
(raw_token.type === TOKEN.TEXT && !last_tag_token.tag_complete)) {
303-
parser_token = this._handle_inside_tag(printer, raw_token, last_tag_token, tokens);
303+
parser_token = this._handle_inside_tag(printer, raw_token, last_tag_token, last_token);
304304
} else if (raw_token.type === TOKEN.TAG_CLOSE) {
305305
parser_token = this._handle_tag_close(printer, raw_token, last_tag_token);
306306
} else if (raw_token.type === TOKEN.TEXT) {
@@ -357,7 +357,7 @@ Beautifier.prototype._handle_tag_close = function(printer, raw_token, last_tag_t
357357
return parser_token;
358358
};
359359

360-
Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_token, tokens) {
360+
Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_token, last_token) {
361361
var wrapped = last_tag_token.has_wrapped_attrs;
362362
var parser_token = {
363363
text: raw_token.text,
@@ -378,7 +378,6 @@ Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_
378378
} else {
379379
if (raw_token.type === TOKEN.ATTRIBUTE) {
380380
printer.set_space_before_token(true);
381-
last_tag_token.attr_count += 1;
382381
} else if (raw_token.type === TOKEN.EQUALS) { //no space before =
383382
printer.set_space_before_token(false);
384383
} else if (raw_token.type === TOKEN.VALUE && raw_token.previous.type === TOKEN.EQUALS) { //no space before value
@@ -391,29 +390,15 @@ Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_
391390
wrapped = wrapped || raw_token.newlines !== 0;
392391
}
393392

394-
395-
if (this._is_wrap_attributes_force) {
396-
var force_attr_wrap = last_tag_token.attr_count > 1;
397-
if (this._is_wrap_attributes_force_expand_multiline && last_tag_token.attr_count === 1) {
398-
var is_only_attribute = true;
399-
var peek_index = 0;
400-
var peek_token;
401-
do {
402-
peek_token = tokens.peek(peek_index);
403-
if (peek_token.type === TOKEN.ATTRIBUTE) {
404-
is_only_attribute = false;
405-
break;
406-
}
407-
peek_index += 1;
408-
} while (peek_index < 4 && peek_token.type !== TOKEN.EOF && peek_token.type !== TOKEN.TAG_CLOSE);
409-
410-
force_attr_wrap = !is_only_attribute;
411-
}
412-
413-
if (force_attr_wrap) {
414-
printer.print_newline(false);
415-
wrapped = true;
416-
}
393+
// Wrap for 'force' options, and if the number of attributes is at least that specified in 'wrap_attributes_min_attrs':
394+
// 1. always wrap the second and beyond attributes
395+
// 2. wrap the first attribute only if 'force-expand-multiline' is specified
396+
if (this._is_wrap_attributes_force &&
397+
last_tag_token.attr_count >= this._options.wrap_attributes_min_attrs &&
398+
(last_token.type !== TOKEN.TAG_OPEN || // ie. second attribute and beyond
399+
this._is_wrap_attributes_force_expand_multiline)) {
400+
printer.print_newline(false);
401+
wrapped = true;
417402
}
418403
}
419404
printer.print_token(raw_token);
@@ -542,12 +527,12 @@ Beautifier.prototype._print_custom_beatifier_text = function(printer, raw_token,
542527
}
543528
};
544529

545-
Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_token, last_token) {
530+
Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_token, last_token, tokens) {
546531
var parser_token = this._get_tag_open_token(raw_token);
547532

548533
if ((last_tag_token.is_unformatted || last_tag_token.is_content_unformatted) &&
549534
!last_tag_token.is_empty_element &&
550-
raw_token.type === TOKEN.TAG_OPEN && raw_token.text.indexOf('</') === 0) {
535+
raw_token.type === TOKEN.TAG_OPEN && !parser_token.is_start_tag) {
551536
// End element tags for unformatted or content_unformatted elements
552537
// are printed raw to keep any newlines inside them exactly the same.
553538
printer.add_raw_token(raw_token);
@@ -561,6 +546,19 @@ Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_to
561546
printer.print_token(raw_token);
562547
}
563548

549+
// count the number of attributes
550+
if (parser_token.is_start_tag && this._is_wrap_attributes_force) {
551+
var peek_index = 0;
552+
var peek_token;
553+
do {
554+
peek_token = tokens.peek(peek_index);
555+
if (peek_token.type === TOKEN.ATTRIBUTE) {
556+
parser_token.attr_count += 1;
557+
}
558+
peek_index += 1;
559+
} while (peek_token.type !== TOKEN.EOF && peek_token.type !== TOKEN.TAG_CLOSE);
560+
}
561+
564562
//indent attributes an auto, forced, aligned or forced-align line-wrap
565563
if (this._is_wrap_attributes_force_aligned || this._is_wrap_attributes_aligned_multiple || this._is_wrap_attributes_preserve_aligned) {
566564
parser_token.alignment_size = raw_token.text.length + 1;

js/src/html/options.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ function Options(options) {
4343
this.indent_handlebars = this._get_boolean('indent_handlebars', true);
4444
this.wrap_attributes = this._get_selection('wrap_attributes',
4545
['auto', 'force', 'force-aligned', 'force-expand-multiline', 'aligned-multiple', 'preserve', 'preserve-aligned']);
46+
this.wrap_attributes_min_attrs = this._get_number('wrap_attributes_min_attrs', 2);
4647
this.wrap_attributes_indent_size = this._get_number('wrap_attributes_indent_size', this.indent_size);
4748
this.extra_liners = this._get_array('extra_liners', ['head', 'body', '/html']);
4849

0 commit comments

Comments
 (0)