From 053e1661a65b3f38fd8965a90c3ab9f6a0a57f48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Thu, 30 Apr 2026 19:40:52 +0200 Subject: [PATCH 1/4] feat: add `functionExpression.indentInsideIife` option Add a new boolean config option to control whether the body of a function expression inside an IIFE is indented. Defaults to `true` (existing behavior). When set to `false`, `(function () { ... })();` will not indent its body. --- src/configuration/builder.rs | 8 ++ src/configuration/resolve_config.rs | 3 +- src/configuration/types.rs | 2 + src/generation/context.rs | 8 +- src/generation/generate.rs | 55 +++++------ ...ctionExpression_IndentInsideIife_False.txt | 94 +++++++++++++++++++ 6 files changed, 139 insertions(+), 31 deletions(-) create mode 100644 tests/specs/expressions/FunctionExpression/FunctionExpression_IndentInsideIife_False.txt diff --git a/src/configuration/builder.rs b/src/configuration/builder.rs index aeaaa4d3..42a977e2 100644 --- a/src/configuration/builder.rs +++ b/src/configuration/builder.rs @@ -348,6 +348,14 @@ impl ConfigurationBuilder { self.insert("functionExpression.spaceAfterFunctionKeyword", value.into()) } + /// Whether to indent the body of a function expression used in an IIFE. + /// + /// `true` (default) - Indents the body as normal. + /// `false` - Does not indent the body of the function in `(function() { ... })();`. + pub fn function_expression_indent_inside_iife(&mut self, value: bool) -> &mut Self { + self.insert("functionExpression.indentInsideIife", value.into()) + } + /// Whether to add a space before the parentheses of a get accessor. /// /// `true` - Ex. `get myProp ()` diff --git a/src/configuration/resolve_config.rs b/src/configuration/resolve_config.rs index 486b2365..08905cc9 100644 --- a/src/configuration/resolve_config.rs +++ b/src/configuration/resolve_config.rs @@ -289,6 +289,7 @@ pub fn resolve_config(config: ConfigKeyMap, global_config: &GlobalConfiguration) function_declaration_space_before_parentheses: get_value(&mut config, "functionDeclaration.spaceBeforeParentheses", false, &mut diagnostics), function_expression_space_before_parentheses: get_value(&mut config, "functionExpression.spaceBeforeParentheses", false, &mut diagnostics), function_expression_space_after_function_keyword: get_value(&mut config, "functionExpression.spaceAfterFunctionKeyword", false, &mut diagnostics), + function_expression_indent_inside_iife: get_value(&mut config, "functionExpression.indentInsideIife", true, &mut diagnostics), get_accessor_space_before_parentheses: get_value(&mut config, "getAccessor.spaceBeforeParentheses", false, &mut diagnostics), if_statement_space_after_if_keyword: get_value(&mut config, "ifStatement.spaceAfterIfKeyword", true, &mut diagnostics), import_declaration_space_surrounding_named_imports: get_value(&mut config, "importDeclaration.spaceSurroundingNamedImports", true, &mut diagnostics), @@ -353,8 +354,8 @@ pub fn resolve_config(config: ConfigKeyMap, global_config: &GlobalConfiguration) #[cfg(test)] mod tests { - use dprint_core::configuration::resolve_global_config; use dprint_core::configuration::NewLineKind; + use dprint_core::configuration::resolve_global_config; use super::super::builder::ConfigurationBuilder; use super::*; diff --git a/src/configuration/types.rs b/src/configuration/types.rs index 1e67d7b7..dc146765 100644 --- a/src/configuration/types.rs +++ b/src/configuration/types.rs @@ -604,6 +604,8 @@ pub struct Configuration { pub function_expression_space_before_parentheses: bool, #[serde(rename = "functionExpression.spaceAfterFunctionKeyword")] pub function_expression_space_after_function_keyword: bool, + #[serde(rename = "functionExpression.indentInsideIife")] + pub function_expression_indent_inside_iife: bool, #[serde(rename = "getAccessor.spaceBeforeParentheses")] pub get_accessor_space_before_parentheses: bool, #[serde(rename = "ifStatement.spaceAfterIfKeyword")] diff --git a/src/generation/context.rs b/src/generation/context.rs index 13b23f7f..5f92dd84 100644 --- a/src/generation/context.rs +++ b/src/generation/context.rs @@ -1,11 +1,11 @@ -use deno_ast::swc::common::comments::Comment; -use deno_ast::swc::parser::token::TokenAndSpan; -use deno_ast::view::*; use deno_ast::MediaType; use deno_ast::SourcePos; use deno_ast::SourceRange; use deno_ast::SourceRanged; use deno_ast::SourceRangedForSpanned; +use deno_ast::swc::common::comments::Comment; +use deno_ast::swc::parser::token::TokenAndSpan; +use deno_ast::view::*; use dprint_core::formatting::ConditionReference; use dprint_core::formatting::IndentLevel; use dprint_core::formatting::IsStartOfLine; @@ -68,6 +68,7 @@ pub struct Context<'a> { stored_lsil: FxHashMap<(SourcePos, SourcePos), LineStartIndentLevel>, stored_ln: FxHashMap<(SourcePos, SourcePos), LineNumber>, stored_il: FxHashMap<(SourcePos, SourcePos), IndentLevel>, + pub skip_iife_body_indent: bool, pub end_statement_or_member_lns: Stack, before_comments_start_info_stack: Stack<(SourceRange, LineNumber, IsStartOfLine)>, if_stmt_last_brace_condition_ref: Option, @@ -102,6 +103,7 @@ impl<'a> Context<'a> { stored_lsil: FxHashMap::default(), stored_ln: FxHashMap::default(), stored_il: FxHashMap::default(), + skip_iife_body_indent: false, end_statement_or_member_lns: Default::default(), before_comments_start_info_stack: Default::default(), if_stmt_last_brace_condition_ref: None, diff --git a/src/generation/generate.rs b/src/generation/generate.rs index 5c5ad077..7d9871dc 100644 --- a/src/generation/generate.rs +++ b/src/generation/generate.rs @@ -1,9 +1,3 @@ -use deno_ast::swc::common::comments::Comment; -use deno_ast::swc::common::comments::CommentKind; -use deno_ast::swc::parser::token::BinOpToken; -use deno_ast::swc::parser::token::Token; -use deno_ast::swc::parser::token::TokenAndSpan; -use deno_ast::view::*; use deno_ast::CommentsIterator; use deno_ast::MediaType; use deno_ast::ParsedSource; @@ -11,6 +5,12 @@ use deno_ast::SourcePos; use deno_ast::SourceRange; use deno_ast::SourceRanged; use deno_ast::SourceRangedForSpanned; +use deno_ast::swc::common::comments::Comment; +use deno_ast::swc::common::comments::CommentKind; +use deno_ast::swc::parser::token::BinOpToken; +use deno_ast::swc::parser::token::Token; +use deno_ast::swc::parser::token::TokenAndSpan; +use deno_ast::view::*; use dprint_core::formatting::condition_resolvers; use dprint_core::formatting::conditions::*; use dprint_core::formatting::ir_helpers::*; @@ -115,11 +115,7 @@ fn gen_node_with_inner_gen<'a>(node: Node<'a>, context: &mut Context<'a>, inner_ // keep the leading text, but leave the trailing text to be formatted if on a separate line let node_text = node.text_fast(context.program); let end_trim = node_text.trim_end(); - if node_text[end_trim.len()..].contains('\n') { - end_trim - } else { - node_text - } + if node_text[end_trim.len()..].contains('\n') { end_trim } else { node_text } } else { node.text_fast(context.program) }; @@ -1134,11 +1130,7 @@ fn gen_export_named_decl<'a>(node: &NamedExport<'a>, context: &mut Context<'a>) items.push_sc(sc!(";")); } - if should_single_line { - with_no_new_lines(items) - } else { - items - } + if should_single_line { with_no_new_lines(items) } else { items } } fn gen_function_decl<'a>(node: &FnDecl<'a>, context: &mut Context<'a>) -> PrintItems { @@ -1349,11 +1341,7 @@ fn gen_import_decl<'a>(node: &ImportDecl<'a>, context: &mut Context<'a>) -> Prin items.push_sc(sc!(";")); } - if should_single_line { - with_no_new_lines(items) - } else { - items - } + if should_single_line { with_no_new_lines(items) } else { items } } fn gen_import_equals_decl<'a>(node: &TsImportEqualsDecl<'a>, context: &mut Context<'a>) -> PrintItems { @@ -2638,7 +2626,21 @@ fn gen_expr_with_type_args<'a>(node: &TsExprWithTypeArgs<'a>, context: &mut Cont items } +fn is_iife_fn_expr(node: &FnExpr) -> bool { + let parent = node.parent(); + if parent.kind() == NodeKind::ParenExpr { + if let Some(grandparent) = parent.parent() { + return grandparent.kind() == NodeKind::CallExpr; + } + } + false +} + fn gen_fn_expr<'a>(node: &FnExpr<'a>, context: &mut Context<'a>) -> PrintItems { + if !context.config.function_expression_indent_inside_iife && is_iife_fn_expr(node) { + context.skip_iife_body_indent = true; + } + let items = gen_function_decl_or_expr( FunctionDeclOrExprNode { node: node.into(), @@ -7775,11 +7777,7 @@ fn gen_close_paren_with_type<'a>(opts: GenCloseParenWithTypeOptions<'a>, context items.extend(generated_type_node); items.push_info(type_node_end_ln); - if use_new_line_group { - new_line_group(items) - } else { - items - } + if use_new_line_group { new_line_group(items) } else { items } } else { items }; @@ -9475,6 +9473,8 @@ struct GenBlockOptions<'a> { fn gen_block<'a>(gen_inner: impl FnOnce(Vec>, &mut Context<'a>) -> PrintItems, opts: GenBlockOptions<'a>, context: &mut Context<'a>) -> PrintItems { let mut items = PrintItems::new(); + let skip_indent = context.skip_iife_body_indent; + context.skip_iife_body_indent = false; let before_open_token_ln = LineNumber::new("after_open_token_info"); let first_member_range = opts.children.first().map(|x| x.range()); let range = opts.range; @@ -9493,7 +9493,8 @@ fn gen_block<'a>(gen_inner: impl FnOnce(Vec>, &mut Context<'a>) -> Prin items.push_signal(Signal::NewLine); } items.push_line_and_column(start_inner_lc); - items.extend(ir_helpers::with_indent(gen_inner(opts.children, context))); + let inner = gen_inner(opts.children, context); + items.extend(if skip_indent { inner } else { ir_helpers::with_indent(inner) }); items.push_line_and_column(end_inner_lc); if is_tokens_same_line_and_empty { diff --git a/tests/specs/expressions/FunctionExpression/FunctionExpression_IndentInsideIife_False.txt b/tests/specs/expressions/FunctionExpression/FunctionExpression_IndentInsideIife_False.txt new file mode 100644 index 00000000..ec29668f --- /dev/null +++ b/tests/specs/expressions/FunctionExpression/FunctionExpression_IndentInsideIife_False.txt @@ -0,0 +1,94 @@ +~~ functionExpression.indentInsideIife: false ~~ +== should not indent body of IIFE == +(function() { + const a = "foobar"; + return { a }; +})(); + +[expect] +(function() { +const a = "foobar"; +return { a }; +})(); + +== should not indent body of named IIFE == +(function init() { + const a = "foobar"; + return { a }; +})(); + +[expect] +(function init() { +const a = "foobar"; +return { a }; +})(); + +== should not indent body of IIFE with args == +(function(x) { + const a = x; + return { a }; +})(42); + +[expect] +(function(x) { +const a = x; +return { a }; +})(42); + +== should still indent body of regular function expression == +const fn = function() { + const a = "foobar"; + return { a }; +}; + +[expect] +const fn = function() { + const a = "foobar"; + return { a }; +}; + +== should still indent body of function expression in call argument == +call(function() { + const a = "foobar"; + return { a }; +}); + +[expect] +call(function() { + const a = "foobar"; + return { a }; +}); + +== should not affect arrow function IIFE == +(() => { + const a = "foobar"; + return { a }; +})(); + +[expect] +(() => { + const a = "foobar"; + return { a }; +})(); + +== should handle IIFE with nested function == +(function() { + function inner() { + return 1; + } + return inner(); +})(); + +[expect] +(function() { +function inner() { + return 1; +} +return inner(); +})(); + +== should handle empty IIFE == +(function() {})(); + +[expect] +(function() {})(); From 703d9009324692c427c7302baede260d259ec72a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Thu, 30 Apr 2026 19:43:17 +0200 Subject: [PATCH 2/4] revert unrelated import reordering from rustfmt --- src/generation/context.rs | 6 +++--- src/generation/generate.rs | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/generation/context.rs b/src/generation/context.rs index 5f92dd84..2f50f4c5 100644 --- a/src/generation/context.rs +++ b/src/generation/context.rs @@ -1,11 +1,11 @@ +use deno_ast::swc::common::comments::Comment; +use deno_ast::swc::parser::token::TokenAndSpan; +use deno_ast::view::*; use deno_ast::MediaType; use deno_ast::SourcePos; use deno_ast::SourceRange; use deno_ast::SourceRanged; use deno_ast::SourceRangedForSpanned; -use deno_ast::swc::common::comments::Comment; -use deno_ast::swc::parser::token::TokenAndSpan; -use deno_ast::view::*; use dprint_core::formatting::ConditionReference; use dprint_core::formatting::IndentLevel; use dprint_core::formatting::IsStartOfLine; diff --git a/src/generation/generate.rs b/src/generation/generate.rs index 7d9871dc..bac6b895 100644 --- a/src/generation/generate.rs +++ b/src/generation/generate.rs @@ -1,3 +1,9 @@ +use deno_ast::swc::common::comments::Comment; +use deno_ast::swc::common::comments::CommentKind; +use deno_ast::swc::parser::token::BinOpToken; +use deno_ast::swc::parser::token::Token; +use deno_ast::swc::parser::token::TokenAndSpan; +use deno_ast::view::*; use deno_ast::CommentsIterator; use deno_ast::MediaType; use deno_ast::ParsedSource; @@ -5,12 +11,6 @@ use deno_ast::SourcePos; use deno_ast::SourceRange; use deno_ast::SourceRanged; use deno_ast::SourceRangedForSpanned; -use deno_ast::swc::common::comments::Comment; -use deno_ast::swc::common::comments::CommentKind; -use deno_ast::swc::parser::token::BinOpToken; -use deno_ast::swc::parser::token::Token; -use deno_ast::swc::parser::token::TokenAndSpan; -use deno_ast::view::*; use dprint_core::formatting::condition_resolvers; use dprint_core::formatting::conditions::*; use dprint_core::formatting::ir_helpers::*; From ce46e9f890bf9807c9ef80dcdd7d9dc66f23af92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Thu, 30 Apr 2026 19:46:37 +0200 Subject: [PATCH 3/4] revert unrelated rustfmt reformatting of if/else blocks --- src/generation/generate.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/generation/generate.rs b/src/generation/generate.rs index bac6b895..a67a79e1 100644 --- a/src/generation/generate.rs +++ b/src/generation/generate.rs @@ -115,7 +115,11 @@ fn gen_node_with_inner_gen<'a>(node: Node<'a>, context: &mut Context<'a>, inner_ // keep the leading text, but leave the trailing text to be formatted if on a separate line let node_text = node.text_fast(context.program); let end_trim = node_text.trim_end(); - if node_text[end_trim.len()..].contains('\n') { end_trim } else { node_text } + if node_text[end_trim.len()..].contains('\n') { + end_trim + } else { + node_text + } } else { node.text_fast(context.program) }; @@ -1130,7 +1134,11 @@ fn gen_export_named_decl<'a>(node: &NamedExport<'a>, context: &mut Context<'a>) items.push_sc(sc!(";")); } - if should_single_line { with_no_new_lines(items) } else { items } + if should_single_line { + with_no_new_lines(items) + } else { + items + } } fn gen_function_decl<'a>(node: &FnDecl<'a>, context: &mut Context<'a>) -> PrintItems { @@ -1341,7 +1349,11 @@ fn gen_import_decl<'a>(node: &ImportDecl<'a>, context: &mut Context<'a>) -> Prin items.push_sc(sc!(";")); } - if should_single_line { with_no_new_lines(items) } else { items } + if should_single_line { + with_no_new_lines(items) + } else { + items + } } fn gen_import_equals_decl<'a>(node: &TsImportEqualsDecl<'a>, context: &mut Context<'a>) -> PrintItems { @@ -7777,7 +7789,11 @@ fn gen_close_paren_with_type<'a>(opts: GenCloseParenWithTypeOptions<'a>, context items.extend(generated_type_node); items.push_info(type_node_end_ln); - if use_new_line_group { new_line_group(items) } else { items } + if use_new_line_group { + new_line_group(items) + } else { + items + } } else { items }; From 0b3c27122d292ac9defa073f6c6af12b404a4cc5 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Mon, 4 May 2026 11:31:18 -0400 Subject: [PATCH 4/4] Various fixes --- deployment/schema.json | 15 +++++ src/configuration/builder.rs | 10 +-- src/configuration/resolve_config.rs | 2 +- src/configuration/types.rs | 4 +- src/generation/generate.rs | 18 ++++-- ...t => FunctionExpression_FlatIife_True.txt} | 62 ++++++++++++++++++- 6 files changed, 96 insertions(+), 15 deletions(-) rename tests/specs/expressions/FunctionExpression/{FunctionExpression_IndentInsideIife_False.txt => FunctionExpression_FlatIife_True.txt} (57%) diff --git a/deployment/schema.json b/deployment/schema.json index 50c4f059..13e5b70d 100644 --- a/deployment/schema.json +++ b/deployment/schema.json @@ -645,6 +645,18 @@ "description": "Ex. `function()`" }] }, + "functionExpression.flatIife": { + "description": "Whether to skip indenting the body of a function expression used in an IIFE.", + "type": "boolean", + "default": false, + "oneOf": [{ + "const": true, + "description": "Does not indent the body of the function in `(function() { ... })();`." + }, { + "const": false, + "description": "Indents the body as normal." + }] + }, "getAccessor.spaceBeforeParentheses": { "description": "Whether to add a space before the parentheses of a get accessor.", "type": "boolean", @@ -973,6 +985,9 @@ "functionExpression.spaceAfterFunctionKeyword": { "$ref": "#/definitions/functionExpression.spaceAfterFunctionKeyword" }, + "functionExpression.flatIife": { + "$ref": "#/definitions/functionExpression.flatIife" + }, "getAccessor.spaceBeforeParentheses": { "$ref": "#/definitions/getAccessor.spaceBeforeParentheses" }, diff --git a/src/configuration/builder.rs b/src/configuration/builder.rs index 42a977e2..bfa35df5 100644 --- a/src/configuration/builder.rs +++ b/src/configuration/builder.rs @@ -348,12 +348,12 @@ impl ConfigurationBuilder { self.insert("functionExpression.spaceAfterFunctionKeyword", value.into()) } - /// Whether to indent the body of a function expression used in an IIFE. + /// Whether to skip indenting the body of a function expression used in an IIFE. /// - /// `true` (default) - Indents the body as normal. - /// `false` - Does not indent the body of the function in `(function() { ... })();`. - pub fn function_expression_indent_inside_iife(&mut self, value: bool) -> &mut Self { - self.insert("functionExpression.indentInsideIife", value.into()) + /// `true` - Does not indent the body of the function in `(function() { ... })();`. + /// `false` (default) - Indents the body as normal. + pub fn function_expression_flat_iife(&mut self, value: bool) -> &mut Self { + self.insert("functionExpression.flatIife", value.into()) } /// Whether to add a space before the parentheses of a get accessor. diff --git a/src/configuration/resolve_config.rs b/src/configuration/resolve_config.rs index 08905cc9..ea393be3 100644 --- a/src/configuration/resolve_config.rs +++ b/src/configuration/resolve_config.rs @@ -289,7 +289,7 @@ pub fn resolve_config(config: ConfigKeyMap, global_config: &GlobalConfiguration) function_declaration_space_before_parentheses: get_value(&mut config, "functionDeclaration.spaceBeforeParentheses", false, &mut diagnostics), function_expression_space_before_parentheses: get_value(&mut config, "functionExpression.spaceBeforeParentheses", false, &mut diagnostics), function_expression_space_after_function_keyword: get_value(&mut config, "functionExpression.spaceAfterFunctionKeyword", false, &mut diagnostics), - function_expression_indent_inside_iife: get_value(&mut config, "functionExpression.indentInsideIife", true, &mut diagnostics), + function_expression_flat_iife: get_value(&mut config, "functionExpression.flatIife", false, &mut diagnostics), get_accessor_space_before_parentheses: get_value(&mut config, "getAccessor.spaceBeforeParentheses", false, &mut diagnostics), if_statement_space_after_if_keyword: get_value(&mut config, "ifStatement.spaceAfterIfKeyword", true, &mut diagnostics), import_declaration_space_surrounding_named_imports: get_value(&mut config, "importDeclaration.spaceSurroundingNamedImports", true, &mut diagnostics), diff --git a/src/configuration/types.rs b/src/configuration/types.rs index dc146765..61b08bf7 100644 --- a/src/configuration/types.rs +++ b/src/configuration/types.rs @@ -604,8 +604,8 @@ pub struct Configuration { pub function_expression_space_before_parentheses: bool, #[serde(rename = "functionExpression.spaceAfterFunctionKeyword")] pub function_expression_space_after_function_keyword: bool, - #[serde(rename = "functionExpression.indentInsideIife")] - pub function_expression_indent_inside_iife: bool, + #[serde(rename = "functionExpression.flatIife")] + pub function_expression_flat_iife: bool, #[serde(rename = "getAccessor.spaceBeforeParentheses")] pub get_accessor_space_before_parentheses: bool, #[serde(rename = "ifStatement.spaceAfterIfKeyword")] diff --git a/src/generation/generate.rs b/src/generation/generate.rs index a67a79e1..47ca3b54 100644 --- a/src/generation/generate.rs +++ b/src/generation/generate.rs @@ -2639,17 +2639,23 @@ fn gen_expr_with_type_args<'a>(node: &TsExprWithTypeArgs<'a>, context: &mut Cont } fn is_iife_fn_expr(node: &FnExpr) -> bool { - let parent = node.parent(); - if parent.kind() == NodeKind::ParenExpr { - if let Some(grandparent) = parent.parent() { - return grandparent.kind() == NodeKind::CallExpr; - } + let mut current: Node = node.into(); + while let Some(parent) = current.parent() { + if parent.is::() { + current = parent; + continue; + } + return match parent { + Node::CallExpr(call) => call.callee.range() == current.range(), + Node::OptCall(call) => call.callee.range() == current.range(), + _ => false, + }; } false } fn gen_fn_expr<'a>(node: &FnExpr<'a>, context: &mut Context<'a>) -> PrintItems { - if !context.config.function_expression_indent_inside_iife && is_iife_fn_expr(node) { + if context.config.function_expression_flat_iife && is_iife_fn_expr(node) { context.skip_iife_body_indent = true; } diff --git a/tests/specs/expressions/FunctionExpression/FunctionExpression_IndentInsideIife_False.txt b/tests/specs/expressions/FunctionExpression/FunctionExpression_FlatIife_True.txt similarity index 57% rename from tests/specs/expressions/FunctionExpression/FunctionExpression_IndentInsideIife_False.txt rename to tests/specs/expressions/FunctionExpression/FunctionExpression_FlatIife_True.txt index ec29668f..38190c72 100644 --- a/tests/specs/expressions/FunctionExpression/FunctionExpression_IndentInsideIife_False.txt +++ b/tests/specs/expressions/FunctionExpression/FunctionExpression_FlatIife_True.txt @@ -1,4 +1,4 @@ -~~ functionExpression.indentInsideIife: false ~~ +~~ functionExpression.flatIife: true ~~ == should not indent body of IIFE == (function() { const a = "foobar"; @@ -92,3 +92,63 @@ return inner(); [expect] (function() {})(); + +== should not indent body of IIFE wrapped in extra parens == +((function() { + const a = "foobar"; + return { a }; +}))(); + +[expect] +(function() { +const a = "foobar"; +return { a }; +})(); + +== should not indent body of optional IIFE == +(function() { + const a = "foobar"; + return { a }; +})?.(); + +[expect] +(function() { +const a = "foobar"; +return { a }; +})?.(); + +== should not indent body of bare-callee IIFE == +void function() { + const a = "foobar"; + return { a }; +}(); + +[expect] +void function() { +const a = "foobar"; +return { a }; +}(); + +== should still indent body of function expression in member call == +(function() { + const a = "foobar"; + return { a }; +}).call(null); + +[expect] +(function() { + const a = "foobar"; + return { a }; +}).call(null); + +== should still indent body of function expression as call argument == +foo((function() { + const a = "foobar"; + return { a }; +})); + +[expect] +foo(function() { + const a = "foobar"; + return { a }; +});