Merge pull request #2263 from gergely-gyorgy-both/fix-angular-control-flow-and-script-style-tags-indentation

Fixed #2260 - <style> and <script> tags indentation if also indenting angular control flows
This commit is contained in:
Liam Newman 2024-06-29 16:07:48 -07:00 committed by GitHub
commit 49df420f65
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 87 additions and 48 deletions

View File

@ -135,6 +135,10 @@ TemplatablePattern.prototype.__set_templated_pattern = function() {
if (!this._disabled.handlebars) {
items.push(this.__patterns.handlebars._starting_pattern.source);
}
if (!this._disabled.angular) {
// Handlebars ('{{' and '}}') are also special tokens in Angular)
items.push(this.__patterns.handlebars._starting_pattern.source);
}
if (!this._disabled.erb) {
items.push(this.__patterns.erb._starting_pattern.source);
}

View File

@ -291,7 +291,7 @@ Beautifier.prototype.beautify = function() {
type: ''
};
var last_tag_token = new TagOpenParserToken();
var last_tag_token = new TagOpenParserToken(this._options);
var printer = new Printer(this._options, baseIndentString);
var tokens = new Tokenizer(source_text, this._options).tokenize();
@ -614,7 +614,7 @@ Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_to
return parser_token;
};
var TagOpenParserToken = function(parent, raw_token) {
var TagOpenParserToken = function(options, parent, raw_token) {
this.parent = parent || null;
this.text = '';
this.type = 'TK_TAG_OPEN';
@ -681,13 +681,14 @@ var TagOpenParserToken = function(parent, raw_token) {
}
// handlebars tags that don't start with # or ^ are single_tags, and so also start and end.
// if they start with # or ^, they are still considered single tags if indenting of handlebars is set to false
this.is_end_tag = this.is_end_tag ||
(this.tag_start_char === '{' && (this.text.length < 3 || (/[^#\^]/.test(this.text.charAt(handlebar_starts)))));
(this.tag_start_char === '{' && (!options.indent_handlebars || this.text.length < 3 || (/[^#\^]/.test(this.text.charAt(handlebar_starts)))));
}
};
Beautifier.prototype._get_tag_open_token = function(raw_token) { //function to get a full tag and parse its type
var parser_token = new TagOpenParserToken(this._tag_stack.get_parser_token(), raw_token);
var parser_token = new TagOpenParserToken(this._options, this._tag_stack.get_parser_token(), raw_token);
parser_token.alignment_size = this._options.wrap_attributes_indent_size;

View File

@ -130,6 +130,7 @@ Tokenizer.prototype._get_next_token = function(previous_token, open_token) { //
token = token || this._read_open_handlebars(c, open_token);
token = token || this._read_attribute(c, previous_token, open_token);
token = token || this._read_close(c, open_token);
token = token || this._read_script_and_style(c, previous_token);
token = token || this._read_control_flows(c, open_token);
token = token || this._read_raw_content(c, previous_token, open_token);
token = token || this._read_content_word(c, open_token);
@ -215,8 +216,8 @@ Tokenizer.prototype._read_open_handlebars = function(c, open_token) {
var resulting_string = null;
var token = null;
if (!open_token || open_token.type === TOKEN.CONTROL_FLOW_OPEN) {
if (this._options.indent_handlebars && c === '{' && this._input.peek(1) === '{') {
if (this._input.peek(2) === '!') {
if ((this._options.templating.includes('angular') || this._options.indent_handlebars) && c === '{' && this._input.peek(1) === '{') {
if (this._options.indent_handlebars && this._input.peek(2) === '!') {
resulting_string = this.__patterns.handlebars_comment.read();
resulting_string = resulting_string || this.__patterns.handlebars.read();
token = this._create_token(TOKEN.COMMENT, resulting_string);
@ -232,8 +233,8 @@ Tokenizer.prototype._read_open_handlebars = function(c, open_token) {
Tokenizer.prototype._read_control_flows = function(c, open_token) {
var resulting_string = '';
var token = null;
// Only check for control flows if angular templating is set AND indenting is set
if (!this._options.templating.includes('angular') || !this._options.indent_handlebars) {
// Only check for control flows if angular templating is set
if (!this._options.templating.includes('angular')) {
return token;
}
@ -326,7 +327,6 @@ Tokenizer.prototype._is_content_unformatted = function(tag_name) {
this._options.unformatted.indexOf(tag_name) !== -1);
};
Tokenizer.prototype._read_raw_content = function(c, previous_token, open_token) { // jshint unused:false
var resulting_string = '';
if (open_token && open_token.text[0] === '{') {
@ -335,16 +335,7 @@ Tokenizer.prototype._read_raw_content = function(c, previous_token, open_token)
previous_token.opened.text[0] === '<' && previous_token.text[0] !== '/') {
// ^^ empty tag has no content
var tag_name = previous_token.opened.text.substr(1).toLowerCase();
if (tag_name === 'script' || tag_name === 'style') {
// Script and style tags are allowed to have comments wrapping their content
// or just have regular content.
var token = this._read_comment_or_cdata(c);
if (token) {
token.type = TOKEN.TEXT;
return token;
}
resulting_string = this._input.readUntil(new RegExp('</' + tag_name + '[\\n\\r\\t ]*?>', 'ig'));
} else if (this._is_content_unformatted(tag_name)) {
if (this._is_content_unformatted(tag_name)) {
resulting_string = this._input.readUntil(new RegExp('</' + tag_name + '[\\n\\r\\t ]*?>', 'ig'));
}
@ -357,6 +348,26 @@ Tokenizer.prototype._read_raw_content = function(c, previous_token, open_token)
return null;
};
Tokenizer.prototype._read_script_and_style = function(c, previous_token) { // jshint unused:false
if (previous_token.type === TOKEN.TAG_CLOSE && previous_token.opened.text[0] === '<' && previous_token.text[0] !== '/') {
var tag_name = previous_token.opened.text.substr(1).toLowerCase();
if (tag_name === 'script' || tag_name === 'style') {
// Script and style tags are allowed to have comments wrapping their content
// or just have regular content.
var token = this._read_comment_or_cdata(c);
if (token) {
token.type = TOKEN.TEXT;
return token;
}
var resulting_string = this._input.readUntil(new RegExp('</' + tag_name + '[\\n\\r\\t ]*?>', 'ig'));
if (resulting_string) {
return this._create_token(TOKEN.TEXT, resulting_string);
}
}
}
return null;
};
Tokenizer.prototype._read_content_word = function(c, open_token) {
var resulting_string = '';
if (this._options.unformatted_content_delimiter) {
@ -371,6 +382,7 @@ Tokenizer.prototype._read_content_word = function(c, open_token) {
if (resulting_string) {
return this._create_token(TOKEN.TEXT, resulting_string);
}
return null;
};
module.exports.Tokenizer = Tokenizer;

View File

@ -3916,7 +3916,7 @@ exports.test_data = {
description: "https://github.com/beautify-web/js-beautify/issues/2219",
template: "^^^ $$$",
options: [
{ name: "templating", value: "'angular, handlebars'" }
{ name: "templating", value: "'angular'" }
],
tests: [{
input: [
@ -4240,18 +4240,7 @@ exports.test_data = {
]
}, {
comment: 'CSS @media should remain unchanged',
// This behavior is currently incorrect. This codifies the way it fails.
// unchanged: [
// '<style type="text/css">',
// ' @media only screen and (min-width:480px) {',
// ' .mj-column-per-100 {',
// ' width: 100% !important;',
// ' max-width: 100%;',
// ' }',
// ' }',
// '</style>'
// ]
input: [
unchanged: [
'<style type="text/css">',
' @media only screen and (min-width:480px) {',
' .mj-column-per-100 {',
@ -4260,30 +4249,63 @@ exports.test_data = {
' }',
' }',
'</style>'
],
output: [
]
}, {
comment: 'CSS @media, the inside of <script> tag and control flows should be indented correctly',
fragment: true,
input: [
'<head>',
'<style type="text/css">',
'@media only screen and (min-width:480px) {',
' .mj-column-per-100',
' {',
' width:',
' 100%',
' !important;',
' max-width:',
' 100%;',
'.mj-column-per-100 {',
'width: 100% !important;',
'max-width: 100%;',
'}',
' }',
'</style>'
'}',
'</style>',
'<script>',
'if(someExpression) {',
'callFunc();',
'}',
'</script>',
'</head>',
'<body>',
'<div>',
'@if(someOtherExpression) {',
'Text',
'}',
'</div>',
'</body>'
],
output: [
'<head>',
' <style type="text/css">',
' @media only screen and (min-width:480px) {',
' .mj-column-per-100 {',
' width: 100% !important;',
' max-width: 100%;',
' }',
' }',
' </style>',
' <script>',
' if (someExpression) {',
' callFunc();',
' }',
' </script>',
'</head>',
'<body>',
' <div>',
' @if(someOtherExpression) {',
' Text',
' }',
' </div>',
'</body>'
]
}]
}, {
name: "No indenting for angular control flow should be done if indent_handlebars is false",
name: "No indenting for angular control flow should be done if angular templating is not set",
description: "https://github.com/beautify-web/js-beautify/issues/2219",
template: "^^^ $$$",
options: [
{ name: "templating", value: "'angular, handlebars'" },
{ name: "indent_handlebars", value: "false" }
],
tests: [{
unchanged: [
'@if (a > b) {',