Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions deployment/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,18 @@
"description": "Ex. `function<T>()`"
}]
},
"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",
Expand Down Expand Up @@ -973,6 +985,9 @@
"functionExpression.spaceAfterFunctionKeyword": {
"$ref": "#/definitions/functionExpression.spaceAfterFunctionKeyword"
},
"functionExpression.flatIife": {
"$ref": "#/definitions/functionExpression.flatIife"
},
"getAccessor.spaceBeforeParentheses": {
"$ref": "#/definitions/getAccessor.spaceBeforeParentheses"
},
Expand Down
8 changes: 8 additions & 0 deletions src/configuration/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,14 @@ impl ConfigurationBuilder {
self.insert("functionExpression.spaceAfterFunctionKeyword", value.into())
}

/// Whether to skip indenting the body of a function expression used in an IIFE.
///
/// `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.
///
/// `true` - Ex. `get myProp ()`
Expand Down
3 changes: 2 additions & 1 deletion src/configuration/resolve_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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_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),
Expand Down Expand Up @@ -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::*;
Expand Down
2 changes: 2 additions & 0 deletions src/configuration/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.flatIife")]
pub function_expression_flat_iife: bool,
#[serde(rename = "getAccessor.spaceBeforeParentheses")]
pub get_accessor_space_before_parentheses: bool,
#[serde(rename = "ifStatement.spaceAfterIfKeyword")]
Expand Down
2 changes: 2 additions & 0 deletions src/generation/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<LineNumber>,
before_comments_start_info_stack: Stack<(SourceRange, LineNumber, IsStartOfLine)>,
if_stmt_last_brace_condition_ref: Option<ConditionReference>,
Expand Down Expand Up @@ -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,
Expand Down
25 changes: 24 additions & 1 deletion src/generation/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2638,7 +2638,27 @@ fn gen_expr_with_type_args<'a>(node: &TsExprWithTypeArgs<'a>, context: &mut Cont
items
}

fn is_iife_fn_expr(node: &FnExpr) -> bool {
let mut current: Node = node.into();
while let Some(parent) = current.parent() {
if parent.is::<ParenExpr>() {
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_flat_iife && is_iife_fn_expr(node) {
context.skip_iife_body_indent = true;
}

let items = gen_function_decl_or_expr(
FunctionDeclOrExprNode {
node: node.into(),
Expand Down Expand Up @@ -9475,6 +9495,8 @@ struct GenBlockOptions<'a> {

fn gen_block<'a>(gen_inner: impl FnOnce(Vec<Node<'a>>, &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;
Expand All @@ -9493,7 +9515,8 @@ fn gen_block<'a>(gen_inner: impl FnOnce(Vec<Node<'a>>, &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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
~~ functionExpression.flatIife: true ~~
== 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() {})();

== 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 };
});
Loading